/** * Components Handler * Watches user-components/ for .vue and .json file changes * and broadcasts notifications via the sync server. */ import { watch, mkdirSync, existsSync, type FSWatcher } from 'fs' import { join } from 'path' import { USER_COMPONENTS_DIR } from '../../config' let componentsWatcher: FSWatcher | null = null let debounceTimer: ReturnType | null = null const DEBOUNCE_MS = 400 export function setupComponentsWatcher(workingDir: string, broadcast: (message: string, filter?: (ws: any) => boolean) => void) { const componentsDir = join(workingDir, USER_COMPONENTS_DIR) // Auto-create directory if it doesn't exist if (!existsSync(componentsDir)) { try { mkdirSync(componentsDir, { recursive: true }) } catch (e: any) { console.error(`[Components] Failed to create ${componentsDir}: ${e.message}`) return } } try { componentsWatcher = watch(componentsDir, { recursive: true }, (_, filename) => { if (!filename) return // Only watch .vue and .json files if (!filename.endsWith('.vue') && !filename.endsWith('.json')) return // Debounce if (debounceTimer) clearTimeout(debounceTimer) debounceTimer = setTimeout(() => { // Extract folder name from path (first segment) const folder = filename.split(/[/\\]/)[0] || '' const file = filename.split(/[/\\]/).pop() || filename console.log(`[Components] Change: ${filename}`) broadcast(JSON.stringify({ type: 'component-change', folder, file, timestamp: Date.now() })) }, DEBOUNCE_MS) }) console.log(`[Components] Watching ${componentsDir}`) } catch (e: any) { console.error(`[Components] Watch failed: ${e.message}`) } } export function cleanupComponentsWatcher() { if (componentsWatcher) { componentsWatcher.close() componentsWatcher = null } if (debounceTimer) { clearTimeout(debounceTimer) debounceTimer = null } }