import { spawn } from 'node:child_process'; import path from 'node:path'; import type { Plugin } from 'vite'; const NAV_PROTOTYPE_ID = 'oneos-prototype-nav'; const SYNC_SCRIPT = 'scripts/sync-prototype-nav-registry.mjs'; const DEBOUNCE_MS = 900; function extractPrototypeId(filePath: string, projectRoot: string): string | null { const relative = path.relative(projectRoot, filePath).split(path.sep).join('/'); const match = relative.match(/^src\/prototypes\/([^/]+)\//u); if (!match) return null; const prototypeId = match[1]; if (prototypeId === NAV_PROTOTYPE_ID) return null; if (relative.includes('prototype-registry.json') || relative.includes('nav-menu.json')) return null; return prototypeId; } export function createPrototypeNavRegistryPlugin(projectRoot = process.cwd()): Plugin { let debounceTimer: ReturnType | null = null; let running = false; let queuedPrototypeId: string | null = null; const runSync = (prototypeId: string | null) => { if (!prototypeId) return; queuedPrototypeId = prototypeId; if (debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { if (running) return; running = true; const targetId = queuedPrototypeId; queuedPrototypeId = null; const child = spawn( process.execPath, [ path.join(projectRoot, SYNC_SCRIPT), '--prototype', targetId || '', '--quiet', '--skip-directory-sync', `--project-root=${projectRoot}`, ], { cwd: projectRoot, stdio: 'ignore' }, ); child.on('exit', () => { running = false; if (queuedPrototypeId) runSync(queuedPrototypeId); }); }, DEBOUNCE_MS); }; return { name: 'axhub-prototype-nav-registry', apply: 'serve', configureServer(server) { const handle = (filePath: string) => { const prototypeId = extractPrototypeId(filePath, projectRoot); if (prototypeId) runSync(prototypeId); }; server.watcher.on('change', handle); server.watcher.on('add', handle); }, }; }