@nicmeriano/spool-server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/orchestrator/index.ts","../src/orchestrator/types.ts","../src/orchestrator/routes/events.ts","../src/orchestrator/routes/annotations.ts","../src/orchestrator/routes/changes.ts","../src/orchestrator/pending-changes-processor.ts","../src/orchestrator/agent-options.ts","../src/orchestrator/routes/tasks.ts","../src/orchestrator/agent-runner.ts","../src/orchestrator/system-prompt.ts","../src/orchestrator/routes/variants.ts","../src/orchestrator/variant-generator.ts","../src/orchestrator/routes/chat.ts","../src/orchestrator/chat-handler.ts","../src/bin.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport { cors } from 'hono/cors';\nimport { createAdaptorServer } from '@hono/node-server';\nimport { watch } from 'chokidar';\nimport * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createRequire } from 'node:module';\n\n// ESM shim for __dirname\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\nconst require = createRequire(import.meta.url);\n\nimport type { SpoolState, StateUpdateMessage } from './types.js';\nimport { createEmptyState } from './types.js';\nimport { createEventsRoutes, broadcast, getClientCount } from './routes/events.js';\nimport { createAnnotationsRoutes } from './routes/annotations.js';\nimport { createChangesRoutes } from './routes/changes.js';\nimport { createTasksRoutes } from './routes/tasks.js';\nimport { createVariantsRoutes } from './routes/variants.js';\nimport { createChatRoutes } from './routes/chat.js';\n\nconst DEFAULT_PORT = 3142;\nconst STATE_FILE = '.spool/state.json';\n\n/**\n * Generate a stable appId from the project directory path.\n * This ensures each project gets its own isolated state in localStorage.\n */\nfunction generateAppId(dir: string): string {\n const hash = crypto.createHash('sha256').update(dir).digest('hex').slice(0, 8);\n return `spool_${hash}`;\n}\n\n/**\n * Options for starting the server\n */\nexport interface ServerOptions {\n /** Port to listen on (default: 3142) */\n port?: number;\n /** Working directory for state file and agent (default: process.cwd()) */\n cwd?: string;\n}\n\n// ========================================\n// Project Directory (--project-dir flag)\n// ========================================\n\nfunction parseProjectDir(): string {\n const args = process.argv;\n const idx = args.indexOf('--project-dir');\n if (idx !== -1 && idx + 1 < args.length) {\n const dir = path.resolve(args[idx + 1]);\n if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {\n console.error(`[annotate-server] --project-dir \"${args[idx + 1]}\" is not a valid directory`);\n process.exit(1);\n }\n return dir;\n }\n return process.cwd();\n}\n\nlet projectDir = parseProjectDir();\n\n// ========================================\n// State Management\n// ========================================\n\nlet currentState: SpoolState = createEmptyState(generateAppId(projectDir));\nlet stateFilePath: string;\n\nfunction getStateFilePath(): string {\n if (!stateFilePath) {\n stateFilePath = path.resolve(projectDir, STATE_FILE);\n }\n return stateFilePath;\n}\n\nfunction ensureStateDir(): void {\n const dir = path.dirname(getStateFilePath());\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nfunction loadState(): SpoolState {\n const filePath = getStateFilePath();\n\n if (fs.existsSync(filePath)) {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const state = JSON.parse(content) as SpoolState;\n console.error(`[spool] Loaded state from ${filePath}`);\n return state;\n } catch (error) {\n console.error(`[spool] Error loading state:`, error);\n }\n }\n\n console.error(`[spool] No state file found, starting fresh`);\n return createEmptyState(generateAppId(projectDir));\n}\n\nfunction saveState(state: SpoolState): void {\n ensureStateDir();\n const filePath = getStateFilePath();\n\n try {\n fs.writeFileSync(filePath, JSON.stringify(state, null, 2), 'utf-8');\n console.error(`[spool] Saved state to ${filePath}`);\n } catch (error) {\n console.error(`[spool] Error saving state:`, error);\n }\n}\n\n// ========================================\n// Abort Controller State\n// ========================================\n\nlet currentTaskAbortController: AbortController | null = null;\nlet currentChatAbortController: AbortController | null = null;\nlet currentChatMessageId: string | null = null;\n\n// ========================================\n// File Watcher\n// ========================================\n\nlet fileWatcher: ReturnType<typeof watch> | null = null;\n\nfunction startFileWatcher(): void {\n const filePath = getStateFilePath();\n ensureStateDir();\n\n fileWatcher = watch(filePath, {\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 100,\n pollInterval: 50,\n },\n });\n\n fileWatcher.on('change', () => {\n console.error(`[spool] State file changed, reloading...`);\n const newState = loadState();\n\n if (JSON.stringify(newState) !== JSON.stringify(currentState)) {\n currentState = newState;\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: currentState.currentTaskId,\n state: currentState,\n };\n broadcast(update);\n }\n });\n\n fileWatcher.on('add', () => {\n console.error(`[spool] State file created`);\n currentState = loadState();\n\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: currentState.currentTaskId,\n state: currentState,\n };\n broadcast(update);\n });\n\n fileWatcher.on('error', (error) => {\n console.error(`[spool] File watcher error:`, error);\n });\n\n console.error(`[spool] Watching ${filePath} for changes`);\n}\n\nfunction stopFileWatcher(): void {\n if (fileWatcher) {\n fileWatcher.close();\n fileWatcher = null;\n }\n}\n\n// ========================================\n// Static File Serving Helpers\n// ========================================\n\nfunction findInjectScript(): string | null {\n try {\n const injectPkg = require.resolve('@nicmeriano/spool-inject/package.json');\n const injectDir = path.dirname(injectPkg);\n const injectPath = path.join(injectDir, 'dist', 'inject.js');\n if (fs.existsSync(injectPath)) {\n return injectPath;\n }\n } catch {\n // Not resolvable via require, try fallback paths\n }\n\n const possiblePaths = [\n path.resolve(__dirname, '../../inject/dist/inject.js'),\n path.resolve(__dirname, '../../../inject/dist/inject.js'),\n ];\n\n for (const scriptPath of possiblePaths) {\n if (fs.existsSync(scriptPath)) {\n return scriptPath;\n }\n }\n\n return null;\n}\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html',\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n};\n\nfunction findShellDist(): string | null {\n try {\n const shellPkg = require.resolve('@nicmeriano/spool-shell/package.json');\n const shellDir = path.dirname(shellPkg);\n const distDir = path.join(shellDir, 'dist');\n if (fs.existsSync(distDir)) {\n return distDir;\n }\n } catch {\n // Not resolvable via require, try fallback paths\n }\n\n const possiblePaths = [\n path.resolve(__dirname, '../../shell/dist'),\n path.resolve(process.cwd(), 'packages/shell/dist'),\n path.resolve(process.cwd(), '../shell/dist'),\n ];\n\n for (const distPath of possiblePaths) {\n if (fs.existsSync(distPath)) {\n return distPath;\n }\n }\n\n return null;\n}\n\n// ========================================\n// Main Entry Point\n// ========================================\n\nexport async function startServer(options: ServerOptions = {}): Promise<void> {\n const port = options.port ?? parseInt(process.env.PORT || String(DEFAULT_PORT), 10);\n\n if (options.cwd) {\n projectDir = path.resolve(options.cwd);\n stateFilePath = '';\n }\n\n console.error(`[spool] Project directory: ${projectDir}`);\n\n // Load initial state\n currentState = loadState();\n\n // Clear persisted appUrl — the Vite plugin will report the fresh URL on startup.\n // Without this, the initial state:update sends the old URL from the previous run,\n // causing the iframe to point to the wrong port.\n if (currentState.appUrl) {\n currentState.appUrl = undefined;\n }\n\n // Crash recovery\n if (currentState.status === 'generating') {\n console.error(`[spool] Recovering from interrupted task, resetting state`);\n currentState.status = 'idle';\n currentState.currentTaskId = null;\n for (const page of Object.values(currentState.pages)) {\n for (const ann of page.annotations) {\n if (ann.status === 'in_progress') {\n ann.status = 'open';\n }\n }\n }\n saveState(currentState);\n }\n\n // Shared context for route handlers\n const routeCtx = {\n getState: () => currentState,\n setState: (s: SpoolState) => {\n currentState = s;\n },\n saveState,\n loadState,\n projectDir,\n getTaskAbortController: () => currentTaskAbortController,\n setTaskAbortController: (ac: AbortController | null) => {\n currentTaskAbortController = ac;\n },\n getChatAbortController: () => currentChatAbortController,\n setChatAbortController: (ac: AbortController | null) => {\n currentChatAbortController = ac;\n },\n getChatMessageId: () => currentChatMessageId,\n setChatMessageId: (id: string | null) => {\n currentChatMessageId = id;\n },\n };\n\n // Create Hono app\n const app = new Hono();\n\n // CORS — restrict to localhost origins\n app.use('/*', cors({\n origin: (origin) => {\n if (!origin) return '*'; // Allow non-browser requests (curl, Vite plugin, etc.)\n try {\n const hostname = new URL(origin).hostname;\n return hostname === 'localhost' || hostname === '127.0.0.1' ? origin : null;\n } catch {\n return null;\n }\n },\n }));\n\n // Mount API routes\n app.route('/api', createEventsRoutes(routeCtx));\n app.route('/api/annotations', createAnnotationsRoutes(routeCtx));\n app.route('/api/changes', createChangesRoutes(routeCtx));\n app.route('/api/tasks', createTasksRoutes(routeCtx));\n app.route('/api/variants', createVariantsRoutes(routeCtx));\n app.route('/api/chat', createChatRoutes(routeCtx));\n\n // Health check\n app.get('/health', (c) => {\n const openCount = Object.values(currentState.pages)\n .flatMap((p) => p.annotations)\n .filter((a) => a.status === 'open').length;\n\n return c.json({\n status: 'ok',\n open_annotations: openCount,\n connected_clients: getClientCount(),\n });\n });\n\n // Inject script\n app.get('/inject.js', (c) => {\n const injectPath = findInjectScript();\n\n if (!injectPath) {\n console.error(`[spool] inject.js not found. Run 'pnpm build' in packages/inject.`);\n return c.text('inject.js not found - please build the inject package', 404);\n }\n\n try {\n const content = fs.readFileSync(injectPath, 'utf-8');\n return c.text(content, 200, {\n 'Content-Type': 'application/javascript',\n 'Cache-Control': 'no-cache',\n });\n } catch (error) {\n console.error(`[spool] Error reading inject.js:`, error);\n return c.text('Error reading inject.js', 500);\n }\n });\n\n // Static file serving for shell UI (SPA fallback)\n app.get('/*', (c) => {\n const shellDist = findShellDist();\n if (!shellDist) {\n return c.text('Not Found', 404);\n }\n\n const urlPath = new URL(c.req.url).pathname;\n const filePath = path.join(shellDist, urlPath);\n\n // Try exact file first\n if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {\n const ext = path.extname(filePath);\n const contentType = MIME_TYPES[ext] || 'application/octet-stream';\n try {\n const content = fs.readFileSync(filePath);\n return new Response(content, {\n status: 200,\n headers: { 'Content-Type': contentType },\n });\n } catch {\n // Fall through to SPA fallback\n }\n }\n\n // SPA fallback\n const indexPath = path.join(shellDist, 'index.html');\n if (fs.existsSync(indexPath)) {\n try {\n const content = fs.readFileSync(indexPath, 'utf-8');\n return c.html(content);\n } catch {\n // Fall through to 404\n }\n }\n\n return c.text('Not Found', 404);\n });\n\n // Start file watcher\n startFileWatcher();\n\n // Create server and try ports sequentially (like Vite)\n const server = createAdaptorServer(app);\n const MAX_PORT_ATTEMPTS = 20;\n\n await new Promise<void>((resolve, reject) => {\n let currentPort = port;\n let attempts = 0;\n\n const tryListen = () => {\n server.once('error', onError);\n server.listen(currentPort, () => {\n server.removeListener('error', onError);\n const actualPort = currentPort;\n\n console.error(`[spool] HTTP + SSE server listening on http://localhost:${actualPort}`);\n if (actualPort !== port) {\n console.error(`[spool] Port ${port} was in use, using ${actualPort} instead`);\n }\n console.error(`[spool] SSE endpoint at http://localhost:${actualPort}/api/events`);\n console.error(`[spool] Health check at http://localhost:${actualPort}/health`);\n console.error(`[spool] Inject script at http://localhost:${actualPort}/inject.js`);\n console.error(`[spool] State file: ${getStateFilePath()}`);\n\n // Write actual port to .spool/port so the Vite plugin can discover it\n try {\n ensureStateDir();\n const portFilePath = path.resolve(projectDir, '.spool/port');\n fs.writeFileSync(portFilePath, String(actualPort), 'utf-8');\n console.error(`[spool] Wrote port ${actualPort} to ${portFilePath}`);\n } catch (e) {\n console.error(`[spool] Failed to write port file:`, e);\n }\n\n resolve();\n });\n };\n\n function onError(err: NodeJS.ErrnoException) {\n if (err.code === 'EADDRINUSE') {\n attempts++;\n if (attempts >= MAX_PORT_ATTEMPTS) {\n console.error(`[spool] Could not find an available port after ${MAX_PORT_ATTEMPTS} attempts`);\n stopFileWatcher();\n reject(err);\n return;\n }\n currentPort++;\n console.error(`[spool] Port ${currentPort - 1} is in use, trying ${currentPort}...`);\n tryListen();\n } else {\n reject(err);\n }\n }\n\n tryListen();\n });\n\n // Handle shutdown\n const shutdown = () => {\n console.error(`[spool] Shutting down...`);\n stopFileWatcher();\n // Remove port file\n try {\n const portFilePath = path.resolve(projectDir, '.spool/port');\n if (fs.existsSync(portFilePath)) fs.unlinkSync(portFilePath);\n } catch { /* ignore */ }\n server.close();\n process.exit(0);\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n}\n","/**\n * Author - simple for MVP, extensible for future collaboration\n */\nexport interface Author {\n id: string;\n name: string;\n avatar?: string;\n}\n\n/**\n * Attachment for comments (images only for MVP)\n */\nexport interface Attachment {\n id: string;\n filename: string;\n mimeType: 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp';\n /** Size in bytes */\n size: number;\n /** Base64 data URL */\n dataUrl: string;\n createdAt: string;\n}\n\n/**\n * Comment within an annotation thread\n */\nexport interface Comment {\n id: string;\n content: string;\n author: Author;\n createdAt: string;\n /** Image attachments (optional) */\n attachments?: Attachment[];\n}\n\n/**\n * Annotation status\n * - open (blue bubble): Annotation created, Claude should address when submitted\n * - in_progress (spinner): Claude is actively working on it\n * - done (green bubble): Claude has implemented the change\n */\nexport type AnnotationStatus = 'open' | 'in_progress' | 'done';\n\n/**\n * Element information captured during annotation\n */\nexport interface ElementInfo {\n /** CSS selector that uniquely identifies the element */\n selector: string;\n /** HTML tag name (e.g., \"button\", \"div\") */\n tagName: string;\n /** CSS class names */\n className: string;\n /** Element ID if present */\n id?: string;\n /** Text content (truncated) */\n textContent?: string;\n /** React component name if available */\n componentName?: string;\n /** Source file path of the React component */\n componentFile?: string;\n /** Line number in the source file */\n lineNumber?: number;\n /** React component props (if available) */\n props?: Record<string, unknown>;\n}\n\n/**\n * Core annotation with thread support\n */\nexport interface Annotation {\n id: string;\n /** Primary CSS selector to find element (for backward compatibility) */\n selector: string;\n /** Additional CSS selectors for multi-element annotations */\n selectors?: string[];\n /** Viewport-relative anchor point */\n position: { x: number; y: number };\n /** 3-state workflow status */\n status: AnnotationStatus;\n createdAt: string;\n createdBy: Author;\n /** When Claude completed it */\n doneAt?: string;\n /** Claude marks this when done */\n doneBy?: Author;\n /** Git commit SHA for this annotation's changes (enables per-annotation revert) */\n commitSha?: string;\n /** Thread of comments */\n comments: Comment[];\n /** Primary element metadata (for backward compatibility) */\n element: ElementInfo;\n /** Additional element metadata for multi-element annotations */\n elements?: ElementInfo[];\n /** True for page-level comments (not tied to any element) */\n isPageLevel?: boolean;\n /** Exact click position for bubble placement (viewport + scroll offset) */\n clickPosition?: { x: number; y: number };\n}\n\n/**\n * Default author for Claude\n */\nexport const CLAUDE_AUTHOR: Author = {\n id: 'claude',\n name: 'Claude',\n};\n\nexport const CLAUDE_MODEL = 'claude-opus-4-5-20251101';\n\n// ========================================\n// Pending Changes (UI Editing Mode)\n// ========================================\n\n/**\n * Pending change status\n */\nexport type PendingChangeStatus = 'pending' | 'in_progress' | 'done' | 'error';\n\n/**\n * Base interface for all pending changes\n */\nexport interface PendingChangeBase {\n id: string;\n selector: string;\n element: ElementInfo;\n status: PendingChangeStatus;\n createdAt: string;\n errorMessage?: string;\n}\n\n/**\n * Variant data\n */\nexport interface Variant {\n html: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * A pending variant change\n */\nexport interface VariantChange extends PendingChangeBase {\n type: 'variant';\n prompt: string;\n variants: Variant[];\n selectedVariantIndex: number;\n originalHtml: string;\n}\n\n/**\n * A pending style change\n */\nexport interface StyleChange extends PendingChangeBase {\n type: 'style';\n styles: Record<string, string>;\n originalStyles: Record<string, string>;\n}\n\n/**\n * A pending note change\n */\nexport interface NoteChange extends PendingChangeBase {\n type: 'note';\n content: string;\n}\n\n/**\n * Union type for all pending changes\n */\nexport type PendingChange = VariantChange | StyleChange | NoteChange;\n\n// ========================================\n// State.json Structure\n// ========================================\n\n/**\n * Page-specific annotation data\n */\nexport interface PageState {\n url: string;\n annotations: Annotation[];\n pendingChanges?: PendingChange[];\n lastModified: string;\n}\n\n/**\n * Chat message data for server-side persistence\n */\nexport interface ChatMessageData {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n elementRefs?: ChatElementReference[];\n timestamp: string;\n}\n\n/**\n * Root state stored in .spool/state.json\n */\nexport interface SpoolState {\n appId: string;\n status: 'idle' | 'generating';\n currentTaskId: string | null;\n pages: Record<string, PageState>;\n /** Chat messages persisted across hot reloads */\n chatMessages?: ChatMessageData[];\n /** App URL reported by the Vite plugin (dynamic port resolution) */\n appUrl?: string;\n}\n\n// ========================================\n// Message Types\n// ========================================\n\n/**\n * Task payload for addressing annotations\n */\nexport interface TaskPayload {\n action: 'address';\n /** Optional: specific annotation IDs, or address all ready if omitted */\n annotationIds?: string[];\n /** Optional: additional user feedback/context */\n feedback?: string;\n}\n\n/**\n * Task result on completion\n */\nexport interface TaskResult {\n success: boolean;\n annotationsAddressed: number;\n message?: string;\n}\n\n/**\n * Error details\n */\nexport interface TaskError {\n code: string;\n message: string;\n}\n\n// ----------------------------------------\n// Client → Server Messages\n// ----------------------------------------\n\nexport interface TaskSubmitMessage {\n type: 'task:submit';\n id: string;\n payload: TaskPayload;\n}\n\nexport interface TaskCancelMessage {\n type: 'task:cancel';\n taskId: string;\n}\n\nexport interface AnnotationCreateMessage {\n type: 'annotation:create';\n url: string;\n annotation: Annotation;\n}\n\nexport interface AnnotationUpdateMessage {\n type: 'annotation:update';\n id: string;\n changes: Partial<Annotation>;\n}\n\nexport interface AnnotationDeleteMessage {\n type: 'annotation:delete';\n id: string;\n}\n\nexport interface AnnotationRevertMessage {\n type: 'annotation:revert';\n id: string;\n}\n\nexport interface ChangeAddMessage {\n type: 'change:add';\n url: string;\n change: PendingChange;\n}\n\nexport interface ChangeRemoveMessage {\n type: 'change:remove';\n id: string;\n}\n\nexport interface ChangeApplyAllMessage {\n type: 'change:apply_all';\n url: string;\n}\n\nexport interface ChangeApplyMessage {\n type: 'change:apply';\n url: string;\n changeId: string;\n}\n\nexport interface ChangeApplyDirectMessage {\n type: 'change:apply_direct';\n change: PendingChange;\n}\n\nexport interface VariantGenerateMessage {\n type: 'variant:generate';\n id: string;\n payload: {\n selector: string;\n prompt: string;\n elementHtml: string;\n elementInfo: {\n tagName: string;\n componentName?: string;\n componentFile?: string;\n };\n };\n}\n\n// ----------------------------------------\n// Chat Messages\n// ----------------------------------------\n\n/**\n * Element reference included in a chat message\n */\nexport interface ChatElementReference {\n id: string;\n selector: string;\n element: ElementInfo;\n}\n\n/**\n * A message in the chat conversation\n */\nexport interface ChatMessageData {\n id: string;\n role: 'user' | 'assistant';\n content: string;\n elementRefs?: ChatElementReference[];\n timestamp: string;\n}\n\nexport interface ChatSendMessage {\n type: 'chat:send';\n id: string;\n content: string;\n elementRefs: ChatElementReference[];\n history: ChatMessageData[];\n}\n\nexport interface ChatCancelMessage {\n type: 'chat:cancel';\n messageId: string;\n}\n\nexport interface ChatHistoryUpdateMessage {\n type: 'chat:history:update';\n messages: ChatMessageData[];\n}\n\nexport type ClientMessage =\n | TaskSubmitMessage\n | TaskCancelMessage\n | AnnotationCreateMessage\n | AnnotationUpdateMessage\n | AnnotationDeleteMessage\n | AnnotationRevertMessage\n | ChangeAddMessage\n | ChangeRemoveMessage\n | ChangeApplyAllMessage\n | ChangeApplyMessage\n | ChangeApplyDirectMessage\n | VariantGenerateMessage\n | ChatSendMessage\n | ChatCancelMessage\n | ChatHistoryUpdateMessage;\n\n// ----------------------------------------\n// Server → Client Messages\n// ----------------------------------------\n\nexport interface TaskAckMessage {\n type: 'task:ack';\n taskId: string;\n status: 'started';\n}\n\nexport interface StreamTextMessage {\n type: 'stream:text';\n taskId: string;\n content: string;\n isPartial: boolean;\n}\n\nexport interface StreamToolCallMessage {\n type: 'stream:tool_call';\n taskId: string;\n toolName: string;\n toolInput: Record<string, unknown>;\n}\n\nexport interface StateUpdateMessage {\n type: 'state:update';\n taskId: string | null;\n state: SpoolState;\n}\n\nexport interface TaskCompleteMessage {\n type: 'task:complete';\n taskId: string;\n result: TaskResult;\n}\n\nexport interface TaskErrorMessage {\n type: 'task:error';\n taskId: string;\n error: TaskError;\n}\n\nexport interface RevertResultMessage {\n type: 'revert:result';\n annotationId: string;\n success: boolean;\n error?: string;\n}\n\nexport interface AppUrlMessage {\n type: 'app:url';\n url: string;\n}\n\nexport interface ApplyProgressMessage {\n type: 'apply:progress';\n changeId: string;\n status: 'in_progress' | 'done' | 'error';\n error?: string;\n}\n\nexport interface ApplyCompleteMessage {\n type: 'apply:complete';\n success: boolean;\n message?: string;\n}\n\nexport interface VariantResultMessage {\n type: 'variant:result';\n requestId: string;\n variants: Variant[];\n error?: string;\n}\n\n// ----------------------------------------\n// Chat Server Messages\n// ----------------------------------------\n\nexport interface ChatAckMessage {\n type: 'chat:ack';\n messageId: string;\n}\n\nexport interface ChatStreamMessage {\n type: 'chat:stream';\n messageId: string;\n content: string;\n isPartial: boolean;\n}\n\nexport interface ChatToolCallMessage {\n type: 'chat:tool_call';\n messageId: string;\n toolName: string;\n toolInput: Record<string, unknown>;\n}\n\nexport interface ChatCompleteMessage {\n type: 'chat:complete';\n messageId: string;\n success: boolean;\n error?: string;\n}\n\nexport type ServerMessage =\n | TaskAckMessage\n | StreamTextMessage\n | StreamToolCallMessage\n | StateUpdateMessage\n | TaskCompleteMessage\n | TaskErrorMessage\n | RevertResultMessage\n | ApplyProgressMessage\n | ApplyCompleteMessage\n | VariantResultMessage\n | ChatAckMessage\n | ChatStreamMessage\n | ChatToolCallMessage\n | ChatCompleteMessage\n | AppUrlMessage;\n\n// ========================================\n// Utility Functions\n// ========================================\n\n/**\n * Create an empty state structure\n */\nexport function createEmptyState(appId: string): SpoolState {\n return {\n appId,\n status: 'idle',\n currentTaskId: null,\n pages: {},\n };\n}\n\n/**\n * Get all annotations from state, optionally filtered by status\n */\nexport function getAnnotationsFromState(\n state: SpoolState,\n filter?: { status?: AnnotationStatus }\n): Annotation[] {\n const allAnnotations: Annotation[] = [];\n\n for (const page of Object.values(state.pages)) {\n allAnnotations.push(...page.annotations);\n }\n\n if (filter?.status) {\n return allAnnotations.filter((a) => a.status === filter.status);\n }\n\n return allAnnotations;\n}\n\n/**\n * Find an annotation by ID in state\n */\nexport function findAnnotationInState(\n state: SpoolState,\n annotationId: string\n): { annotation: Annotation; pageUrl: string } | null {\n for (const [url, page] of Object.entries(state.pages)) {\n const annotation = page.annotations.find((a) => a.id === annotationId);\n if (annotation) {\n return { annotation, pageUrl: url };\n }\n }\n return null;\n}\n\n/**\n * Update an annotation in state (returns new state, immutable)\n */\nexport function updateAnnotationInState(\n state: SpoolState,\n annotationId: string,\n updates: Partial<Annotation>\n): SpoolState {\n const newPages: Record<string, PageState> = {};\n\n for (const [url, page] of Object.entries(state.pages)) {\n const annotationIndex = page.annotations.findIndex((a) => a.id === annotationId);\n\n if (annotationIndex !== -1) {\n // Found the annotation, update it\n const newAnnotations = [...page.annotations];\n newAnnotations[annotationIndex] = {\n ...newAnnotations[annotationIndex],\n ...updates,\n };\n newPages[url] = {\n ...page,\n annotations: newAnnotations,\n lastModified: new Date().toISOString(),\n };\n } else {\n newPages[url] = page;\n }\n }\n\n return {\n ...state,\n pages: newPages,\n };\n}\n","/**\n * SSE Events Route\n *\n * Manages Server-Sent Events connections for real-time push from server to clients.\n * Also handles POST /api/app-url for dynamic port resolution from the Vite plugin.\n */\n\nimport { Hono } from 'hono';\nimport { streamSSE } from 'hono/streaming';\nimport { execFile } from 'node:child_process';\nimport { platform } from 'node:os';\nimport type { ServerMessage, SpoolState, StateUpdateMessage } from '../types.js';\n\nexport interface SSEClient {\n id: string;\n send: (event: string, data: string) => void;\n close: () => void;\n}\n\nconst sseClients = new Map<string, SSEClient>();\n\nlet clientIdCounter = 0;\n\n/**\n * Broadcast a ServerMessage to all connected SSE clients.\n */\nexport function broadcast(message: ServerMessage): void {\n const data = JSON.stringify(message);\n for (const client of sseClients.values()) {\n client.send(message.type, data);\n }\n}\n\n/**\n * Get the number of connected SSE clients.\n */\nexport function getClientCount(): number {\n return sseClients.size;\n}\n\ninterface EventsContext {\n getState: () => SpoolState;\n setState: (state: SpoolState) => void;\n saveState: (state: SpoolState) => void;\n}\n\n/**\n * Create events routes.\n * Accepts a context with state accessors so the initial state:update can be sent on connect\n * and app URL can be persisted.\n */\nexport function createEventsRoutes(ctx: EventsContext): Hono {\n const app = new Hono();\n\n // SSE endpoint\n app.get('/events', (c) => {\n return streamSSE(c, async (stream) => {\n const clientId = `sse_${++clientIdCounter}`;\n\n const client: SSEClient = {\n id: clientId,\n send: (event, data) => {\n stream.writeSSE({ event, data }).catch(() => {\n // Client disconnected\n sseClients.delete(clientId);\n });\n },\n close: () => {\n sseClients.delete(clientId);\n },\n };\n\n sseClients.set(clientId, client);\n console.error(`[spool] SSE client connected: ${clientId} (total: ${sseClients.size})`);\n\n // Send initial state\n const state = ctx.getState();\n const initMsg: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n await stream.writeSSE({ event: 'state:update', data: JSON.stringify(initMsg) });\n\n // Keepalive ping every 30s\n const keepalive = setInterval(() => {\n stream.writeSSE({ event: 'ping', data: '' }).catch(() => {\n clearInterval(keepalive);\n sseClients.delete(clientId);\n });\n }, 30000);\n\n // Wait until the stream is closed\n stream.onAbort(() => {\n clearInterval(keepalive);\n sseClients.delete(clientId);\n console.error(`[spool] SSE client disconnected: ${clientId} (total: ${sseClients.size})`);\n });\n\n // Keep the stream alive indefinitely\n // The stream will be closed when the client disconnects\n await new Promise(() => {\n // Never resolves — stream stays open until client disconnects\n });\n });\n });\n\n // Dynamic app URL from Vite plugin\n app.post('/app-url', async (c) => {\n const body = await c.req.json<{ url: string }>();\n console.error(`[spool] Received app URL: ${body.url}`);\n\n // Open the shell in the browser (app URL is delivered via SSE, no query params needed)\n const host = c.req.header('host') || 'localhost:3142';\n const shellUrl = `http://${host}`;\n console.error(`[spool] Opening ${shellUrl}`);\n const cmd = platform() === 'darwin' ? 'open' : platform() === 'win32' ? 'start' : 'xdg-open';\n execFile(cmd, [shellUrl]);\n\n // Persist in state so new SSE clients get it via initial state:update\n let state = ctx.getState();\n state = { ...state, appUrl: body.url };\n ctx.setState(state);\n ctx.saveState(state);\n\n // Broadcast to already-connected clients\n broadcast({ type: 'app:url', url: body.url });\n const stateUpdate: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(stateUpdate);\n\n return c.json({ ok: true });\n });\n\n return app;\n}\n","/**\n * Annotations Route\n *\n * HTTP endpoints for annotation CRUD and revert operations.\n */\n\nimport { Hono } from 'hono';\nimport { execFileSync } from 'node:child_process';\nimport type { Annotation, SpoolState, StateUpdateMessage } from '../types.js';\nimport { findAnnotationInState, updateAnnotationInState } from '../types.js';\nimport { broadcast } from './events.js';\n\ninterface AnnotationsContext {\n getState: () => SpoolState;\n setState: (state: SpoolState) => void;\n saveState: (state: SpoolState) => void;\n projectDir: string;\n}\n\nexport function createAnnotationsRoutes(ctx: AnnotationsContext): Hono {\n const app = new Hono();\n\n // POST /api/annotations - Create annotation\n app.post('/', async (c) => {\n const { url, annotation } = await c.req.json<{ url: string; annotation: Annotation }>();\n console.error(`[spool] annotation:create received for ${url}`);\n\n const state = ctx.getState();\n\n if (!state.pages[url]) {\n state.pages[url] = {\n url,\n annotations: [],\n lastModified: new Date().toISOString(),\n };\n }\n\n state.pages[url].annotations.push(annotation);\n state.pages[url].lastModified = new Date().toISOString();\n\n ctx.saveState(state);\n ctx.setState(state);\n\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(update);\n\n return c.json({ ok: true });\n });\n\n // PATCH /api/annotations/:id - Update annotation\n app.patch('/:id', async (c) => {\n const id = c.req.param('id');\n const changes = await c.req.json<Partial<Annotation>>();\n console.error(`[spool] annotation:update received for ${id}`);\n\n const state = ctx.getState();\n let found = false;\n\n for (const page of Object.values(state.pages)) {\n const index = page.annotations.findIndex((a) => a.id === id);\n if (index !== -1) {\n const current = page.annotations[index];\n if (current.status === 'in_progress' && changes.status) {\n const { status: _status, doneAt: _doneAt, doneBy: _doneBy, ...safeChanges } = changes;\n page.annotations[index] = { ...current, ...safeChanges };\n } else {\n page.annotations[index] = { ...current, ...changes };\n }\n page.lastModified = new Date().toISOString();\n found = true;\n break;\n }\n }\n\n if (!found) {\n return c.json({ error: 'Annotation not found' }, 404);\n }\n\n ctx.saveState(state);\n ctx.setState(state);\n\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(update);\n\n return c.json({ ok: true });\n });\n\n // DELETE /api/annotations/:id - Delete annotation\n app.delete('/:id', async (c) => {\n const id = c.req.param('id');\n console.error(`[spool] annotation:delete received for ${id}`);\n\n const state = ctx.getState();\n let deleted = false;\n\n for (const page of Object.values(state.pages)) {\n const index = page.annotations.findIndex((a) => a.id === id);\n if (index !== -1) {\n page.annotations.splice(index, 1);\n page.lastModified = new Date().toISOString();\n deleted = true;\n break;\n }\n }\n\n if (!deleted) {\n return c.json({ error: 'Annotation not found' }, 404);\n }\n\n ctx.saveState(state);\n ctx.setState(state);\n\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(update);\n\n return c.json({ ok: true });\n });\n\n // POST /api/annotations/:id/revert - Revert annotation\n app.post('/:id/revert', async (c) => {\n const id = c.req.param('id');\n console.error(`[spool] annotation:revert for ${id}`);\n\n let state = ctx.getState();\n const found = findAnnotationInState(state, id);\n\n if (!found || found.annotation.status !== 'done' || !found.annotation.commitSha) {\n return c.json({ success: false, error: 'No revertible commit found' });\n }\n\n try {\n execFileSync('git', ['revert', '--no-edit', found.annotation.commitSha], {\n cwd: ctx.projectDir,\n encoding: 'utf-8',\n });\n\n state = updateAnnotationInState(state, id, {\n status: 'open',\n doneAt: undefined,\n doneBy: undefined,\n commitSha: undefined,\n });\n ctx.saveState(state);\n ctx.setState(state);\n broadcast({ type: 'state:update', taskId: null, state });\n console.error(`[spool] Successfully reverted ${id}`);\n\n return c.json({ success: true });\n } catch (error) {\n try {\n execFileSync('git', ['revert', '--abort'], { cwd: ctx.projectDir });\n } catch {\n /* ignore */\n }\n console.error(`[spool] Revert failed for ${id}:`, error);\n return c.json({\n success: false,\n error: 'Revert failed — code has likely changed since this annotation was implemented',\n });\n }\n });\n\n return app;\n}\n","/**\n * Changes Route\n *\n * HTTP endpoints for pending change mutations and apply operations.\n */\n\nimport { Hono } from 'hono';\nimport type {\n SpoolState,\n PendingChange,\n StateUpdateMessage,\n StreamTextMessage,\n StreamToolCallMessage,\n ApplyProgressMessage,\n ApplyCompleteMessage,\n} from '../types.js';\nimport { processChanges } from '../pending-changes-processor.js';\nimport { broadcast } from './events.js';\n\ninterface ChangesContext {\n getState: () => SpoolState;\n setState: (state: SpoolState) => void;\n saveState: (state: SpoolState) => void;\n projectDir: string;\n}\n\nexport function createChangesRoutes(ctx: ChangesContext): Hono {\n const app = new Hono();\n\n // POST /api/changes - Add a pending change\n app.post('/', async (c) => {\n const { url, change } = await c.req.json<{ url: string; change: PendingChange }>();\n console.error(`[spool] change:add for ${url}`);\n\n const state = ctx.getState();\n\n if (!state.pages[url]) {\n state.pages[url] = {\n url,\n annotations: [],\n pendingChanges: [],\n lastModified: new Date().toISOString(),\n };\n }\n\n if (!state.pages[url].pendingChanges) {\n state.pages[url].pendingChanges = [];\n }\n\n state.pages[url].pendingChanges!.push(change);\n state.pages[url].lastModified = new Date().toISOString();\n\n ctx.saveState(state);\n ctx.setState(state);\n\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(update);\n\n return c.json({ ok: true });\n });\n\n // DELETE /api/changes/:id - Remove a pending change\n app.delete('/:id', async (c) => {\n const changeId = c.req.param('id');\n console.error(`[spool] change:remove for ${changeId}`);\n\n const state = ctx.getState();\n let removed = false;\n\n for (const page of Object.values(state.pages)) {\n if (page.pendingChanges) {\n const index = page.pendingChanges.findIndex((ch) => ch.id === changeId);\n if (index !== -1) {\n page.pendingChanges.splice(index, 1);\n page.lastModified = new Date().toISOString();\n removed = true;\n break;\n }\n }\n }\n\n if (!removed) {\n return c.json({ error: 'Change not found' }, 404);\n }\n\n ctx.saveState(state);\n ctx.setState(state);\n\n const update: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(update);\n\n return c.json({ ok: true });\n });\n\n // POST /api/changes/apply-all - Apply all pending changes\n app.post('/apply-all', async (c) => {\n const { url } = await c.req.json<{ url: string }>();\n console.error(`[spool] change:apply_all for ${url}`);\n\n const state = ctx.getState();\n const page = state.pages[url];\n\n if (!page || !page.pendingChanges || page.pendingChanges.length === 0) {\n return c.json({ accepted: true, message: 'No pending changes to apply' });\n }\n\n const pendingChanges = page.pendingChanges.filter((ch) => ch.status === 'pending');\n if (pendingChanges.length === 0) {\n return c.json({ accepted: true, message: 'No pending changes to apply' });\n }\n\n // Return immediately, process async\n const applyAbortController = new AbortController();\n\n // Mark in_progress and process async\n (async () => {\n for (const change of pendingChanges) {\n const idx = page.pendingChanges!.findIndex((ch) => ch.id === change.id);\n if (idx !== -1) {\n page.pendingChanges![idx] = { ...change, status: 'in_progress' };\n }\n }\n ctx.saveState(state);\n\n const result = await processChanges({\n changes: pendingChanges,\n cwd: ctx.projectDir,\n abortController: applyAbortController,\n callbacks: {\n onText: (content, isPartial) => {\n const textMsg: StreamTextMessage = {\n type: 'stream:text',\n taskId: 'apply_all',\n content,\n isPartial,\n };\n broadcast(textMsg);\n },\n onToolCall: (toolName, toolInput) => {\n const toolMsg: StreamToolCallMessage = {\n type: 'stream:tool_call',\n taskId: 'apply_all',\n toolName,\n toolInput,\n };\n broadcast(toolMsg);\n },\n onChangeProgress: (changeId, status, error) => {\n const idx = page.pendingChanges!.findIndex((ch) => ch.id === changeId);\n if (idx !== -1) {\n page.pendingChanges![idx] = {\n ...page.pendingChanges![idx],\n status,\n errorMessage: error,\n };\n }\n ctx.saveState(state);\n\n const progressMsg: ApplyProgressMessage = {\n type: 'apply:progress',\n changeId,\n status,\n error,\n };\n broadcast(progressMsg);\n\n const stateUpdate: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(stateUpdate);\n },\n },\n });\n\n const complete: ApplyCompleteMessage = {\n type: 'apply:complete',\n success: result.success,\n message:\n result.errors.length > 0\n ? `Applied ${result.changesProcessed} changes, errors: ${result.errors.join(', ')}`\n : `Applied ${result.changesProcessed} changes`,\n };\n broadcast(complete);\n\n const finalUpdate: StateUpdateMessage = {\n type: 'state:update',\n taskId: state.currentTaskId,\n state,\n };\n broadcast(finalUpdate);\n })();\n\n return c.json({ accepted: true });\n });\n\n // POST /api/changes/:id/apply - Apply a single change\n app.post('/:id/apply', async (c) => {\n const changeId = c.req.param('id');\n const { url } = await c.req.json<{ url: string }>();\n console.error(`[spool] change:apply for ${changeId} at ${url}`);\n\n const state = ctx.getState();\n const page = state.pages[url];\n\n if (!page || !page.pendingChanges) {\n return c.json({ accepted: false, error: 'Page not found' }, 404);\n }\n\n const change = page.pendingChanges.find((ch) => ch.id === changeId);\n if (!change) {\n return c.json({ accepted: false, error: 'Change not found' }, 404);\n }\n\n if (change.status !== 'pending') {\n return c.json({ accepted: false, error: 'Change is not pending' }, 400);\n }\n\n const singleAbortController = new AbortController();\n\n (async () => {\n const idx = page.pendingChanges!.findIndex((ch) => ch.id === changeId);\n if (idx !== -1) {\n page.pendingChanges![idx] = { ...change, status: 'in_progress' };\n }\n ctx.saveState(state);\n\n const result = await processChanges({\n changes: [change],\n cwd: ctx.projectDir,\n abortController: singleAbortController,\n callbacks: {\n onText: (content, isPartial) => {\n const textMsg: StreamTextMessage = {\n type: 'stream:text',\n taskId: `apply_${changeId}`,\n content,\n isPartial,\n };\n broadcast(textMsg);\n },\n onToolCall: (toolName, toolInput) => {\n const toolMsg: StreamToolCallMessage = {\n type: 'stream:tool_call',\n taskId: `apply_${changeId}`,\n toolName,\n toolInput,\n };\n broadcast(toolMsg);\n },\n onChangeProgress: (id, status, error) => {\n const i = page.pendingChanges!.findIndex((ch) => ch.id === id);\n if (i !== -1) {\n page.pendingChanges![i] = {\n ...page.pendingChanges![i],\n status,\n errorMessage: error,\n };\n }\n ctx.saveState(state);\n\n broadcast({ type: 'apply:progress', changeId: id, status, error });\n broadcast({ type: 'state:update', taskId: state.currentTaskId, state });\n },\n },\n });\n\n broadcast({\n type: 'apply:complete',\n success: result.success,\n message: result.errors.length > 0\n ? `Error: ${result.errors.join(', ')}`\n : 'Change applied successfully',\n });\n broadcast({ type: 'state:update', taskId: state.currentTaskId, state });\n })();\n\n return c.json({ accepted: true });\n });\n\n // POST /api/changes/apply-direct - Apply a change directly (not persisted to queue)\n app.post('/apply-direct', async (c) => {\n const { change } = await c.req.json<{ change: PendingChange }>();\n console.error(`[spool] change:apply_direct for ${change.selector}`);\n\n const directAbortController = new AbortController();\n\n // Send initial progress\n broadcast({ type: 'apply:progress', changeId: change.id, status: 'in_progress' });\n\n (async () => {\n const result = await processChanges({\n changes: [{ ...change, status: 'in_progress' }],\n cwd: ctx.projectDir,\n abortController: directAbortController,\n callbacks: {\n onText: (content, isPartial) => {\n broadcast({\n type: 'stream:text',\n taskId: `apply_direct_${change.id}`,\n content,\n isPartial,\n });\n },\n onToolCall: (toolName, toolInput) => {\n broadcast({\n type: 'stream:tool_call',\n taskId: `apply_direct_${change.id}`,\n toolName,\n toolInput,\n });\n },\n onChangeProgress: (id, status, error) => {\n broadcast({ type: 'apply:progress', changeId: id, status, error });\n },\n },\n });\n\n broadcast({\n type: 'apply:complete',\n success: result.success,\n message: result.errors.length > 0\n ? `Error: ${result.errors.join(', ')}`\n : 'Change applied successfully',\n });\n })();\n\n return c.json({ accepted: true });\n });\n\n return app;\n}\n","/**\n * Pending Changes Processor\n *\n * Processes pending changes (notes, styles, variants) through Claude Agent SDK.\n * Used for both single change and batch \"Apply All\" operations.\n */\n\nimport { query } from '@anthropic-ai/claude-agent-sdk';\nimport { CLAUDE_MODEL, type PendingChange, type StyleChange, type NoteChange, type VariantChange } from './types.js';\nimport { createPathEnforcer } from './agent-options.js';\n\n/**\n * Callbacks for streaming progress to the client.\n */\nexport interface ProcessorCallbacks {\n onText: (content: string, isPartial: boolean) => void;\n onToolCall: (toolName: string, toolInput: Record<string, unknown>) => void;\n onChangeProgress: (changeId: string, status: 'in_progress' | 'done' | 'error', error?: string) => void;\n}\n\n/**\n * Configuration for processing changes.\n */\nexport interface ProcessChangesOptions {\n changes: PendingChange[];\n cwd: string;\n callbacks: ProcessorCallbacks;\n abortController: AbortController;\n}\n\n/**\n * Result of processing changes.\n */\nexport interface ProcessChangesResult {\n success: boolean;\n changesProcessed: number;\n errors: string[];\n}\n\n/**\n * Build a system prompt for processing pending changes.\n */\nfunction buildSystemPrompt(cwd: string): string {\n return `You are implementing UI changes from a pending changes queue. Users use a visual editing tool in their browser to specify changes, and your job is to implement them in the source code.\n\n## Working Directory\n\nYour working directory is: ${cwd}\nYou can ONLY access files within this directory. Do not attempt to access files outside it.\n\n## Tools\n\nYou have the following tools available:\n- **Read**: Read file contents. Parameter: file_path (absolute path)\n- **Edit**: Replace text in a file. Parameters: file_path, old_string, new_string. Read a file before editing it.\n- **Write**: Create or overwrite a file. Parameters: file_path, content\n- **Glob**: Find files by pattern. Parameters: pattern, path (optional directory)\n- **Grep**: Search file contents. Parameters: pattern, path (optional directory)\n\nAlways use absolute paths based on your working directory.\n\n## Change Types\n\nThere are three types of changes you'll handle:\n\n### 1. Note Changes\nUser describes a change in natural language. Read the description and implement it.\nExample: \"Make this button blue\" or \"Add more padding to this card\"\n\n### 2. Style Changes\nUser modified CSS properties using a visual editor. Apply these style changes to the component.\nThe \\`styles\\` object contains the new values, and \\`originalStyles\\` contains what was there before.\nYou should update the component's styling to match the new values.\n\n### 3. Variant Changes\nUser selected an AI-generated HTML variant. Replace the element's current HTML/JSX with the selected variant.\nThe \\`selectedVariantIndex\\` indicates which variant to use from the \\`variants\\` array.\n\n## Workflow\n\nFor each change:\n\n1. Read the \\`element.componentFile\\` to find the source file\n2. Locate the element using \\`selector\\` and \\`element.componentName\\`\n3. Implement the change based on its type\n4. After completing each change, output: \"CHANGE_COMPLETE: <change-id>\"\n\n## Key Fields to Use\n\n- \\`selector\\`: CSS selector identifying the element\n- \\`element.componentName\\`: React component name\n- \\`element.componentFile\\`: Path to the source file\n- For notes: \\`content\\` - the user's description\n- For styles: \\`styles\\` - the CSS properties to apply\n- For variants: \\`variants[selectedVariantIndex].html\\` - the new HTML\n\n## Constraints\n\n- Make minimal, focused changes\n- Follow existing code patterns and conventions\n- Use Tailwind classes if the project uses Tailwind\n- For style changes, prefer inline styles or add to existing className if using CSS modules`;\n}\n\n/**\n * Format a single change for the prompt.\n */\nfunction formatChange(change: PendingChange, index: number): string {\n const component = change.element.componentFile\n ? `${change.element.componentName || 'Unknown'} (${change.element.componentFile})`\n : change.element.selector || 'Unknown element';\n\n let description = '';\n\n switch (change.type) {\n case 'note': {\n const noteChange = change as NoteChange;\n description = `**Note**: \"${noteChange.content}\"`;\n break;\n }\n case 'style': {\n const styleChange = change as StyleChange;\n const styleList = Object.entries(styleChange.styles)\n .map(([key, value]) => `${key}: ${value}`)\n .join(', ');\n description = `**Style changes**: { ${styleList} }`;\n break;\n }\n case 'variant': {\n const variantChange = change as VariantChange;\n const selectedVariant = variantChange.variants[variantChange.selectedVariantIndex];\n description = `**Variant**: Replace with:\\n\\`\\`\\`html\\n${selectedVariant?.html || '(no variant selected)'}\\n\\`\\`\\``;\n break;\n }\n }\n\n return `${index + 1}. **${change.id}** - ${component}\n Type: ${change.type}\n Selector: \\`${change.selector}\\`\n ${description}`;\n}\n\n/**\n * Build the task prompt from pending changes.\n */\nfunction buildTaskPrompt(changes: PendingChange[]): string {\n if (changes.length === 0) {\n return 'There are no pending changes to apply.';\n }\n\n const changesList = changes.map((c, i) => formatChange(c, i)).join('\\n\\n');\n\n return `## Pending Changes to Apply\n\n${changesList}\n\nPlease implement these changes. For each change:\n1. Read the component file\n2. Make the required modifications\n3. Output \"CHANGE_COMPLETE: <change-id>\" when done\n\nStart with the first change and work through them in order.`;\n}\n\n/**\n * Process pending changes through Claude.\n */\nexport async function processChanges(options: ProcessChangesOptions): Promise<ProcessChangesResult> {\n const { changes, cwd, callbacks, abortController } = options;\n\n if (changes.length === 0) {\n return {\n success: true,\n changesProcessed: 0,\n errors: [],\n };\n }\n\n // Mark all changes as in_progress\n for (const change of changes) {\n callbacks.onChangeProgress(change.id, 'in_progress');\n }\n\n const taskPrompt = buildTaskPrompt(changes);\n const systemPrompt = buildSystemPrompt(cwd);\n const errors: string[] = [];\n let changesProcessed = 0;\n\n // Track which changes have been completed\n const changeIds = new Set(changes.map((c) => c.id));\n const completedIds = new Set<string>();\n\n // Buffer to accumulate text for detecting completion markers across chunks\n let textBuffer = '';\n\n try {\n const stream = query({\n prompt: taskPrompt,\n options: {\n systemPrompt,\n cwd,\n abortController,\n tools: { type: 'preset', preset: 'claude_code' },\n allowedTools: ['Read', 'Edit', 'Write', 'Glob', 'Grep'],\n // Enforce project directory boundaries\n canUseTool: createPathEnforcer(cwd),\n permissionMode: 'acceptEdits',\n includePartialMessages: true,\n // Don't load external CLAUDE.md (would leak monorepo context into the isolated agent)\n settingSources: [],\n model: CLAUDE_MODEL,\n },\n });\n\n for await (const message of stream) {\n if (abortController.signal.aborted) {\n break;\n }\n\n switch (message.type) {\n case 'assistant': {\n const assistantMessage = message.message;\n if (assistantMessage.content) {\n for (const block of assistantMessage.content) {\n if (block.type === 'tool_use') {\n callbacks.onToolCall(block.name, block.input as Record<string, unknown>);\n }\n }\n }\n break;\n }\n\n case 'stream_event': {\n const event = message.event;\n if (event.type === 'content_block_delta') {\n const delta = event.delta;\n if ('text' in delta) {\n callbacks.onText(delta.text, true);\n\n // Accumulate text to detect completion markers that may span chunks\n textBuffer += delta.text;\n\n // Check for change completion markers in accumulated text\n // Use global regex to find all matches\n const regex = /CHANGE_COMPLETE:\\s*(\\S+)/g;\n let match;\n while ((match = regex.exec(textBuffer)) !== null) {\n const changeId = match[1];\n if (changeIds.has(changeId) && !completedIds.has(changeId)) {\n completedIds.add(changeId);\n changesProcessed++;\n callbacks.onChangeProgress(changeId, 'done');\n }\n }\n\n // Keep only the last 200 chars to prevent unbounded growth\n // (enough to catch any split marker)\n if (textBuffer.length > 500) {\n textBuffer = textBuffer.slice(-200);\n }\n }\n }\n break;\n }\n\n case 'result': {\n if (message.subtype === 'success') {\n // Claude completed successfully - mark all remaining changes as done\n for (const change of changes) {\n if (!completedIds.has(change.id)) {\n completedIds.add(change.id);\n changesProcessed++;\n callbacks.onChangeProgress(change.id, 'done');\n }\n }\n } else {\n const resultErrors = 'errors' in message ? message.errors : [];\n errors.push(...resultErrors);\n // Mark any incomplete changes as errors\n for (const change of changes) {\n if (!completedIds.has(change.id)) {\n callbacks.onChangeProgress(change.id, 'error', resultErrors.join(', ') || 'Unknown error');\n }\n }\n }\n break;\n }\n }\n }\n\n // Handle aborted case\n if (abortController.signal.aborted) {\n for (const change of changes) {\n if (!completedIds.has(change.id)) {\n callbacks.onChangeProgress(change.id, 'error', 'Task cancelled');\n }\n }\n return {\n success: false,\n changesProcessed,\n errors: ['Task cancelled'],\n };\n }\n\n return {\n success: errors.length === 0,\n changesProcessed,\n errors,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n errors.push(errorMessage);\n\n // Mark all incomplete changes as errors\n for (const change of changes) {\n if (!completedIds.has(change.id)) {\n callbacks.onChangeProgress(change.id, 'error', errorMessage);\n }\n }\n\n return {\n success: false,\n changesProcessed,\n errors,\n };\n }\n}\n","/**\n * Shared agent options for path enforcement.\n *\n * Provides a `canUseTool` callback that restricts file-access tools\n * to the project directory, preventing agents from reading or\n * modifying files outside the user's application.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { CanUseTool } from '@anthropic-ai/claude-agent-sdk';\n\n/** Check whether an absolute path is inside the project boundary. */\nfunction isInsideProject(abs: string, boundary: string): boolean {\n return abs === boundary || abs.startsWith(boundary + path.sep);\n}\n\n/**\n * Create a `canUseTool` callback that denies file access outside the project directory.\n *\n * Guards against:\n * - Explicit paths outside the project (absolute or relative with `..`)\n * - Glob/Grep patterns containing `..` for parent traversal\n * - Glob/Grep called without a `path` (forces path to projectDir)\n * - Symlinks that resolve to targets outside the project\n */\nexport function createPathEnforcer(projectDir: string): CanUseTool {\n const resolved = path.resolve(projectDir);\n\n return async (toolName, input, _options) => {\n // --- 1. Check file_path / path parameter ---\n const filePath = (input.file_path || input.path) as string | undefined;\n if (filePath) {\n const abs = path.resolve(resolved, filePath);\n if (!isInsideProject(abs, resolved)) {\n return { behavior: 'deny' as const, message: `Cannot access files outside project directory: ${filePath}` };\n }\n\n // For file-access tools, also resolve symlinks to catch traversal via node_modules links\n if (['Read', 'Edit', 'Write'].includes(toolName)) {\n try {\n const realPath = fs.realpathSync(abs);\n if (!isInsideProject(realPath, resolved)) {\n return { behavior: 'deny' as const, message: `Cannot access files outside project directory (symlink): ${filePath}` };\n }\n } catch {\n // File may not exist yet (Write creates new files) – allow\n }\n }\n }\n\n // --- 2. For Glob/Grep: deny patterns with \"..\" and force path to projectDir ---\n if (toolName === 'Glob' || toolName === 'Grep') {\n const pattern = input.pattern as string | undefined;\n if (pattern && pattern.includes('..')) {\n return { behavior: 'deny' as const, message: 'Patterns cannot traverse parent directories' };\n }\n // If no explicit path, pin the search to projectDir so it doesn't\n // default to the server's process.cwd() (which is the monorepo root)\n if (!input.path) {\n return { behavior: 'allow' as const, updatedInput: { ...input, path: resolved } };\n }\n }\n\n // --- 3. Bash: block commands referencing parent paths ---\n if (toolName === 'Bash') {\n const command = input.command as string | undefined;\n if (command) {\n const normalized = command.replace(/\\s+/g, ' ');\n if (normalized.includes('..') && !normalized.startsWith('git ')) {\n return { behavior: 'deny' as const, message: `Cannot run commands referencing paths outside project directory` };\n }\n }\n }\n\n return { behavior: 'allow' as const, updatedInput: input };\n };\n}\n","/**\n * Tasks Route\n *\n * HTTP endpoints for task submission and cancellation.\n */\n\nimport { Hono } from 'hono';\nimport { execFileSync } from 'node:child_process';\nimport type {\n SpoolState,\n TaskPayload,\n StateUpdateMessage,\n StreamTextMessage,\n StreamToolCallMessage,\n TaskCompleteMessage,\n TaskErrorMessage,\n} from '../types.js';\nimport { runAgent } from '../agent-runner.js';\nimport { broadcast } from './events.js';\n\ninterface TasksContext {\n getState: () => SpoolState;\n setState: (state: SpoolState) => void;\n saveState: (state: SpoolState) => void;\n loadState: () => SpoolState;\n projectDir: string;\n getTaskAbortController: () => AbortController | null;\n setTaskAbortController: (ac: AbortController | null) => void;\n}\n\nexport function createTasksRoutes(ctx: TasksContext): Hono {\n const app = new Hono();\n\n // POST /api/tasks - Submit a task\n app.post('/', async (c) => {\n const { id: taskId, payload } = await c.req.json<{ id: string; payload: TaskPayload }>();\n console.error(`[spool] task:submit received`);\n console.error(` Task ID: ${taskId}`);\n console.error(` Action: ${payload.action}`);\n console.error(` Annotation IDs: ${payload.annotationIds?.join(', ') || 'all ready'}`);\n\n let state = ctx.getState();\n\n if (state.status === 'generating') {\n return c.json(\n { error: { code: 'ALREADY_GENERATING', message: 'A task is already in progress' } },\n 409\n );\n }\n\n // Update state to generating\n state = { ...state, status: 'generating', currentTaskId: taskId };\n ctx.saveState(state);\n ctx.setState(state);\n\n // Broadcast task:ack\n broadcast({ type: 'task:ack', taskId, status: 'started' });\n\n // Create abort controller\n const abortController = new AbortController();\n ctx.setTaskAbortController(abortController);\n\n // Create temporary branch\n let originalBranch: string | null = null;\n const branchName = `spool/${taskId}`;\n try {\n originalBranch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {\n cwd: ctx.projectDir,\n encoding: 'utf-8',\n }).trim();\n execFileSync('git', ['checkout', '-b', branchName], { cwd: ctx.projectDir, encoding: 'utf-8' });\n console.error(`[spool] Created branch ${branchName} from ${originalBranch}`);\n } catch (e) {\n console.error(`[spool] Could not create branch: ${e}`);\n originalBranch = null;\n }\n\n // Run agent async\n runAgent({\n taskId,\n payload,\n state,\n cwd: ctx.projectDir,\n abortController,\n callbacks: {\n onText: (content, isPartial) => {\n broadcast({ type: 'stream:text', taskId, content, isPartial });\n },\n onToolCall: (toolName, toolInput) => {\n broadcast({ type: 'stream:tool_call', taskId, toolName, toolInput });\n },\n onStateChange: () => {\n const newState = ctx.loadState();\n const currentState = ctx.getState();\n if (JSON.stringify(newState) !== JSON.stringify(currentState)) {\n ctx.setState(newState);\n broadcast({ type: 'state:update', taskId, state: newState });\n }\n },\n },\n })\n .then((result) => {\n console.error(`[spool] Task ${taskId} completed:`, result);\n\n // Merge branch back\n if (originalBranch) {\n try {\n execFileSync('git', ['checkout', originalBranch], { cwd: ctx.projectDir, encoding: 'utf-8' });\n execFileSync(\n 'git', ['merge', '--no-ff', branchName, '-m', `Merge annotation changes (${taskId})`],\n { cwd: ctx.projectDir, encoding: 'utf-8' }\n );\n execFileSync('git', ['branch', '-d', branchName], { cwd: ctx.projectDir, encoding: 'utf-8' });\n console.error(`[spool] Merged ${branchName} into ${originalBranch}`);\n } catch (e) {\n console.error(`[spool] Branch merge/cleanup error: ${e}`);\n }\n }\n\n let s = ctx.getState();\n s = { ...s, status: 'idle', currentTaskId: null };\n ctx.saveState(s);\n ctx.setState(s);\n\n broadcast({ type: 'task:complete', taskId, result });\n\n if (ctx.getTaskAbortController() === abortController) {\n ctx.setTaskAbortController(null);\n }\n })\n .catch((error) => {\n console.error(`[spool] Task ${taskId} error:`, error);\n\n if (originalBranch) {\n try {\n execFileSync('git', ['checkout', originalBranch], { cwd: ctx.projectDir, encoding: 'utf-8' });\n execFileSync('git', ['branch', '-D', branchName], { cwd: ctx.projectDir, encoding: 'utf-8' });\n } catch {\n /* ignore */\n }\n }\n\n let s = ctx.getState();\n s = { ...s, status: 'idle', currentTaskId: null };\n ctx.saveState(s);\n ctx.setState(s);\n\n broadcast({\n type: 'task:error',\n taskId,\n error: {\n code: 'EXECUTION_ERROR',\n message: error instanceof Error ? error.message : String(error),\n },\n });\n\n if (ctx.getTaskAbortController() === abortController) {\n ctx.setTaskAbortController(null);\n }\n });\n\n return c.json({ taskId, status: 'started' });\n });\n\n // POST /api/tasks/:id/cancel - Cancel a task\n app.post('/:id/cancel', async (c) => {\n const taskId = c.req.param('id');\n console.error(`[spool] task:cancel received for ${taskId}`);\n\n const state = ctx.getState();\n if (state.currentTaskId !== taskId) {\n return c.json({ error: 'Task is not current' }, 404);\n }\n\n const ac = ctx.getTaskAbortController();\n if (ac) {\n ac.abort();\n ctx.setTaskAbortController(null);\n }\n\n const newState = { ...state, status: 'idle' as const, currentTaskId: null };\n ctx.saveState(newState);\n ctx.setState(newState);\n\n return c.json({ ok: true });\n });\n\n return app;\n}\n","/**\n * Agent Runner\n *\n * Runs the Claude Agent SDK to implement UI annotations.\n * Streams progress back to the WebSocket server for broadcast to clients.\n */\n\nimport { query } from '@anthropic-ai/claude-agent-sdk';\nimport {\n CLAUDE_MODEL,\n type SpoolState,\n type Annotation,\n type TaskPayload,\n type TaskResult,\n type StreamTextMessage,\n type StreamToolCallMessage,\n} from './types.js';\nimport {\n buildAgentSystemPrompt,\n buildTaskPrompt,\n type AnnotationSummary,\n} from './system-prompt.js';\nimport { createPathEnforcer } from './agent-options.js';\n\n/**\n * Callbacks for streaming agent progress to the client.\n */\nexport interface AgentCallbacks {\n onText: (content: string, isPartial: boolean) => void;\n onToolCall: (toolName: string, toolInput: Record<string, unknown>) => void;\n onStateChange: () => void;\n}\n\n/**\n * Configuration for running the agent.\n */\nexport interface RunAgentOptions {\n taskId: string;\n payload: TaskPayload;\n state: SpoolState;\n cwd: string;\n callbacks: AgentCallbacks;\n abortController: AbortController;\n}\n\n/**\n * Get open annotations from state, optionally filtered by IDs.\n */\nfunction getOpenAnnotations(\n state: SpoolState,\n annotationIds?: string[]\n): Annotation[] {\n const open: Annotation[] = [];\n\n for (const page of Object.values(state.pages)) {\n for (const annotation of page.annotations) {\n if (annotation.status !== 'open') continue;\n\n // If specific IDs provided, filter to those\n if (annotationIds && annotationIds.length > 0) {\n if (annotationIds.includes(annotation.id)) {\n open.push(annotation);\n }\n } else {\n open.push(annotation);\n }\n }\n }\n\n return open;\n}\n\n/**\n * Convert annotations to summaries for the prompt.\n */\nfunction toSummaries(annotations: Annotation[]): AnnotationSummary[] {\n return annotations.map((a) => ({\n id: a.id,\n selector: a.selector,\n selectors: a.selectors,\n comments: a.comments.map((c) => ({ content: c.content })),\n element: a.element\n ? {\n selector: a.element.selector,\n componentName: a.element.componentName,\n componentFile: a.element.componentFile,\n }\n : undefined,\n elements: a.elements?.map((el) => ({\n selector: el.selector,\n componentName: el.componentName,\n componentFile: el.componentFile,\n })),\n }));\n}\n\n/**\n * Run the agent to implement ready annotations.\n */\nexport async function runAgent(options: RunAgentOptions): Promise<TaskResult> {\n const { taskId, payload, state, cwd, callbacks, abortController } = options;\n\n // Get open annotations\n const openAnnotations = getOpenAnnotations(state, payload.annotationIds);\n\n if (openAnnotations.length === 0) {\n return {\n success: true,\n annotationsAddressed: 0,\n message: 'No open annotations to address',\n };\n }\n\n // Build the task prompt\n const summaries = toSummaries(openAnnotations);\n const taskPrompt = buildTaskPrompt(summaries);\n const fullPrompt = payload.feedback\n ? `${taskPrompt}\\n\\n## Additional Context from User\\n\\n${payload.feedback}`\n : taskPrompt;\n\n // Track how many annotations we addressed\n let annotationsAddressed = 0;\n // Track whether we've emitted text to insert separators between turns\n let hasEmittedText = false;\n\n try {\n // Run the agent\n const stream = query({\n prompt: fullPrompt,\n options: {\n systemPrompt: buildAgentSystemPrompt(cwd),\n cwd,\n abortController,\n // Use Claude Code's tools for file operations\n tools: { type: 'preset', preset: 'claude_code' },\n // Enable Skills and git commands for per-annotation commits\n allowedTools: ['Skill', 'Bash(git add*)', 'Bash(git commit*)', 'Bash(git rev-parse*)'],\n // Block web access tools\n disallowedTools: ['WebFetch', 'WebSearch'],\n // Enforce project directory boundaries\n canUseTool: createPathEnforcer(cwd),\n // Auto-accept edits since user initiated this\n permissionMode: 'acceptEdits',\n // Include partial messages for streaming\n includePartialMessages: true,\n // Don't load external CLAUDE.md (would leak monorepo context into the isolated agent)\n settingSources: [],\n model: CLAUDE_MODEL,\n },\n });\n\n // Process stream events\n for await (const message of stream) {\n // Check for abort\n if (abortController.signal.aborted) {\n break;\n }\n\n switch (message.type) {\n case 'assistant': {\n // Process tool_use blocks from assistant messages\n // (text is already streamed via stream_event deltas, so skip text blocks here to avoid duplication)\n const assistantMessage = message.message;\n if (assistantMessage.content) {\n for (const block of assistantMessage.content) {\n if (block.type === 'tool_use') {\n callbacks.onToolCall(block.name, block.input as Record<string, unknown>);\n\n // Check if this is an Edit to state.json marking done\n if (\n block.name === 'Edit' &&\n typeof block.input === 'object' &&\n block.input !== null\n ) {\n const input = block.input as { file_path?: string; new_string?: string };\n if (\n input.file_path?.includes('state.json') &&\n input.new_string?.includes('\"status\": \"done\"')\n ) {\n annotationsAddressed++;\n // Notify that state changed so orchestrator can reload & broadcast\n callbacks.onStateChange();\n } else if (\n input.file_path?.includes('state.json') &&\n input.new_string?.includes('\"status\": \"in_progress\"')\n ) {\n // State changed to in_progress\n callbacks.onStateChange();\n }\n }\n }\n }\n }\n break;\n }\n\n case 'stream_event': {\n // Partial streaming event\n const event = message.event;\n\n // When a new text content block starts after we already emitted text,\n // insert a separator so markdown blocks from different turns don't merge\n if (event.type === 'content_block_start') {\n const contentBlock = (event as { content_block?: { type: string } }).content_block;\n if (contentBlock?.type === 'text' && hasEmittedText) {\n callbacks.onText('\\n\\n', true);\n }\n }\n\n if (event.type === 'content_block_delta') {\n const delta = event.delta;\n if ('text' in delta) {\n callbacks.onText(delta.text, true);\n hasEmittedText = true;\n }\n }\n break;\n }\n\n case 'result': {\n // Final result\n if (message.subtype === 'success') {\n return {\n success: true,\n annotationsAddressed,\n message: message.result,\n };\n } else {\n // Error result\n const errors = 'errors' in message ? message.errors : [];\n return {\n success: false,\n annotationsAddressed,\n message: errors.join(', ') || 'Agent execution failed',\n };\n }\n }\n }\n }\n\n // Stream ended without result (possibly aborted)\n return {\n success: abortController.signal.aborted ? false : true,\n annotationsAddressed,\n message: abortController.signal.aborted ? 'Task cancelled' : 'Completed',\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n annotationsAddressed,\n message: `Agent error: ${errorMessage}`,\n };\n }\n}\n","/**\n * System prompt for Claude when addressing UI annotations.\n *\n * This defines Claude's role as an assistant that implements UI feedback\n * based on annotations stored in .spool/state.json.\n */\n\nconst ANNOTATION_INSTRUCTIONS = `You are implementing UI feedback from annotations. Users mark up UI elements in their browser and describe changes they want. Your job is to implement those changes.\n\n## Your Role\n\nRead annotations from .spool/state.json and implement the requested changes to the codebase.\n\n## Workflow\n\nFor each annotation you implement:\n\n1. **Mark as in_progress**: Before starting work, update the annotation's status to \"in_progress\" in .spool/state.json. This shows a spinner in the user's browser.\n\n2. **Understand the request**: Read the annotation's:\n - \\`element.componentFile\\` - The React component file to modify\n - \\`element.componentName\\` - The component name\n - \\`element.selector\\` - CSS selector identifying the element\n - \\`comments[].content\\` - User's description of the desired change\n - \\`selectors[]\\` - (optional) Additional CSS selectors for multi-element annotations\n - \\`elements[]\\` - (optional) Additional element metadata for multi-element annotations\n\n **Multi-element annotations**: When \\`selectors\\` and \\`elements\\` arrays are present, the user selected multiple elements together. Apply the requested change to ALL elements (the primary \\`selector\\`/\\`element\\` AND each item in \\`selectors\\`/\\`elements\\`).\n\n3. **Implement the change**: Make the minimal code changes needed. Follow existing patterns in the codebase.\n\n4. **Mark as done**: After successfully implementing, update the annotation's status to \"done\" in .spool/state.json. Set:\n - \\`status: \"done\"\\`\n - \\`doneAt: \"<current ISO timestamp>\"\\`\n - \\`doneBy: { id: \"claude\", name: \"Claude\" }\\`\n\n## Updating state.json\n\nThe state file is at \\`.spool/state.json\\`. Use the Edit tool to update annotation statuses. The structure is:\n\n\\`\\`\\`json\n{\n \"pages\": {\n \"<url>\": {\n \"annotations\": [\n {\n \"id\": \"ann_xxx\",\n \"status\": \"open\", // Change to \"in_progress\" then \"done\"\n \"doneAt\": null, // Set to ISO timestamp when done\n \"doneBy\": null, // Set to { \"id\": \"claude\", \"name\": \"Claude\" }\n ...\n }\n ]\n }\n }\n}\n\\`\\`\\`\n\nTo mark as in_progress, edit:\n\\`\\`\\`\n\"status\": \"open\"\n\\`\\`\\`\nto:\n\\`\\`\\`\n\"status\": \"in_progress\"\n\\`\\`\\`\n\nTo mark as done, edit:\n\\`\\`\\`\n\"status\": \"in_progress\",\n \"doneAt\": null,\n \"doneBy\": null\n\\`\\`\\`\nto:\n\\`\\`\\`\n\"status\": \"done\",\n \"doneAt\": \"<timestamp>\",\n \"doneBy\": { \"id\": \"claude\", \"name\": \"Claude\" },\n \"commitSha\": \"<sha from git rev-parse HEAD>\"\n\\`\\`\\`\n\n## Git Commits\n\nAfter implementing each annotation's code changes (before marking as done):\n\n1. Stage only the files you modified for this annotation:\n \\`git add <file1> <file2> ...\\`\n Do NOT use \\`git add -A\\` or \\`git add .\\` — only add files you explicitly changed for this annotation.\n\n2. Commit with the annotation ID in the message:\n \\`git commit -m \"[spool] <annotation-id>: <brief description of change>\"\\`\n\n3. Get the commit SHA:\n Run \\`git rev-parse HEAD\\` and note the output.\n\n4. When marking done in state.json, include the commitSha field:\n \\`\"status\": \"done\"\\`,\n \\`\"doneAt\": \"<timestamp>\"\\`,\n \\`\"doneBy\": { \"id\": \"claude\", \"name\": \"Claude\" }\\`,\n \\`\"commitSha\": \"<sha from step 3>\"\\`\n\n## Answering Questions\n\nIf an annotation's comment is a question (asking for information, clarification, or guidance rather than requesting a code change), add a reply comment to the annotation's comments array with your answer. The reply should have \\`author: { \"id\": \"claude\", \"name\": \"Claude\" }\\`. Then mark the annotation as done.\n\n## Constraints\n\n- Always update state.json status fields before and after implementing\n- Make minimal, focused changes - don't refactor unrelated code\n- Follow existing code patterns and conventions\n- If an annotation is unclear, implement your best interpretation\n- Process annotations one at a time, completing each before starting the next`;\n\n/**\n * Build the full system prompt for the annotation agent, including tool\n * usage instructions and the working-directory boundary.\n */\nexport function buildAgentSystemPrompt(cwd: string): string {\n return `${ANNOTATION_INSTRUCTIONS}\n\n## Working Directory\n\nYour working directory is: ${cwd}\nYou can ONLY access files within this directory. Do not attempt to access files outside it.\n\n## Tools\n\nYou have the following tools available:\n- **Read**: Read file contents. Parameter: file_path (absolute path)\n- **Edit**: Replace text in a file. Parameters: file_path, old_string, new_string. Read a file before editing it.\n- **Write**: Create or overwrite a file. Parameters: file_path, content\n- **Glob**: Find files by pattern. Parameters: pattern, path (optional directory)\n- **Grep**: Search file contents. Parameters: pattern, path (optional directory)\n- **Bash**: Run shell commands. Only git commands are allowed (git add, git commit, git rev-parse).\n\nAlways use absolute paths based on your working directory.`;\n}\n\n/**\n * Build a task prompt from open annotations.\n * This is appended to the system prompt to give Claude the specific task.\n */\nexport function buildTaskPrompt(annotations: AnnotationSummary[]): string {\n if (annotations.length === 0) {\n return 'There are no open annotations to address.';\n }\n\n const annotationList = annotations\n .map((a, i) => {\n const comment = a.comments[0]?.content || '(no comment)';\n const component = a.element?.componentFile\n ? `${a.element.componentName || 'Unknown'} (${a.element.componentFile})`\n : a.element?.selector || 'Unknown element';\n\n let entry = `${i + 1}. **${a.id}** - ${component}\n Request: \"${comment}\"`;\n\n // Include additional elements for multi-element annotations\n if (a.elements && a.elements.length > 0) {\n const additionalList = a.elements.map((el) => {\n if (el.componentFile) {\n return ` - ${el.componentName || 'Unknown'} (${el.componentFile})`;\n }\n return ` - ${el.selector || 'Unknown element'}`;\n }).join('\\n');\n entry += `\\n Additional elements:\\n${additionalList}`;\n } else if (a.selectors && a.selectors.length > 0) {\n entry += `\\n Additional selectors: ${a.selectors.join(', ')}`;\n }\n\n return entry;\n })\n .join('\\n\\n');\n\n return `## Annotations to Address\n\n${annotationList}\n\nPlease implement these changes. For each annotation:\n1. Mark it as in_progress in .spool/state.json\n2. Make the code changes\n3. Mark it as done in .spool/state.json\n\nStart with the first annotation.`;\n}\n\n/**\n * Minimal annotation info needed for the prompt.\n */\nexport interface AnnotationSummary {\n id: string;\n selector: string;\n selectors?: string[];\n comments: { content: string }[];\n element?: {\n selector: string;\n componentName?: string;\n componentFile?: string;\n };\n elements?: {\n selector?: string;\n componentName?: string;\n componentFile?: string;\n }[];\n}\n","/**\n * Variants Route\n *\n * HTTP endpoint for AI variant generation.\n * Returns variants directly in the HTTP response (no SSE needed).\n */\n\nimport { Hono } from 'hono';\nimport { generateVariants } from '../variant-generator.js';\n\ninterface VariantsContext {\n projectDir: string;\n}\n\nexport function createVariantsRoutes(ctx: VariantsContext): Hono {\n const app = new Hono();\n\n // POST /api/variants/generate - Generate element variants\n app.post('/generate', async (c) => {\n const { selector, prompt, elementHtml, elementInfo } = await c.req.json<{\n selector: string;\n prompt: string;\n elementHtml: string;\n elementInfo: {\n tagName: string;\n componentName?: string;\n componentFile?: string;\n };\n }>();\n\n console.error(`[spool] variant:generate for ${selector}`);\n console.error(` Prompt: ${prompt}`);\n\n try {\n const result = await generateVariants(\n {\n selector,\n element: {\n tagName: elementInfo.tagName,\n componentName: elementInfo.componentName,\n componentFile: elementInfo.componentFile,\n },\n prompt,\n currentHtml: elementHtml,\n },\n ctx.projectDir\n );\n\n return c.json({ variants: result.variants, error: result.error });\n } catch (error) {\n console.error('[spool] variant:generate error:', error);\n return c.json({\n variants: [],\n error: error instanceof Error ? error.message : String(error),\n });\n }\n });\n\n return app;\n}\n","/**\n * Variant Generator\n *\n * Generates HTML/JSX alternatives for UI elements using Claude.\n */\n\nimport { query } from '@anthropic-ai/claude-agent-sdk';\nimport { CLAUDE_MODEL, type Variant } from './types.js';\n\n/**\n * Minimal element info for variant generation.\n */\nexport interface VariantElementInfo {\n tagName: string;\n componentName?: string;\n componentFile?: string;\n}\n\n/**\n * Request payload for variant generation.\n */\nexport interface VariantGeneratePayload {\n selector: string;\n element: VariantElementInfo;\n prompt: string;\n currentHtml?: string;\n}\n\n/**\n * Result of variant generation.\n */\nexport interface VariantGenerateResult {\n variants: Variant[];\n error?: string;\n}\n\n/**\n * Build a system prompt for variant generation.\n */\nfunction buildSystemPrompt(): string {\n return `You are a UI design assistant that generates alternative HTML/JSX variants for UI elements.\n\n## Your Task\n\nGiven an element's current state and a user's prompt, generate 3-6 alternative HTML/JSX variants.\n\n## Output Format\n\nYou MUST output EXACTLY the following JSON structure and nothing else:\n\n\\`\\`\\`json\n{\n \"variants\": [\n {\n \"html\": \"<button class=\\\\\"...\\\\\">....</button>\",\n \"description\": \"Brief description of this variant\"\n },\n {\n \"html\": \"<button class=\\\\\"...\\\\\">....</button>\",\n \"description\": \"Brief description of this variant\"\n }\n ]\n}\n\\`\\`\\`\n\n## Guidelines\n\n1. Generate 3-6 meaningful alternatives based on the user's prompt\n2. Each variant should be a complete, self-contained HTML/JSX snippet\n3. Use Tailwind CSS classes for styling (assume the project uses Tailwind)\n4. Include brief descriptions explaining what makes each variant different\n5. Variants should be progressively more creative/different from the original\n6. Ensure all variants are semantically equivalent (same purpose/functionality)\n7. Output ONLY the JSON - no explanations before or after\n\n## Examples\n\nIf user says \"make it more prominent\":\n- Variant 1: Larger font and more padding\n- Variant 2: Bold colors and shadow\n- Variant 3: Animated hover effect\n- Variant 4: Gradient background\n\nIf user says \"make it more subtle\":\n- Variant 1: Lighter colors\n- Variant 2: Reduced padding and smaller text\n- Variant 3: Ghost/outline style\n- Variant 4: Minimal with icon only\n`;\n}\n\n/**\n * Build the task prompt from the payload.\n */\nfunction buildTaskPrompt(payload: VariantGeneratePayload): string {\n const { element, prompt, currentHtml } = payload;\n\n const elementInfo = [\n `Tag: ${element.tagName}`,\n element.componentName && `Component: ${element.componentName}`,\n element.componentFile && `File: ${element.componentFile}`,\n ]\n .filter(Boolean)\n .join('\\n');\n\n return `## Element Information\n\n${elementInfo}\n\n## Current HTML\n${currentHtml || '(not provided - generate based on element info)'}\n\n## User Request\n\"${prompt}\"\n\nGenerate 3-6 HTML/JSX variants based on the user's request. Output ONLY the JSON structure described.`;\n}\n\n/**\n * Parse variants from Claude's response.\n */\nfunction parseVariants(text: string): Variant[] {\n console.error('[variant-generator] Parsing response, length:', text.length);\n console.error('[variant-generator] Response preview:', text.slice(0, 300));\n\n // Try multiple strategies to extract JSON\n\n // Strategy 1: Extract from ```json code block\n const jsonBlockMatch = text.match(/```json\\s*([\\s\\S]*?)\\s*```/);\n if (jsonBlockMatch) {\n console.error('[variant-generator] Found JSON code block');\n try {\n const parsed = JSON.parse(jsonBlockMatch[1]);\n if (Array.isArray(parsed.variants)) {\n return parsed.variants.map((v: { html?: string; description?: string }, i: number) => ({\n html: v.html || '',\n metadata: { description: v.description || `Variant ${i + 1}` },\n }));\n }\n } catch (e) {\n console.error('[variant-generator] Failed to parse JSON block:', e);\n }\n }\n\n // Strategy 2: Find JSON object with \"variants\" key anywhere in text\n const objectMatch = text.match(/\\{[\\s\\S]*?\"variants\"\\s*:\\s*\\[[\\s\\S]*?\\]\\s*\\}/);\n if (objectMatch) {\n console.error('[variant-generator] Found JSON object with variants key');\n try {\n const parsed = JSON.parse(objectMatch[0]);\n if (Array.isArray(parsed.variants)) {\n return parsed.variants.map((v: { html?: string; description?: string }, i: number) => ({\n html: v.html || '',\n metadata: { description: v.description || `Variant ${i + 1}` },\n }));\n }\n } catch (e) {\n console.error('[variant-generator] Failed to parse object match:', e);\n }\n }\n\n // Strategy 3: Try to find just an array of objects with html/description\n const arrayMatch = text.match(/\\[\\s*\\{[\\s\\S]*?\"html\"[\\s\\S]*?\\}\\s*\\]/);\n if (arrayMatch) {\n console.error('[variant-generator] Found array with html objects');\n try {\n const parsed = JSON.parse(arrayMatch[0]);\n if (Array.isArray(parsed)) {\n return parsed.map((v: { html?: string; description?: string }, i: number) => ({\n html: v.html || '',\n metadata: { description: v.description || `Variant ${i + 1}` },\n }));\n }\n } catch (e) {\n console.error('[variant-generator] Failed to parse array:', e);\n }\n }\n\n // Strategy 4: Try parsing the entire text as JSON\n try {\n const parsed = JSON.parse(text.trim());\n if (Array.isArray(parsed.variants)) {\n return parsed.variants.map((v: { html?: string; description?: string }, i: number) => ({\n html: v.html || '',\n metadata: { description: v.description || `Variant ${i + 1}` },\n }));\n }\n if (Array.isArray(parsed)) {\n return parsed.map((v: { html?: string; description?: string }, i: number) => ({\n html: v.html || '',\n metadata: { description: v.description || `Variant ${i + 1}` },\n }));\n }\n } catch (e) {\n // Not valid JSON\n }\n\n console.error('[variant-generator] Could not parse variants from response');\n console.error('[variant-generator] Full response:', text);\n return [];\n}\n\n/**\n * Generate variants for an element using Claude.\n */\nexport async function generateVariants(\n payload: VariantGeneratePayload,\n cwd: string\n): Promise<VariantGenerateResult> {\n const systemPrompt = buildSystemPrompt();\n const taskPrompt = buildTaskPrompt(payload);\n\n let responseText = '';\n\n console.error('[variant-generator] Starting variant generation');\n console.error('[variant-generator] Prompt:', payload.prompt);\n console.error('[variant-generator] Element:', payload.element.tagName, payload.element.componentName);\n\n try {\n const stream = query({\n prompt: taskPrompt,\n options: {\n systemPrompt,\n cwd,\n tools: { type: 'preset', preset: 'claude_code' },\n allowedTools: [], // No tools needed for this task\n permissionMode: 'acceptEdits',\n includePartialMessages: false,\n model: CLAUDE_MODEL,\n maxTurns: 1, // Single turn is enough for variant generation\n },\n });\n\n for await (const message of stream) {\n switch (message.type) {\n case 'stream_event': {\n const event = message.event;\n if (event.type === 'content_block_delta') {\n const delta = event.delta;\n if ('text' in delta) {\n responseText += delta.text;\n // Log progress every 500 chars\n if (responseText.length % 500 < 50) {\n console.error('[variant-generator] Received', responseText.length, 'chars so far');\n }\n }\n }\n break;\n }\n\n case 'assistant': {\n // Also try to get text from assistant messages\n const assistantMessage = message.message;\n if (assistantMessage.content) {\n for (const block of assistantMessage.content) {\n if (block.type === 'text' && block.text) {\n console.error('[variant-generator] Got text from assistant message, length:', block.text.length);\n if (!responseText) {\n responseText = block.text;\n }\n }\n }\n }\n break;\n }\n\n case 'result': {\n if (message.subtype !== 'success') {\n const errors = 'errors' in message ? message.errors : [];\n return {\n variants: [],\n error: errors.join(', ') || 'Failed to generate variants',\n };\n }\n break;\n }\n }\n }\n\n console.error('[variant-generator] Stream complete, total response length:', responseText.length);\n\n // Parse the response\n const variants = parseVariants(responseText);\n\n console.error('[variant-generator] Parsed', variants.length, 'variants');\n\n if (variants.length === 0) {\n return {\n variants: [],\n error: 'Failed to parse variants from response',\n };\n }\n\n return { variants };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error('[variant-generator] Error:', errorMessage);\n\n return {\n variants: [],\n error: errorMessage,\n };\n }\n}\n","/**\n * Chat Route\n *\n * HTTP endpoints for chat operations.\n * Chat streaming is pushed via SSE broadcast; client correlates by messageId.\n */\n\nimport { Hono } from 'hono';\nimport type {\n SpoolState,\n ChatElementReference,\n ChatMessageData,\n StateUpdateMessage,\n ChatStreamMessage,\n ChatToolCallMessage,\n ChatCompleteMessage,\n} from '../types.js';\nimport { handleChat } from '../chat-handler.js';\nimport { broadcast } from './events.js';\n\ninterface ChatContext {\n getState: () => SpoolState;\n setState: (state: SpoolState) => void;\n saveState: (state: SpoolState) => void;\n projectDir: string;\n getChatAbortController: () => AbortController | null;\n setChatAbortController: (ac: AbortController | null) => void;\n getChatMessageId: () => string | null;\n setChatMessageId: (id: string | null) => void;\n}\n\nexport function createChatRoutes(ctx: ChatContext): Hono {\n const app = new Hono();\n\n // POST /api/chat - Send a chat message\n app.post('/', async (c) => {\n const { id: messageId, content, elementRefs, history } = await c.req.json<{\n id: string;\n content: string;\n elementRefs: ChatElementReference[];\n history: ChatMessageData[];\n }>();\n\n console.error(`[spool] chat:send received`);\n console.error(` Message ID: ${messageId}`);\n console.error(` Content: ${content.slice(0, 100)}${content.length > 100 ? '...' : ''}`);\n console.error(` Element refs: ${elementRefs.length}`);\n\n // Abort previous chat if still running\n const prevAc = ctx.getChatAbortController();\n if (prevAc) {\n console.error(`[spool] Chat already in progress, aborting previous`);\n prevAc.abort();\n }\n\n const abortController = new AbortController();\n ctx.setChatAbortController(abortController);\n ctx.setChatMessageId(messageId);\n\n // Process async, streaming via SSE\n handleChat({\n messageId,\n content,\n elementRefs,\n history,\n cwd: ctx.projectDir,\n abortController,\n callbacks: {\n onText: (text, isPartial) => {\n broadcast({ type: 'chat:stream', messageId, content: text, isPartial });\n },\n onToolCall: (toolName, toolInput) => {\n broadcast({ type: 'chat:tool_call', messageId, toolName, toolInput });\n },\n },\n })\n .then((result) => {\n console.error(`[spool] Chat ${messageId} completed:`, result.success);\n\n // Persist chat history\n const timestamp = new Date().toISOString();\n const updatedHistory: ChatMessageData[] = [\n ...history,\n {\n id: messageId + '_user',\n role: 'user',\n content,\n elementRefs,\n timestamp,\n },\n ];\n if (result.responseContent) {\n updatedHistory.push({\n id: messageId,\n role: 'assistant',\n content: result.responseContent,\n timestamp,\n });\n }\n\n let state = ctx.getState();\n state = { ...state, chatMessages: updatedHistory };\n ctx.saveState(state);\n ctx.setState(state);\n\n broadcast({ type: 'state:update', taskId: state.currentTaskId, state });\n broadcast({\n type: 'chat:complete',\n messageId,\n success: result.success,\n error: result.error,\n });\n\n if (ctx.getChatMessageId() === messageId) {\n ctx.setChatAbortController(null);\n ctx.setChatMessageId(null);\n }\n })\n .catch((error) => {\n console.error(`[spool] Chat ${messageId} error:`, error);\n\n broadcast({\n type: 'chat:complete',\n messageId,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n if (ctx.getChatMessageId() === messageId) {\n ctx.setChatAbortController(null);\n ctx.setChatMessageId(null);\n }\n });\n\n return c.json({ messageId });\n });\n\n // POST /api/chat/cancel - Cancel chat\n app.post('/cancel', async (c) => {\n const { messageId } = await c.req.json<{ messageId: string }>();\n console.error(`[spool] chat:cancel for ${messageId}`);\n\n if (ctx.getChatMessageId() !== messageId) {\n return c.json({ error: 'Not current chat' }, 404);\n }\n\n const ac = ctx.getChatAbortController();\n if (ac) {\n ac.abort();\n ctx.setChatAbortController(null);\n ctx.setChatMessageId(null);\n }\n\n return c.json({ ok: true });\n });\n\n // PUT /api/chat/history - Update chat history\n app.put('/history', async (c) => {\n const { messages } = await c.req.json<{ messages: ChatMessageData[] }>();\n console.error(`[spool] chat:history:update (${messages.length} messages)`);\n\n let state = ctx.getState();\n state = { ...state, chatMessages: messages };\n ctx.saveState(state);\n ctx.setState(state);\n\n broadcast({ type: 'state:update', taskId: state.currentTaskId, state });\n\n return c.json({ ok: true });\n });\n\n return app;\n}\n","/**\n * Chat Handler\n *\n * Handles conversational chat with Claude, allowing users to discuss\n * and request changes to UI elements referenced in their messages.\n */\n\nimport { query } from '@anthropic-ai/claude-agent-sdk';\nimport {\n CLAUDE_MODEL,\n type ChatElementReference,\n type ChatMessageData,\n} from './types.js';\nimport { createPathEnforcer } from './agent-options.js';\n\n/**\n * Callbacks for streaming chat responses to the client.\n */\nexport interface ChatCallbacks {\n onText: (content: string, isPartial: boolean) => void;\n onToolCall: (toolName: string, toolInput: Record<string, unknown>) => void;\n}\n\n/**\n * Options for handling a chat message.\n */\nexport interface HandleChatOptions {\n messageId: string;\n content: string;\n elementRefs: ChatElementReference[];\n history: ChatMessageData[];\n cwd: string;\n callbacks: ChatCallbacks;\n abortController: AbortController;\n}\n\n/**\n * Result of handling a chat message.\n */\nexport interface ChatResult {\n success: boolean;\n error?: string;\n /** The accumulated assistant response content */\n responseContent?: string;\n}\n\n/**\n * Build the chat system prompt that enables conversational + code change capabilities.\n */\nfunction buildChatSystemPrompt(cwd: string): string {\n return `You are an AI assistant helping a developer with their React application through a chat interface.\nThe developer can reference specific UI elements in their messages by clicking on them in the browser.\n\n## Working Directory\n\nYour working directory is: ${cwd}\nYou can ONLY access files within this directory. Do not attempt to access files outside it.\n\n## Tools\n\nYou have the following tools available:\n- **Read**: Read file contents. Parameter: file_path (absolute path)\n- **Edit**: Replace text in a file. Parameters: file_path, old_string, new_string\n- **Write**: Create or overwrite a file. Parameters: file_path, content\n- **Glob**: Find files by pattern. Parameters: pattern, path (optional directory)\n- **Grep**: Search file contents. Parameters: pattern, path (optional directory)\n\nAlways use absolute paths based on your working directory. Read a file before editing it.\n\n## Element References\n\nWhen the user references UI elements, you'll see them in the prompt with their details:\n- CSS selector to locate the element\n- Component name and file location (if available)\n- Text content of the element\n\nUse this information to understand what the user is talking about and make targeted changes.\n\n## Capabilities\n\nYou can:\n1. **Answer questions** about the codebase, UI elements, or implementation approaches\n2. **Make code changes** when the user requests modifications to their UI or code\n3. **Explain code** and help the user understand how things work\n4. **Suggest improvements** when asked for recommendations\n\n## Guidelines\n\n- Be conversational and helpful\n- When making changes, explain what you're doing\n- If the user's request is unclear, ask clarifying questions\n- Keep responses focused and relevant to the user's question\n- When referencing files, use the component file paths provided in element references when available\n- Focus exclusively on the user's React application code`;\n}\n\n/**\n * Build the user prompt with element references and conversation history.\n */\nfunction buildChatPrompt(\n content: string,\n elementRefs: ChatElementReference[],\n history: ChatMessageData[]\n): string {\n const parts: string[] = [];\n\n // Add conversation history\n if (history.length > 0) {\n parts.push('## Conversation History\\n');\n for (const msg of history) {\n const role = msg.role === 'user' ? 'User' : 'Assistant';\n parts.push(`**${role}:** ${msg.content}\\n`);\n }\n parts.push('');\n }\n\n // Add element references if present\n if (elementRefs.length > 0) {\n parts.push('## Referenced UI Elements\\n');\n for (const ref of elementRefs) {\n parts.push(`### Element: ${ref.element.componentName || ref.element.tagName}`);\n parts.push(`- **Selector:** \\`${ref.selector}\\``);\n if (ref.element.componentName) {\n parts.push(`- **Component:** ${ref.element.componentName}`);\n }\n if (ref.element.componentFile) {\n parts.push(`- **File:** ${ref.element.componentFile}${ref.element.lineNumber ? `:${ref.element.lineNumber}` : ''}`);\n }\n if (ref.element.textContent) {\n const truncated = ref.element.textContent.length > 100\n ? ref.element.textContent.slice(0, 100) + '...'\n : ref.element.textContent;\n parts.push(`- **Text:** \"${truncated}\"`);\n }\n if (ref.element.className) {\n parts.push(`- **Classes:** ${ref.element.className}`);\n }\n parts.push('');\n }\n }\n\n // Add current message\n parts.push('## Current Message\\n');\n parts.push(content);\n\n return parts.join('\\n');\n}\n\n/**\n * Handle a chat message by running Claude with the Agent SDK.\n */\nexport async function handleChat(options: HandleChatOptions): Promise<ChatResult> {\n const { messageId, content, elementRefs, history, cwd, callbacks, abortController } = options;\n\n // Build the prompt\n const prompt = buildChatPrompt(content, elementRefs, history);\n\n // Accumulate the response content for persistence\n let responseContent = '';\n\n try {\n // Run the agent\n const stream = query({\n prompt,\n options: {\n systemPrompt: buildChatSystemPrompt(cwd),\n cwd,\n abortController,\n // Use Claude Code's tools for file operations\n tools: { type: 'preset', preset: 'claude_code' },\n // Only allow file-access tools — no Bash, WebFetch, or WebSearch\n allowedTools: ['Read', 'Edit', 'Write', 'Glob', 'Grep'],\n // Enforce project directory boundaries\n canUseTool: createPathEnforcer(cwd),\n // Auto-accept edits since user initiated this via chat\n permissionMode: 'acceptEdits',\n // Include partial messages for streaming\n includePartialMessages: true,\n // Don't load external CLAUDE.md (would leak monorepo context into the isolated agent)\n settingSources: [],\n model: CLAUDE_MODEL,\n },\n });\n\n // Process stream events\n for await (const message of stream) {\n // Check for abort\n if (abortController.signal.aborted) {\n break;\n }\n\n switch (message.type) {\n case 'assistant': {\n // Process content blocks from assistant messages\n const assistantMessage = message.message;\n if (assistantMessage.content) {\n for (const block of assistantMessage.content) {\n if (block.type === 'tool_use') {\n callbacks.onToolCall(block.name, block.input as Record<string, unknown>);\n } else if (block.type === 'text') {\n // Capture text content for persistence (in case stream events don't include it)\n // Only add if not already captured via streaming\n if (!responseContent.includes(block.text)) {\n responseContent += block.text;\n }\n }\n }\n }\n break;\n }\n\n case 'stream_event': {\n // Partial streaming event\n const event = message.event;\n\n // When a new text content block starts after we already have text,\n // insert a separator so markdown blocks from different turns don't merge\n if (event.type === 'content_block_start') {\n const contentBlock = (event as { content_block?: { type: string } }).content_block;\n if (contentBlock?.type === 'text' && responseContent.length > 0) {\n if (!responseContent.endsWith('\\n\\n')) {\n const sep = responseContent.endsWith('\\n') ? '\\n' : '\\n\\n';\n responseContent += sep;\n callbacks.onText(sep, true);\n }\n }\n }\n\n if (event.type === 'content_block_delta') {\n const delta = event.delta;\n if ('text' in delta) {\n // Accumulate for persistence\n responseContent += delta.text;\n callbacks.onText(delta.text, true);\n }\n }\n break;\n }\n\n case 'user': {\n // These are input messages, not responses\n break;\n }\n\n case 'result': {\n // Final result\n if (message.subtype === 'success') {\n return {\n success: true,\n responseContent,\n };\n } else {\n // Error result\n const errors = 'errors' in message ? message.errors : [];\n return {\n success: false,\n error: errors.join(', ') || 'Chat request failed',\n responseContent,\n };\n }\n }\n }\n }\n\n // Stream ended without result (possibly aborted)\n return {\n success: !abortController.signal.aborted,\n error: abortController.signal.aborted ? 'Chat cancelled' : undefined,\n responseContent,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: `Chat error: ${errorMessage}`,\n responseContent,\n };\n }\n}\n","#!/usr/bin/env node\nimport { startServer } from './orchestrator/index.js';\n\n// Parse CLI arguments\nconst args = process.argv.slice(2);\nconst projectDirIdx = args.indexOf('--project-dir');\nconst cwd = projectDirIdx !== -1 && projectDirIdx + 1 < args.length\n ? args[projectDirIdx + 1]\n : undefined;\n\nstartServer({ cwd }).catch((error) => {\n console.error(`[spool] Fatal error:`, error);\n process.exit(1);\n});\n"],"mappings":"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","names":["Hono","fs","path","Hono","Hono","Hono","projectDir","cwd","Hono","Hono","execFileSync","query","cwd","buildTaskPrompt","cwd","buildTaskPrompt","query","Hono","execFileSync","currentState","Hono","query","buildSystemPrompt","buildTaskPrompt","cwd","query","Hono","Hono","query","cwd","query","sep","Hono","require","args","Hono","resolve"]}