@neotx/core 0.1.0-alpha.20 → 0.1.0-alpha.22

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/agents/loader.ts","../src/agents/schema.ts","../src/agents/registry.ts","../src/agents/resolver.ts","../src/concurrency/queue.ts","../src/concurrency/semaphore.ts","../src/config.ts","../src/paths.ts","../src/config/schema.ts","../src/config/dotNotation.ts","../src/config/merge.ts","../src/config/ConfigStore.ts","../src/config/ConfigWatcher.ts","../src/cost/journal.ts","../src/shared/date.ts","../src/shared/fs.ts","../src/events/emitter.ts","../src/events/journal.ts","../src/events/webhook.ts","../src/isolation/clone.ts","../src/isolation/git.ts","../src/isolation/sandbox.ts","../src/middleware/audit-log.ts","../src/middleware/budget-guard.ts","../src/middleware/chain.ts","../src/middleware/loop-detection.ts","../src/orchestrator.ts","../src/orchestrator/run-store.ts","../src/shared/process.ts","../src/orchestrator/prompt-builder.ts","../src/runner/output-parser.ts","../src/sdk-types.ts","../src/runner/session.ts","../src/runner/recovery.ts","../src/runner/session-executor.ts","../src/supervisor/memory/embedder.ts","../src/supervisor/memory/entry.ts","../src/supervisor/memory/format.ts","../src/supervisor/memory/store.ts","../src/supervisor/schemas.ts","../src/supervisor/decisions.ts","../src/supervisor/activity-log.ts","../src/supervisor/daemon.ts","../src/supervisor/event-queue.ts","../src/supervisor/heartbeat.ts","../src/supervisor/idle-detector.ts","../src/supervisor/log-buffer.ts","../src/supervisor/prompt-builder.ts","../src/supervisor/webhookEvents.ts","../src/supervisor/webhook-server.ts","../src/supervisor/StatusReader.ts","../src/supervisor/shutdown.ts","../src/webhook-config.ts","../src/index.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { AgentConfig } from \"@/agents/schema\";\nimport { agentConfigSchema } from \"@/agents/schema\";\n\n/**\n * Load a single agent definition from a YAML file.\n * If the `prompt` field points to a .md file, resolve it relative\n * to the YAML file's directory and read its content.\n */\nexport async function loadAgentFile(filePath: string): Promise<AgentConfig> {\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf-8\");\n } catch {\n throw new Error(`Agent file not found: ${filePath}`);\n }\n\n let parsed: unknown;\n try {\n parsed = parseYaml(raw);\n } catch (err) {\n throw new Error(\n `Invalid YAML in agent file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const result = agentConfigSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid agent config in ${filePath}:\\n${issues}`);\n }\n\n const config = result.data;\n\n // If prompt points to a .md file, read it\n if (config.prompt?.endsWith(\".md\")) {\n const promptPath = path.resolve(path.dirname(filePath), config.prompt);\n try {\n config.prompt = await readFile(promptPath, \"utf-8\");\n } catch {\n throw new Error(`Prompt file not found: ${promptPath} (referenced in ${filePath})`);\n }\n }\n\n return config;\n}\n","import { z } from \"zod\";\n\n// ─── Agent model enum ────────────────────────────────────\n\nexport const agentModelSchema = z.enum([\"opus\", \"sonnet\", \"haiku\"]);\n\n// ─── Agent tool enum ─────────────────────────────────────\n\nexport const agentToolSchema = z.enum([\n \"Read\",\n \"Write\",\n \"Edit\",\n \"Bash\",\n \"Glob\",\n \"Grep\",\n \"Agent\",\n \"WebSearch\",\n \"WebFetch\",\n \"NotebookEdit\",\n]);\n\n// ─── Agent tool entry (tool or $inherited token) ─────────\n\nexport const agentToolEntrySchema = z.union([agentToolSchema, z.literal(\"$inherited\")]);\n\n// ─── Agent sandbox enum ──────────────────────────────────\n\nexport const agentSandboxSchema = z.enum([\"writable\", \"readonly\"]);\n\n// ─── AgentConfig schema (from YAML) ─────────────────────\n\nexport const agentConfigSchema = z.object({\n name: z.string(),\n extends: z.string().optional(),\n description: z.string().optional(),\n model: agentModelSchema.optional(),\n tools: z.array(agentToolEntrySchema).optional(),\n prompt: z.string().optional(),\n promptAppend: z.string().optional(),\n sandbox: agentSandboxSchema.optional(),\n maxTurns: z.number().optional(),\n mcpServers: z.array(z.string()).optional(),\n});\n\n// ─── Derived types ───────────────────────────────────────\n\nexport type AgentConfig = z.infer<typeof agentConfigSchema>;\nexport type AgentModel = z.infer<typeof agentModelSchema>;\nexport type AgentTool = z.infer<typeof agentToolSchema>;\nexport type AgentToolEntry = z.infer<typeof agentToolEntrySchema>;\n","import { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { loadAgentFile } from \"@/agents/loader\";\nimport { resolveAgent } from \"@/agents/resolver\";\nimport type { AgentConfig } from \"@/agents/schema\";\nimport type { ResolvedAgent } from \"@/types\";\n\nexport class AgentRegistry {\n private readonly builtInDir: string;\n private readonly customDir: string | undefined;\n private agents = new Map<string, ResolvedAgent>();\n\n constructor(builtInDir: string, customDir?: string) {\n this.builtInDir = builtInDir;\n this.customDir = customDir;\n }\n\n async load(): Promise<void> {\n this.agents.clear();\n\n // Load built-in agents\n const builtInConfigs = await loadAgentsFromDir(this.builtInDir);\n const builtInMap = new Map<string, AgentConfig>();\n for (const config of builtInConfigs) {\n builtInMap.set(config.name, config);\n }\n\n // Resolve built-in agents\n for (const config of builtInConfigs) {\n const resolved = resolveAgent(config, builtInMap);\n // Force built-in source for agents loaded from the built-in dir\n this.agents.set(config.name, { ...resolved, source: \"built-in\" });\n }\n\n // Load custom agents (if directory exists)\n if (this.customDir) {\n let customConfigs: AgentConfig[];\n try {\n customConfigs = await loadAgentsFromDir(this.customDir);\n } catch {\n // Custom dir doesn't exist — that's fine\n customConfigs = [];\n }\n\n for (const config of customConfigs) {\n const resolved = resolveAgent(config, builtInMap);\n this.agents.set(config.name, resolved);\n }\n }\n }\n\n get(name: string): ResolvedAgent | undefined {\n return this.agents.get(name);\n }\n\n list(): ResolvedAgent[] {\n return [...this.agents.values()];\n }\n\n has(name: string): boolean {\n return this.agents.has(name);\n }\n}\n\nasync function loadAgentsFromDir(dir: string): Promise<AgentConfig[]> {\n const entries = await readdir(dir);\n const ymlFiles = entries.filter((f) => f.endsWith(\".yml\") || f.endsWith(\".yaml\"));\n\n const configs: AgentConfig[] = [];\n for (const file of ymlFiles) {\n const config = await loadAgentFile(path.join(dir, file));\n configs.push(config);\n }\n return configs;\n}\n","import type { AgentConfig, AgentTool } from \"@/agents/schema\";\nimport type { AgentDefinition, ResolvedAgent } from \"@/types\";\n\n/**\n * Resolve an agent config into a fully-merged ResolvedAgent.\n *\n * Resolution rules:\n * 1. No `extends` → agent must define all required fields\n * 2. With `extends: \"developer\"` → start from built-in, apply overrides\n * 3. Same name as built-in without `extends:` → treated as `extends: <name>` implicitly\n */\nexport function resolveAgent(\n config: AgentConfig,\n builtIns: Map<string, AgentConfig>,\n): ResolvedAgent {\n const extendsName =\n config.extends ??\n (builtIns.has(config.name) && config.extends === undefined ? config.name : undefined);\n\n if (extendsName !== undefined) {\n return resolveExtendedAgent(config, extendsName, builtIns);\n }\n\n return resolveCustomAgent(config);\n}\n\n// ─── Extended agent (inherits from built-in) ────────────\n\nfunction resolveExtendedAgent(\n config: AgentConfig,\n extendsName: string,\n builtIns: Map<string, AgentConfig>,\n): ResolvedAgent {\n const base = builtIns.get(extendsName);\n\n if (!base) {\n throw new Error(\n `Agent \"${config.name}\" extends \"${extendsName}\", but no built-in agent with that name exists.`,\n );\n }\n\n const tools = mergeTools(config.tools, base.tools);\n const prompt = mergePrompt(config.prompt, config.promptAppend, base.prompt);\n const mcpServers = mergeMcpServerNames(base.mcpServers, config.mcpServers);\n\n const definition: AgentDefinition = {\n description: config.description ?? base.description ?? \"\",\n prompt,\n tools,\n model: config.model ?? base.model ?? \"sonnet\",\n ...(mcpServers.length > 0 ? { mcpServers } : {}),\n };\n\n return {\n name: config.name,\n definition,\n sandbox: config.sandbox ?? base.sandbox ?? \"readonly\",\n ...(config.maxTurns !== undefined\n ? { maxTurns: config.maxTurns }\n : base.maxTurns !== undefined\n ? { maxTurns: base.maxTurns }\n : {}),\n source: config.name === extendsName && !config.extends ? \"built-in\" : \"extended\",\n };\n}\n\n// ─── Custom agent (no inheritance) ──────────────────────\n\nfunction resolveCustomAgent(config: AgentConfig): ResolvedAgent {\n if (!config.description) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"description\". Add a 'description' field to the agent YAML.`,\n );\n }\n if (!config.model) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"model\". Add a 'model' field (e.g., 'claude-sonnet-4-20250514').`,\n );\n }\n if (!config.tools) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"tools\". Add a 'tools' array to the agent YAML.`,\n );\n }\n if (!config.sandbox) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"sandbox\". Add a 'sandbox' field ('full' or 'permissive').`,\n );\n }\n if (!config.prompt) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"prompt\". Add a 'prompt' field or 'promptFile' reference.`,\n );\n }\n\n // Filter out $inherited from tools (shouldn't be there without extends, but be safe)\n const tools = config.tools.filter((t): t is AgentTool => t !== \"$inherited\");\n\n let prompt = config.prompt;\n if (config.promptAppend) {\n prompt = `${prompt}\\n\\n${config.promptAppend}`;\n }\n\n const definition: AgentDefinition = {\n description: config.description,\n prompt,\n tools,\n model: config.model,\n ...(config.mcpServers?.length ? { mcpServers: config.mcpServers } : {}),\n };\n\n return {\n name: config.name,\n definition,\n sandbox: config.sandbox,\n ...(config.maxTurns !== undefined ? { maxTurns: config.maxTurns } : {}),\n source: \"custom\",\n };\n}\n\n// ─── Helpers ────────────────────────────────────────────\n\nfunction mergeTools(configTools: AgentConfig[\"tools\"], baseTools: AgentConfig[\"tools\"]): string[] {\n if (!configTools) return (baseTools ?? []) as string[];\n if (configTools.includes(\"$inherited\")) {\n const newTools = configTools.filter((t) => t !== \"$inherited\");\n return [...(baseTools ?? []), ...newTools] as string[];\n }\n return configTools as string[];\n}\n\nfunction mergePrompt(\n configPrompt: string | undefined,\n promptAppend: string | undefined,\n basePrompt: string | undefined,\n): string {\n let prompt = configPrompt ?? basePrompt ?? \"\";\n if (promptAppend) {\n prompt = `${prompt}\\n\\n${promptAppend}`;\n }\n return prompt;\n}\n\nfunction mergeMcpServerNames(base: string[] | undefined, override: string[] | undefined): string[] {\n if (!base?.length && !override?.length) return [];\n return [...new Set([...(base ?? []), ...(override ?? [])])];\n}\n","import type { Priority } from \"@/types\";\n\nconst PRIORITY_ORDER: Record<Priority, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\ninterface QueueItem<T> {\n value: T;\n priority: Priority;\n insertionOrder: number;\n}\n\n/**\n * FIFO priority queue. Items with higher priority (critical > high > medium > low)\n * are dequeued first. Within the same priority level, FIFO order is maintained.\n */\nexport class PriorityQueue<T> {\n private readonly items: QueueItem<T>[] = [];\n private readonly maxSize: number;\n private insertionCounter = 0;\n\n constructor(maxSize: number) {\n this.maxSize = maxSize;\n }\n\n enqueue(value: T, priority: Priority): void {\n // Reset counter when queue is empty to prevent overflow after prolonged use\n if (this.items.length === 0) {\n this.insertionCounter = 0;\n }\n\n if (this.items.length >= this.maxSize) {\n throw new Error(`Queue full (${this.maxSize} items). Cannot enqueue.`);\n }\n\n const item: QueueItem<T> = {\n value,\n priority,\n insertionOrder: this.insertionCounter++,\n };\n\n // Insert in sorted position (binary search would be overkill for queue sizes ≤ 50)\n let inserted = false;\n for (let i = 0; i < this.items.length; i++) {\n const existing = this.items[i];\n if (existing && this.comparePriority(item, existing) < 0) {\n this.items.splice(i, 0, item);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n this.items.push(item);\n }\n }\n\n dequeue(): T | undefined {\n const item = this.items.shift();\n return item?.value;\n }\n\n peek(): T | undefined {\n return this.items[0]?.value;\n }\n\n get size(): number {\n return this.items.length;\n }\n\n get isEmpty(): boolean {\n return this.items.length === 0;\n }\n\n remove(predicate: (item: T) => boolean): boolean {\n const index = this.items.findIndex((entry) => predicate(entry.value));\n if (index === -1) return false;\n this.items.splice(index, 1);\n return true;\n }\n\n /** Dequeue the first item matching the predicate (respects priority order). */\n dequeueWhere(predicate: (item: T) => boolean): T | undefined {\n const index = this.items.findIndex((entry) => predicate(entry.value));\n if (index === -1) return undefined;\n const removed = this.items.splice(index, 1)[0];\n if (!removed) return undefined;\n return removed.value;\n }\n\n /** Compare by priority first, then by insertion order (FIFO within same priority). */\n private comparePriority(a: QueueItem<T>, b: QueueItem<T>): number {\n const priorityDiff = PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority];\n if (priorityDiff !== 0) return priorityDiff;\n return a.insertionOrder - b.insertionOrder;\n }\n}\n","import { PriorityQueue } from \"@/concurrency/queue\";\nimport type { Priority } from \"@/types\";\n\nexport interface SemaphoreConfig {\n maxSessions: number;\n maxPerRepo: number;\n queueMax?: number;\n}\n\nexport interface SemaphoreCallbacks {\n onEnqueue?: (sessionId: string, repo: string, position: number) => void;\n onDequeue?: (sessionId: string, repo: string, waitedMs: number) => void;\n}\n\ninterface WaitingEntry {\n sessionId: string;\n repo: string;\n resolve: () => void;\n reject: (reason: unknown) => void;\n enqueuedAt: number;\n _cleanupAbort?: () => void;\n}\n\n/**\n * Concurrency semaphore with global + per-repo limits and a priority queue.\n * When at capacity, `acquire()` blocks until a slot is available.\n */\nexport class Semaphore {\n private readonly maxSessions: number;\n private readonly maxPerRepo: number;\n private readonly queue: PriorityQueue<WaitingEntry>;\n private readonly callbacks: SemaphoreCallbacks;\n\n // sessionId → repo\n private readonly activeSessions = new Map<string, string>();\n // repo → count\n private readonly repoCounts = new Map<string, number>();\n\n constructor(config: SemaphoreConfig, callbacks: SemaphoreCallbacks = {}) {\n this.maxSessions = config.maxSessions;\n this.maxPerRepo = config.maxPerRepo;\n this.queue = new PriorityQueue<WaitingEntry>(config.queueMax ?? 50);\n this.callbacks = callbacks;\n }\n\n /**\n * Acquire a slot. Blocks (via promise) if at capacity.\n * Throws if the queue is full.\n */\n async acquire(\n repo: string,\n sessionId: string,\n priority: Priority = \"medium\",\n signal?: AbortSignal,\n ): Promise<void> {\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n\n if (this.canAcquire(repo)) {\n this.allocate(repo, sessionId);\n return;\n }\n\n return new Promise<void>((resolve, reject) => {\n const entry: WaitingEntry = {\n sessionId,\n repo,\n resolve,\n reject,\n enqueuedAt: Date.now(),\n };\n\n this.queue.enqueue(entry, priority);\n this.callbacks.onEnqueue?.(sessionId, repo, this.queue.size);\n\n if (signal) {\n const onAbort = () => {\n this.queue.remove((e) => e === entry);\n reject(signal.reason ?? new DOMException(\"The operation was aborted.\", \"AbortError\"));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n\n // Store cleanup so we can remove the listener on normal dequeue\n entry._cleanupAbort = () => signal.removeEventListener(\"abort\", onAbort);\n }\n });\n }\n\n /** Release a slot and process the next waiting entry. */\n release(sessionId: string): void {\n const repo = this.activeSessions.get(sessionId);\n if (!repo) return;\n\n this.activeSessions.delete(sessionId);\n const count = this.repoCounts.get(repo) ?? 0;\n if (count <= 1) {\n this.repoCounts.delete(repo);\n } else {\n this.repoCounts.set(repo, count - 1);\n }\n\n this.processQueue();\n }\n\n /** Non-blocking attempt to acquire a slot. Returns true if successful. */\n tryAcquire(repo: string, sessionId: string): boolean {\n if (!this.canAcquire(repo)) return false;\n this.allocate(repo, sessionId);\n return true;\n }\n\n /** Total number of active slots. */\n activeCount(): number {\n return this.activeSessions.size;\n }\n\n /** Number of active slots for a specific repo. */\n activeCountForRepo(repo: string): number {\n return this.repoCounts.get(repo) ?? 0;\n }\n\n /** Can a slot be acquired for this repo without blocking? */\n isAvailable(repo: string): boolean {\n return this.canAcquire(repo);\n }\n\n /** Current queue depth. */\n queueDepth(): number {\n return this.queue.size;\n }\n\n private canAcquire(repo: string): boolean {\n if (this.activeSessions.size >= this.maxSessions) return false;\n const repoCount = this.repoCounts.get(repo) ?? 0;\n return repoCount < this.maxPerRepo;\n }\n\n private allocate(repo: string, sessionId: string): void {\n this.activeSessions.set(sessionId, repo);\n this.repoCounts.set(repo, (this.repoCounts.get(repo) ?? 0) + 1);\n }\n\n private processQueue(): void {\n // Find the highest-priority entry whose repo has capacity\n const entry = this.queue.dequeueWhere((e) => this.canAcquire(e.repo));\n if (!entry) return;\n\n this.allocate(entry.repo, entry.sessionId);\n entry._cleanupAbort?.();\n const waitedMs = Date.now() - entry.enqueuedAt;\n this.callbacks.onDequeue?.(entry.sessionId, entry.repo, waitedMs);\n entry.resolve();\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport type { z } from \"zod\";\nimport { getDataDir, toRepoSlug } from \"@/paths\";\n\n// ─── Re-export all schemas and types from config module ──\n\nexport type {\n GitStrategy,\n GlobalConfig,\n McpServerConfig,\n NeoConfig,\n RepoConfig,\n RepoConfigInput,\n RepoOverrideConfig,\n} from \"@/config/index\";\nexport {\n budgetConfigSchema,\n ConfigStore,\n ConfigWatcher,\n concurrencyConfigSchema,\n gitStrategySchema,\n globalConfigSchema,\n mcpServerConfigSchema,\n neoConfigSchema,\n recoveryConfigSchema,\n repoConfigSchema,\n repoOverrideConfigSchema,\n sessionsConfigSchema,\n supervisorConfigSchema,\n} from \"@/config/index\";\n\n// ─── Import schemas for internal use ─────────────────────\n\nimport type { NeoConfig, RepoConfig, RepoConfigInput } from \"@/config/index\";\nimport { globalConfigSchema, neoConfigSchema, repoConfigSchema } from \"@/config/index\";\n\n// ─── Default global config ──────────────────────────────\n\nconst DEFAULT_GLOBAL_CONFIG = {\n repos: [],\n concurrency: {\n maxSessions: 5,\n maxPerRepo: 4,\n queueMax: 50,\n },\n budget: {\n dailyCapUsd: 500,\n alertThresholdPct: 80,\n },\n};\n\n// ─── YAML loader helper ─────────────────────────────────\n\nfunction parseYamlFile(raw: string, filePath: string): unknown {\n try {\n return parseYaml(raw);\n } catch (err) {\n throw new Error(\n `Invalid YAML in ${filePath}: ${err instanceof Error ? err.message : String(err)}. Check YAML syntax at the indicated line.`,\n );\n }\n}\n\nfunction formatZodErrors(issues: z.ZodIssue[], filePath: string): string {\n const formatted = issues.map((i) => ` - ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\");\n return `Invalid config in ${filePath}:\\n${formatted}`;\n}\n\n// ─── Config loaders ─────────────────────────────────────\n\n/**\n * Load NeoConfig from a single file (legacy compatibility).\n */\nexport async function loadConfig(configPath: string): Promise<NeoConfig> {\n let raw: string;\n try {\n raw = await readFile(configPath, \"utf-8\");\n } catch {\n throw new Error(`Config file not found: ${configPath}. Run 'neo init' to get started.`);\n }\n\n const parsed = parseYamlFile(raw, configPath);\n\n const result = neoConfigSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(formatZodErrors(result.error.issues, configPath));\n }\n\n return result.data;\n}\n\n/**\n * Load the global config from ~/.neo/config.yml.\n * Creates the file with defaults if it does not exist.\n */\nexport async function loadGlobalConfig(): Promise<NeoConfig> {\n const configPath = path.join(getDataDir(), \"config.yml\");\n\n if (!existsSync(configPath)) {\n await mkdir(getDataDir(), { recursive: true });\n await writeFile(configPath, stringifyYaml(DEFAULT_GLOBAL_CONFIG), \"utf-8\");\n return globalConfigSchema.parse(DEFAULT_GLOBAL_CONFIG);\n }\n\n const raw = await readFile(configPath, \"utf-8\");\n const parsed = parseYamlFile(raw, configPath);\n\n const result = globalConfigSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(formatZodErrors(result.error.issues, configPath));\n }\n\n return result.data;\n}\n\n// ─── Repo CRUD operations ───────────────────────────────\n\n/**\n * Add a repo to ~/.neo/config.yml. Deduplicates by resolved path.\n */\nexport async function addRepoToGlobalConfig(repo: RepoConfigInput): Promise<void> {\n const config = await loadGlobalConfig();\n const resolvedPath = path.resolve(repo.path);\n const parsed = repoConfigSchema.parse({ ...repo, path: resolvedPath });\n\n const existing = config.repos.findIndex((r) => path.resolve(r.path) === resolvedPath);\n if (existing >= 0) {\n config.repos[existing] = parsed;\n } else {\n config.repos.push(parsed);\n }\n\n const configPath = path.join(getDataDir(), \"config.yml\");\n await writeFile(configPath, stringifyYaml(config), \"utf-8\");\n}\n\n/**\n * Remove a repo from ~/.neo/config.yml by path, name, or slug.\n */\nexport async function removeRepoFromGlobalConfig(pathOrName: string): Promise<boolean> {\n const config = await loadGlobalConfig();\n const resolvedPath = path.resolve(pathOrName);\n const initialLength = config.repos.length;\n\n config.repos = config.repos.filter(\n (r) =>\n path.resolve(r.path) !== resolvedPath &&\n r.name !== pathOrName &&\n toRepoSlug(r) !== pathOrName,\n );\n\n if (config.repos.length === initialLength) return false;\n\n const configPath = path.join(getDataDir(), \"config.yml\");\n await writeFile(configPath, stringifyYaml(config), \"utf-8\");\n return true;\n}\n\n/**\n * List all registered repos from ~/.neo/config.yml.\n */\nexport async function listReposFromGlobalConfig(): Promise<RepoConfig[]> {\n const config = await loadGlobalConfig();\n return config.repos;\n}\n","import { homedir } from \"node:os\";\nimport path from \"node:path\";\n\n/**\n * Global data directory for runtime artifacts (journals, runs).\n * Located at ~/.neo, similar to how Claude Code uses ~/.claude.\n */\nexport function getDataDir(): string {\n return path.join(homedir(), \".neo\");\n}\n\nexport function getJournalsDir(): string {\n return path.join(getDataDir(), \"journals\");\n}\n\nexport function getRunsDir(): string {\n return path.join(getDataDir(), \"runs\");\n}\n\n/**\n * Derive a filesystem-safe slug from a repo config.\n * Uses `name` if present, otherwise `basename(path)`.\n */\nexport function toRepoSlug(repo: { name?: string | undefined; path: string }): string {\n const raw = repo.name ?? path.basename(repo.path);\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9._-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/**\n * Runs directory for a specific repo: ~/.neo/runs/<slug>/\n */\nexport function getRepoRunsDir(repoSlug: string): string {\n return path.join(getRunsDir(), repoSlug);\n}\n\n/**\n * Path to the dispatch request file for a detached run.\n */\nexport function getRunDispatchPath(repoSlug: string, runId: string): string {\n return path.join(getRepoRunsDir(repoSlug), `${runId}.dispatch.json`);\n}\n\n/**\n * Path to the log file for a detached run.\n */\nexport function getRunLogPath(repoSlug: string, runId: string): string {\n return path.join(getRepoRunsDir(repoSlug), `${runId}.log`);\n}\n\n/**\n * Directory for all supervisor instances: ~/.neo/supervisors/\n */\nexport function getSupervisorsDir(): string {\n return path.join(getDataDir(), \"supervisors\");\n}\n\n/**\n * Directory for a specific supervisor instance: ~/.neo/supervisors/<name>/\n */\nexport function getSupervisorDir(name: string): string {\n return path.join(getSupervisorsDir(), name);\n}\n\n/**\n * Path to a supervisor state file: ~/.neo/supervisors/<name>/state.json\n */\nexport function getSupervisorStatePath(name: string): string {\n return path.join(getSupervisorDir(name), \"state.json\");\n}\n\nexport function getSupervisorActivityPath(name: string): string {\n return path.join(getSupervisorDir(name), \"activity.jsonl\");\n}\n\nexport function getSupervisorInboxPath(name: string): string {\n return path.join(getSupervisorDir(name), \"inbox.jsonl\");\n}\n\nexport function getSupervisorEventsPath(name: string): string {\n return path.join(getSupervisorDir(name), \"events.jsonl\");\n}\n\nexport function getSupervisorLockPath(name: string): string {\n return path.join(getSupervisorDir(name), \"daemon.lock\");\n}\n\nexport function getSupervisorDecisionsPath(name: string): string {\n return path.join(getSupervisorDir(name), \"decisions.jsonl\");\n}\n","import { z } from \"zod\";\n\n// ─── McpServerConfig schemas ─────────────────────────────\n\nconst httpMcpServerSchema = z.object({\n type: z.literal(\"http\"),\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n});\n\nconst stdioMcpServerSchema = z.object({\n type: z.literal(\"stdio\"),\n command: z.string(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n});\n\nexport const mcpServerConfigSchema = z.discriminatedUnion(\"type\", [\n httpMcpServerSchema,\n stdioMcpServerSchema,\n]);\n\n// ─── RepoConfig schema (single repo entry) ──────────────\n\nexport const gitStrategySchema = z.enum([\"pr\", \"branch\"]).default(\"branch\");\n\nexport type GitStrategy = z.infer<typeof gitStrategySchema>;\n\nexport const repoConfigSchema = z.object({\n path: z.string(),\n name: z.string().optional(),\n defaultBranch: z.string().default(\"main\"),\n branchPrefix: z.string().default(\"feat\"),\n pushRemote: z.string().default(\"origin\"),\n gitStrategy: gitStrategySchema,\n});\n\n// ─── Concurrency config schema ───────────────────────────\n\nexport const concurrencyConfigSchema = z\n .object({\n maxSessions: z.number().default(5),\n maxPerRepo: z.number().default(4),\n queueMax: z.number().default(50),\n })\n .default({ maxSessions: 5, maxPerRepo: 4, queueMax: 50 });\n\n// ─── Budget config schema ────────────────────────────────\n\nexport const budgetConfigSchema = z\n .object({\n dailyCapUsd: z.number().default(500),\n alertThresholdPct: z.number().default(80),\n })\n .default({ dailyCapUsd: 500, alertThresholdPct: 80 });\n\n// ─── Recovery config schema ──────────────────────────────\n\nexport const recoveryConfigSchema = z\n .object({\n maxRetries: z.number().default(3),\n backoffBaseMs: z.number().default(30_000),\n })\n .default({ maxRetries: 3, backoffBaseMs: 30_000 });\n\n// ─── Sessions config schema ──────────────────────────────\n\nexport const sessionsConfigSchema = z\n .object({\n initTimeoutMs: z.number().default(120_000),\n maxDurationMs: z.number().default(3_600_000),\n dir: z.string().default(\"/tmp/neo-sessions\"),\n })\n .default({ initTimeoutMs: 120_000, maxDurationMs: 3_600_000, dir: \"/tmp/neo-sessions\" });\n\n// ─── Supervisor config schema ────────────────────────────\n\nexport const supervisorConfigSchema = z\n .object({\n port: z.number().default(7777),\n secret: z.string().optional(),\n heartbeatTimeoutMs: z.number().default(300_000),\n maxConsecutiveFailures: z.number().default(3),\n maxEventsPerSec: z.number().default(10),\n dailyCapUsd: z.number().default(50),\n /** How often consolidation runs (ms) */\n consolidationIntervalMs: z.number().default(300_000),\n /** How often compaction runs (ms) */\n compactionIntervalMs: z.number().default(3_600_000),\n /** Safety timeout for waitForWork (ms) */\n eventTimeoutMs: z.number().default(300_000),\n instructions: z.string().optional(),\n /** Max consecutive idle loop iterations before supervisor pauses polling */\n idleSkipMax: z.number().default(20),\n /** Max consecutive active-work loop iterations before supervisor yields */\n activeWorkSkipMax: z.number().default(3),\n /** When true, supervisor answers pending decisions autonomously instead of waiting for human input */\n autoDecide: z.boolean().default(false),\n })\n .default({\n port: 7777,\n heartbeatTimeoutMs: 300_000,\n maxConsecutiveFailures: 3,\n maxEventsPerSec: 10,\n dailyCapUsd: 50,\n consolidationIntervalMs: 300_000,\n compactionIntervalMs: 3_600_000,\n eventTimeoutMs: 300_000,\n idleSkipMax: 20,\n activeWorkSkipMax: 3,\n autoDecide: false,\n });\n\n// ─── Global config schema (~/.neo/config.yml) ───────────\n// This is now the single source of truth — repos are registered here.\n\nexport const globalConfigSchema = z.object({\n repos: z.array(repoConfigSchema).default([]),\n\n concurrency: concurrencyConfigSchema,\n\n budget: budgetConfigSchema,\n\n recovery: recoveryConfigSchema,\n\n sessions: sessionsConfigSchema,\n\n webhooks: z\n .array(\n z.object({\n url: z.string().url(),\n events: z.array(z.string()).optional(),\n secret: z.string().optional(),\n timeoutMs: z.number().default(5000),\n }),\n )\n .default([]),\n\n supervisor: supervisorConfigSchema,\n\n memory: z\n .object({\n embeddings: z.boolean().default(true),\n })\n .default({ embeddings: true }),\n\n mcpServers: z.record(z.string(), mcpServerConfigSchema).optional(),\n claudeCodePath: z.string().optional(),\n\n idempotency: z\n .object({\n enabled: z.boolean().default(true),\n key: z.enum([\"metadata\", \"prompt\"]).default(\"metadata\"),\n ttlMs: z.number().default(3_600_000),\n })\n .optional(),\n});\n\n// ─── NeoConfig = GlobalConfig (single schema now) ────────\n\nexport const neoConfigSchema = globalConfigSchema;\n\n// ─── Repo override config schema ─────────────────────────\n// Partial subset for repo-level overrides.\n// Only allows: concurrency, budget, recovery, sessions keys.\n\nexport const repoOverrideConfigSchema = z\n .object({\n concurrency: concurrencyConfigSchema.unwrap().partial().optional(),\n budget: budgetConfigSchema.unwrap().partial().optional(),\n recovery: recoveryConfigSchema.unwrap().partial().optional(),\n sessions: sessionsConfigSchema.unwrap().partial().optional(),\n })\n .partial();\n\n// ─── Derived types ───────────────────────────────────────\n\nexport type NeoConfig = z.infer<typeof neoConfigSchema>;\nexport type GlobalConfig = NeoConfig;\nexport type RepoConfig = z.infer<typeof repoConfigSchema>;\nexport type RepoConfigInput = z.input<typeof repoConfigSchema>;\nexport type McpServerConfig = z.infer<typeof mcpServerConfigSchema>;\nexport type RepoOverrideConfig = z.infer<typeof repoOverrideConfigSchema>;\n","import type { NeoConfig } from \"./schema\";\n\n/**\n * Retrieves a nested value from config using dot notation.\n *\n * @param config - The configuration object\n * @param path - Dot-separated path (e.g., \"budget.dailyCapUsd\")\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * getConfigValue(config, \"budget.dailyCapUsd\") // 500\n * getConfigValue(config, \"missing.path\") // undefined\n */\nexport function getConfigValue(config: NeoConfig, path: string): unknown {\n if (path === \"\") {\n return config;\n }\n\n const keys = path.split(\".\");\n let current: unknown = config;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n\n if (typeof current !== \"object\") {\n return undefined;\n }\n\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n}\n\n/**\n * Sets a nested value in config using dot notation, returning a new config object.\n * Creates intermediate objects as needed.\n *\n * @param config - The configuration object\n * @param path - Dot-separated path (e.g., \"budget.dailyCapUsd\")\n * @param value - The value to set\n * @returns A new config object with the value set (immutable update)\n *\n * @example\n * setConfigValue(config, \"budget.dailyCapUsd\", 1000)\n * setConfigValue(config, \"new.nested.key\", \"value\")\n */\nexport function setConfigValue(config: NeoConfig, path: string, value: unknown): NeoConfig {\n if (path === \"\") {\n // Empty path means replace entire config\n return value as NeoConfig;\n }\n\n const keys = path.split(\".\");\n return setNestedValue(config, keys, value) as NeoConfig;\n}\n\n/**\n * Recursively builds a new object with the value set at the given key path.\n */\nfunction setNestedValue(obj: unknown, keys: readonly string[], value: unknown): unknown {\n const key = keys[0];\n if (key === undefined) {\n return value;\n }\n\n const rest = keys.slice(1);\n\n // Get current object or create empty object if missing/invalid\n const current: Record<string, unknown> =\n obj !== null && typeof obj === \"object\" ? { ...(obj as Record<string, unknown>) } : {};\n\n if (rest.length === 0) {\n // Last key - set the value\n current[key] = value;\n } else {\n // Intermediate key - recurse\n current[key] = setNestedValue(current[key], rest, value);\n }\n\n return current;\n}\n","import type { NeoConfig, RepoOverrideConfig } from \"./schema\";\nimport {\n budgetConfigSchema,\n concurrencyConfigSchema,\n recoveryConfigSchema,\n sessionsConfigSchema,\n} from \"./schema\";\n\n// ─── Default configuration ─────────────────────────────────\n\n/**\n * Default configuration values.\n * Used as base layer when merging configs.\n */\nexport const defaultConfig: NeoConfig = {\n repos: [],\n concurrency: concurrencyConfigSchema.parse(undefined),\n budget: budgetConfigSchema.parse(undefined),\n recovery: recoveryConfigSchema.parse(undefined),\n sessions: sessionsConfigSchema.parse(undefined),\n webhooks: [],\n supervisor: {\n port: 7777,\n heartbeatTimeoutMs: 300_000,\n maxConsecutiveFailures: 3,\n maxEventsPerSec: 10,\n dailyCapUsd: 50,\n consolidationIntervalMs: 300_000,\n compactionIntervalMs: 3_600_000,\n eventTimeoutMs: 300_000,\n idleSkipMax: 20,\n activeWorkSkipMax: 3,\n autoDecide: false,\n },\n memory: { embeddings: true },\n};\n\n// ─── Deep merge utility ────────────────────────────────────\n\n/**\n * Deep merges two objects, with source values taking precedence.\n * Arrays are replaced, not merged.\n */\nfunction deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key of Object.keys(source) as Array<keyof T>) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (sourceValue === undefined) {\n continue;\n }\n\n if (\n sourceValue !== null &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue !== null &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n // Recursively merge nested objects\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>,\n ) as T[keyof T];\n } else {\n // Replace primitive values and arrays\n result[key] = sourceValue as T[keyof T];\n }\n }\n\n return result;\n}\n\n// ─── Deep freeze utility ────────────────────────────────────\n\n/**\n * Recursively freezes an object and all nested objects.\n */\nfunction deepFreeze<T>(obj: T): Readonly<T> {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n\n // Freeze arrays and their elements\n if (Array.isArray(obj)) {\n for (const item of obj) {\n deepFreeze(item);\n }\n return Object.freeze(obj) as Readonly<T>;\n }\n\n // Freeze object properties recursively\n for (const value of Object.values(obj)) {\n deepFreeze(value);\n }\n\n return Object.freeze(obj) as Readonly<T>;\n}\n\n// ─── Config merging ────────────────────────────────────────\n\n/**\n * Merges multiple config layers with precedence: repo > global > defaults.\n *\n * @param defaults - Base configuration defaults\n * @param globalConfig - Global config from ~/.neo/config.yml (optional)\n * @param repoConfig - Repo-level overrides from <repo>/.neo/config.yml (optional)\n * @returns Fully resolved, frozen NeoConfig\n *\n * @example\n * const config = mergeConfigs(defaultConfig, globalConfig, repoOverrides);\n */\nexport function mergeConfigs(\n defaults: NeoConfig,\n globalConfig?: Partial<NeoConfig> | null,\n repoConfig?: RepoOverrideConfig | null,\n): Readonly<NeoConfig> {\n // Start with defaults\n let result = { ...defaults };\n\n // Merge global config (second priority)\n if (globalConfig) {\n result = deepMerge(result, globalConfig);\n }\n\n // Merge repo overrides (highest priority)\n if (repoConfig) {\n result = deepMerge(result, repoConfig as Partial<NeoConfig>);\n }\n\n return deepFreeze(result);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { getConfigValue } from \"./dotNotation\";\nimport { defaultConfig, mergeConfigs } from \"./merge\";\nimport type { NeoConfig, RepoOverrideConfig } from \"./schema\";\nimport { neoConfigSchema, repoOverrideConfigSchema } from \"./schema\";\n\n// ─── ConfigStore ───────────────────────────────────────────\n\n/**\n * Configuration store that loads and merges config files.\n *\n * Config precedence (highest to lowest):\n * 1. Repo config: <repoPath>/.neo/config.yml\n * 2. Global config: ~/.neo/config.yml\n * 3. Default values (hardcoded)\n *\n * @example\n * const store = new ConfigStore('/path/to/repo');\n * await store.load();\n * const dailyCap = store.get<number>('budget.dailyCapUsd');\n */\nexport class ConfigStore {\n private repoPath: string | undefined;\n private config: NeoConfig | null = null;\n\n constructor(repoPath?: string) {\n this.repoPath = repoPath;\n }\n\n // ─── Public API ────────────────────────────────────────\n\n /**\n * Loads and merges config files from all locations.\n * Must be called before get() or getAll().\n */\n async load(): Promise<void> {\n const globalConfig = await this.loadGlobalConfig();\n const repoConfig = await this.loadRepoConfig();\n\n this.config = mergeConfigs(defaultConfig, globalConfig, repoConfig);\n }\n\n /**\n * Gets a config value using dot notation.\n *\n * @param key - Dot-separated path (e.g., \"budget.dailyCapUsd\")\n * @returns The value at the path\n * @throws Error if load() has not been called\n *\n * @example\n * store.get<number>('budget.dailyCapUsd') // 500\n * store.get<string>('sessions.dir') // '/tmp/neo-sessions'\n */\n get<T>(key: string): T {\n if (this.config === null) {\n throw new Error(\"ConfigStore not loaded. Call load() first.\");\n }\n\n return getConfigValue(this.config, key) as T;\n }\n\n /**\n * Returns the full merged configuration.\n *\n * @throws Error if load() has not been called\n */\n getAll(): NeoConfig {\n if (this.config === null) {\n throw new Error(\"ConfigStore not loaded. Call load() first.\");\n }\n\n return this.config;\n }\n\n /**\n * Returns the repository path, if one was provided.\n * Used by ConfigWatcher to determine which files to watch.\n */\n getRepoPath(): string | undefined {\n return this.repoPath;\n }\n\n // ─── Private loaders ───────────────────────────────────\n\n /**\n * Loads global config from ~/.neo/config.yml\n */\n private async loadGlobalConfig(): Promise<NeoConfig | null> {\n const globalPath = join(homedir(), \".neo\", \"config.yml\");\n const raw = await this.loadFile(globalPath);\n\n if (raw === null) {\n return null;\n }\n\n // Validate and parse with defaults\n const parsed = neoConfigSchema.safeParse(raw);\n if (!parsed.success) {\n // Invalid config files are silently ignored — defaults apply\n return null;\n }\n\n return parsed.data;\n }\n\n /**\n * Loads repo-level overrides from <repoPath>/.neo/config.yml\n */\n private async loadRepoConfig(): Promise<RepoOverrideConfig | null> {\n if (!this.repoPath) {\n return null;\n }\n\n const repoConfigPath = join(this.repoPath, \".neo\", \"config.yml\");\n const raw = await this.loadFile(repoConfigPath);\n\n if (raw === null) {\n return null;\n }\n\n // Validate repo overrides (partial subset)\n const parsed = repoOverrideConfigSchema.safeParse(raw);\n if (!parsed.success) {\n // Invalid config files are silently ignored — defaults apply\n return null;\n }\n\n return parsed.data;\n }\n\n /**\n * Loads and parses a YAML config file.\n *\n * @param filePath - Absolute path to the config file\n * @returns Parsed YAML content or null if file doesn't exist\n */\n private async loadFile(filePath: string): Promise<Record<string, unknown> | null> {\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const parsed = parseYaml(content);\n\n if (parsed === null || typeof parsed !== \"object\") {\n return null;\n }\n\n return parsed as Record<string, unknown>;\n } catch {\n // Parse errors are silently ignored — missing/invalid files return null\n return null;\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type FSWatcher, watch } from \"chokidar\";\nimport type { ConfigStore } from \"./ConfigStore\";\n\n// ─── ConfigWatcher ─────────────────────────────────────────\n\n/**\n * Watches config files and reloads the store on changes.\n *\n * Emits 'change' event after successful reload.\n * Uses debouncing to handle rapid saves (e.g., editor auto-save).\n *\n * @example\n * const store = new ConfigStore('/path/to/repo');\n * await store.load();\n *\n * const watcher = new ConfigWatcher(store, { debounceMs: 300 });\n * watcher.on('change', () => console.log('Config reloaded'));\n * watcher.start();\n *\n * // Later: stop watching\n * watcher.stop();\n */\nexport class ConfigWatcher extends EventEmitter {\n private readonly store: ConfigStore;\n private readonly debounceMs: number;\n private readonly repoPath: string | undefined;\n private watcher: FSWatcher | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(store: ConfigStore, options?: { debounceMs?: number }) {\n super();\n this.store = store;\n this.debounceMs = options?.debounceMs ?? 500;\n this.repoPath = store.getRepoPath();\n }\n\n /**\n * Starts watching config files for changes.\n * Watches both global (~/.neo/config.yml) and repo config files.\n */\n start(): void {\n if (this.watcher) {\n return; // Already watching\n }\n\n const paths = this.getConfigPaths();\n\n this.watcher = watch(paths, {\n ignoreInitial: true,\n // Don't error if files don't exist — they may be created later\n ignorePermissionErrors: true,\n });\n\n this.watcher.on(\"change\", () => this.handleChange());\n this.watcher.on(\"add\", () => this.handleChange());\n this.watcher.on(\"unlink\", () => this.handleChange());\n }\n\n /**\n * Stops watching config files.\n */\n stop(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n }\n\n // ─── Private ─────────────────────────────────────────────\n\n /**\n * Returns the list of config file paths to watch.\n */\n private getConfigPaths(): string[] {\n const globalPath = join(homedir(), \".neo\", \"config.yml\");\n const paths = [globalPath];\n\n if (this.repoPath) {\n const repoConfigPath = join(this.repoPath, \".neo\", \"config.yml\");\n paths.push(repoConfigPath);\n }\n\n return paths;\n }\n\n /**\n * Handles file change events with debouncing.\n */\n private handleChange(): void {\n // Clear existing timer to debounce rapid changes\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.reloadConfig();\n }, this.debounceMs);\n }\n\n /**\n * Reloads the config and emits 'change' event.\n */\n private async reloadConfig(): Promise<void> {\n try {\n await this.store.load();\n this.emit(\"change\");\n } catch {\n // Silently ignore reload errors — file may be temporarily invalid\n // ConfigStore.load() already handles missing/invalid files gracefully\n }\n }\n}\n","import { appendFile, readFile } from \"node:fs/promises\";\nimport { fileForDate, toDateKey } from \"@/shared/date\";\nimport { ensureDir } from \"@/shared/fs\";\nimport type { CostEntry } from \"@/types\";\n\n/**\n * Append-only JSONL journal for cost tracking.\n * Monthly file rotation: cost-YYYY-MM.jsonl\n */\nexport class CostJournal {\n private readonly dir: string;\n private readonly dirCache = new Set<string>();\n private dayCache: { key: string; total: number } | null = null;\n\n constructor(options: { dir: string }) {\n this.dir = options.dir;\n }\n\n async append(entry: CostEntry): Promise<void> {\n await ensureDir(this.dir, this.dirCache);\n const file = fileForDate(new Date(entry.timestamp), \"cost\", this.dir);\n await appendFile(file, `${JSON.stringify(entry)}\\n`, \"utf-8\");\n // Invalidate cache — the day total may have changed\n this.dayCache = null;\n }\n\n async getDayTotal(date?: Date): Promise<number> {\n const d = date ?? new Date();\n const dayKey = toDateKey(d);\n\n if (this.dayCache?.key === dayKey) {\n return this.dayCache.total;\n }\n\n const file = fileForDate(d, \"cost\", this.dir);\n let total = 0;\n\n try {\n const content = await readFile(file, \"utf-8\");\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n const entry = JSON.parse(line) as CostEntry;\n if (toDateKey(new Date(entry.timestamp)) === dayKey) {\n total += entry.costUsd;\n }\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n // File doesn't exist yet — total is 0\n }\n\n this.dayCache = { key: dayKey, total };\n return total;\n }\n}\n","import path from \"node:path\";\n\n/**\n * Converts a Date to a YYYY-MM-DD string in UTC.\n *\n * Uses UTC to ensure consistent date keys regardless of local timezone.\n * This is critical for cost tracking and event journaling where entries\n * must be grouped by calendar day consistently across all environments.\n *\n * @param date - The date to convert.\n * @returns A string in YYYY-MM-DD format (e.g., \"2026-03-14\").\n *\n * @example\n * ```ts\n * import { toDateKey } from \"@/shared/date\";\n *\n * toDateKey(new Date(\"2026-03-14T10:00:00Z\")); // => \"2026-03-14\"\n * toDateKey(new Date(\"2026-03-14T23:59:59Z\")); // => \"2026-03-14\"\n * ```\n */\nexport function toDateKey(date: Date): string {\n return date.toISOString().slice(0, 10);\n}\n\n/**\n * Generates a dated file path with monthly rotation.\n *\n * Creates paths in the format: `{dir}/{prefix}-YYYY-MM.jsonl`\n * Uses UTC year/month to ensure consistent file paths across timezones.\n *\n * @param date - The date used to determine the year and month for the file name.\n * @param prefix - The prefix for the file name (e.g., \"cost\", \"events\").\n * @param dir - The directory where the file will be located.\n * @returns The full file path (e.g., \"/data/cost-2026-03.jsonl\").\n *\n * @example\n * ```ts\n * import { fileForDate } from \"@/shared/date\";\n *\n * fileForDate(new Date(\"2026-03-14T10:00:00Z\"), \"cost\", \"/data\");\n * // => \"/data/cost-2026-03.jsonl\"\n *\n * fileForDate(new Date(\"2026-12-31T23:59:59Z\"), \"events\", \"/logs\");\n * // => \"/logs/events-2026-12.jsonl\"\n * ```\n */\nexport function fileForDate(date: Date, prefix: string, dir: string): string {\n const yyyy = date.getUTCFullYear();\n const mm = String(date.getUTCMonth() + 1).padStart(2, \"0\");\n return path.join(dir, `${prefix}-${yyyy}-${mm}.jsonl`);\n}\n","import { mkdir } from \"node:fs/promises\";\n\n/**\n * Ensures a directory exists, creating it recursively if necessary.\n *\n * Uses an optional cache to avoid redundant filesystem calls when the same\n * directory is ensured multiple times. This is useful in hot paths where\n * directory existence is checked frequently.\n *\n * @param dirPath - The absolute or relative path to the directory to ensure.\n * @param cache - Optional Set to track directories that have already been created.\n * When provided, subsequent calls with the same path skip the mkdir call.\n * @returns A promise that resolves when the directory exists.\n *\n * @example\n * ```ts\n * import { ensureDir } from \"@/shared/fs\";\n *\n * // Basic usage - creates directory if it doesn't exist\n * await ensureDir(\"/tmp/my-app/logs\");\n *\n * // With caching - second call skips filesystem\n * const cache = new Set<string>();\n * await ensureDir(\"/tmp/my-app/logs\", cache); // calls mkdir\n * await ensureDir(\"/tmp/my-app/logs\", cache); // returns immediately\n * ```\n */\nexport async function ensureDir(dirPath: string, cache?: Set<string>): Promise<void> {\n if (cache?.has(dirPath)) {\n return;\n }\n\n await mkdir(dirPath, { recursive: true });\n\n cache?.add(dirPath);\n}\n","import { EventEmitter } from \"node:events\";\nimport type { NeoEvent } from \"@/types\";\n\n/**\n * Safe EventEmitter wrapper (ADR-022).\n *\n * - Catches listener errors to prevent cascading crashes\n * - Emits on both the specific event type and the wildcard \"*\" channel\n * - Swallows errors from the error handler itself to guarantee stability\n */\nexport class NeoEventEmitter {\n private readonly emitter = new EventEmitter();\n\n emit(event: NeoEvent): void {\n this.safeEmit(event.type, event);\n this.safeEmit(\"*\", event);\n }\n\n on(eventType: string, listener: (event: NeoEvent) => void): this {\n this.emitter.on(eventType, listener);\n return this;\n }\n\n off(eventType: string, listener: (event: NeoEvent) => void): this {\n this.emitter.off(eventType, listener);\n return this;\n }\n\n once(eventType: string, listener: (event: NeoEvent) => void): this {\n this.emitter.once(eventType, listener);\n return this;\n }\n\n removeAllListeners(eventType?: string): this {\n this.emitter.removeAllListeners(eventType);\n return this;\n }\n\n private safeEmit(eventType: string, event: NeoEvent): void {\n try {\n this.emitter.emit(eventType, event);\n } catch (error) {\n if (eventType !== \"error\") {\n try {\n this.emitter.emit(\"error\", error);\n } catch {\n // Swallow — prevent crash even if error handler throws\n }\n }\n }\n }\n}\n","import { appendFile } from \"node:fs/promises\";\nimport { fileForDate } from \"@/shared/date\";\nimport { ensureDir } from \"@/shared/fs\";\nimport type { NeoEvent } from \"@/types\";\n\n/**\n * Append-only JSONL journal for events.\n * Monthly file rotation: events-YYYY-MM.jsonl\n * Write-only for v0.1 — read API comes in v0.2.\n */\nexport class EventJournal {\n private readonly dir: string;\n private readonly dirCache = new Set<string>();\n\n constructor(options: { dir: string }) {\n this.dir = options.dir;\n }\n\n async append(event: NeoEvent): Promise<void> {\n await ensureDir(this.dir, this.dirCache);\n const file = fileForDate(new Date(event.timestamp), \"events\", this.dir);\n await appendFile(file, `${JSON.stringify(event)}\\n`, \"utf-8\");\n }\n}\n","import { createHmac, randomUUID } from \"node:crypto\";\nimport type { NeoConfig } from \"@/config\";\nimport type { NeoEvent } from \"@/types\";\n\ntype WebhookConfig = NeoConfig[\"webhooks\"][number];\n\ninterface WebhookPayload {\n id: string;\n version: 1;\n event: string;\n payload: Record<string, unknown>;\n source: \"neo\";\n deliveredAt: string;\n}\n\n/** Event types that get retry on failure (terminal events the supervisor must see). */\nconst RETRY_EVENT_TYPES = new Set([\"session:complete\", \"session:fail\", \"budget:alert\"]);\n\nconst RETRY_MAX_ATTEMPTS = 3;\nconst RETRY_BASE_DELAY_MS = 500;\n\n/**\n * Webhook dispatcher for NeoEvents.\n *\n * - Matches events against per-webhook filters (exact or wildcard like \"session:*\")\n * - Excludes gate:waiting events (contain non-serializable callbacks)\n * - Signs payloads with HMAC-SHA256 when a secret is configured\n * - Terminal events (session:complete, session:fail, budget:alert) are retried\n * with exponential backoff on failure\n * - Non-terminal events remain fire-and-forget\n */\nexport class WebhookDispatcher {\n private readonly webhooks: WebhookConfig[];\n private readonly pending: Set<Promise<void>> = new Set();\n\n constructor(webhooks: WebhookConfig[]) {\n this.webhooks = webhooks;\n }\n\n dispatch(event: NeoEvent): void {\n // gate:waiting contains non-serializable callbacks (approve/reject)\n if (event.type === \"gate:waiting\") return;\n\n for (const webhook of this.webhooks) {\n if (!matchesFilter(event.type, webhook.events)) continue;\n\n const payload: WebhookPayload = {\n id: randomUUID(),\n version: 1,\n event: event.type,\n payload: toSerializable(event),\n source: \"neo\",\n deliveredAt: new Date().toISOString(),\n };\n\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (webhook.secret) {\n headers[\"X-Neo-Signature\"] = sign(body, webhook.secret);\n }\n\n if (RETRY_EVENT_TYPES.has(event.type)) {\n // Terminal events: retry with exponential backoff, track for flush\n const p = sendWithRetry(webhook.url, headers, body, webhook.timeoutMs)\n .catch(() => {})\n .finally(() => this.pending.delete(p));\n this.pending.add(p);\n } else {\n // Non-terminal: fire-and-forget\n fetch(webhook.url, {\n method: \"POST\",\n headers,\n body,\n signal: AbortSignal.timeout(webhook.timeoutMs),\n }).catch(() => {});\n }\n }\n }\n\n /** Wait for all pending terminal webhook deliveries to complete. */\n async flush(): Promise<void> {\n if (this.pending.size === 0) return;\n await Promise.allSettled([...this.pending]);\n }\n}\n\n/**\n * Send a webhook POST with exponential backoff retry.\n * Retries up to RETRY_MAX_ATTEMPTS times with delays of 500ms, 1s, 2s.\n */\nasync function sendWithRetry(\n url: string,\n headers: Record<string, string>,\n body: string,\n timeoutMs: number,\n): Promise<void> {\n for (let attempt = 1; attempt <= RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n if (res.ok) return;\n // Non-2xx: treat as failure, retry\n } catch {\n // Network error or timeout: retry\n }\n\n if (attempt < RETRY_MAX_ATTEMPTS) {\n const delay = RETRY_BASE_DELAY_MS * 2 ** (attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n}\n\n/**\n * Check if an event type matches a filter list.\n * Supports exact matches and wildcard prefixes (e.g. \"session:*\").\n * No filter (undefined) means all events match.\n */\nexport function matchesFilter(eventType: string, filters?: string[]): boolean {\n if (!filters || filters.length === 0) return true;\n return filters.some((f) => {\n if (f.endsWith(\":*\")) return eventType.startsWith(f.slice(0, -1));\n return f === eventType;\n });\n}\n\nfunction sign(body: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n}\n\nfunction toSerializable(event: NeoEvent): Record<string, unknown> {\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(event)) {\n if (typeof value !== \"function\") {\n obj[key] = value;\n }\n }\n return obj;\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rm } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT = 60_000;\n\nexport interface SessionCloneInfo {\n path: string;\n branch: string;\n repoPath: string;\n}\n\n/**\n * Create an isolated git clone for an agent session.\n * Uses `git clone --local` to hardlink objects (fast, no network).\n * Then checks out the target branch (existing or new).\n */\nexport async function createSessionClone(options: {\n repoPath: string;\n branch: string;\n baseBranch: string;\n sessionDir: string;\n}): Promise<SessionCloneInfo> {\n const repoPath = resolve(options.repoPath);\n const sessionDir = resolve(options.sessionDir);\n\n await mkdir(dirname(sessionDir), { recursive: true });\n\n // Resolve the real upstream remote URL so the clone is completely\n // independent from the user's local repo. This prevents any git\n // operations in the clone from leaking into the user's working tree.\n const remoteUrl = await execFileAsync(\"git\", [\"config\", \"--get\", \"remote.origin.url\"], {\n cwd: repoPath,\n timeout: GIT_TIMEOUT,\n })\n .then(({ stdout }) => stdout.trim())\n .catch(() => \"\");\n\n // Clone from the real remote (GitHub) instead of the local path.\n // This ensures zero coupling: no hardlinks, no local-path origin,\n // no alternates. Falls back to local clone if no remote is configured.\n const cloneSource = remoteUrl || repoPath;\n await execFileAsync(\"git\", [\"clone\", \"--branch\", options.baseBranch, cloneSource, sessionDir], {\n timeout: GIT_TIMEOUT,\n });\n\n // If branch === baseBranch, we're already on it after clone — nothing to do\n if (options.branch !== options.baseBranch) {\n // Check if the target branch already exists on the remote (e.g. fixer on existing PR)\n const branchExists = await execFileAsync(\n \"git\",\n [\"ls-remote\", \"--heads\", \"origin\", options.branch],\n { cwd: sessionDir, timeout: GIT_TIMEOUT },\n )\n .then(({ stdout }) => stdout.trim().length > 0)\n .catch(() => false);\n\n if (branchExists) {\n // Fetch and checkout the existing branch\n await execFileAsync(\"git\", [\"fetch\", \"origin\", options.branch], {\n cwd: sessionDir,\n timeout: GIT_TIMEOUT,\n });\n await execFileAsync(\"git\", [\"checkout\", \"-b\", options.branch, `origin/${options.branch}`], {\n cwd: sessionDir,\n timeout: GIT_TIMEOUT,\n });\n } else {\n // Create a new branch from baseBranch\n await execFileAsync(\"git\", [\"checkout\", \"-b\", options.branch], {\n cwd: sessionDir,\n timeout: GIT_TIMEOUT,\n });\n }\n }\n\n return { path: sessionDir, branch: options.branch, repoPath };\n}\n\n/**\n * Remove a session clone directory.\n * Idempotent — does not throw if the directory is already gone.\n */\nexport async function removeSessionClone(sessionPath: string): Promise<void> {\n const absPath = resolve(sessionPath);\n\n if (!existsSync(absPath)) {\n return;\n }\n\n await rm(absPath, { recursive: true, force: true });\n}\n\n/**\n * List all session clones under a base directory.\n */\nexport async function listSessionClones(sessionsBaseDir: string): Promise<SessionCloneInfo[]> {\n const absBase = resolve(sessionsBaseDir);\n\n if (!existsSync(absBase)) {\n return [];\n }\n\n const entries = await readdir(absBase, { withFileTypes: true });\n const clones: SessionCloneInfo[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const clonePath = resolve(absBase, entry.name);\n\n try {\n const { stdout: branchOut } = await execFileAsync(\n \"git\",\n [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"],\n {\n cwd: clonePath,\n timeout: GIT_TIMEOUT,\n },\n );\n let repoPath = clonePath;\n try {\n const { stdout: originUrl } = await execFileAsync(\n \"git\",\n [\"config\", \"--get\", \"remote.origin.url\"],\n { cwd: clonePath, timeout: GIT_TIMEOUT },\n );\n const url = originUrl.trim();\n if (url) repoPath = resolve(clonePath, url);\n } catch {\n // No origin or not a clone — keep clonePath as fallback\n }\n clones.push({\n path: clonePath,\n branch: branchOut.trim(),\n repoPath,\n });\n } catch {\n // Not a git repo — skip\n }\n }\n\n return clones;\n}\n","import { execFile } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { RepoConfig } from \"@/config\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT = 60_000;\n\n/**\n * Run a git command with execFile (no shell — prevents injection).\n */\nasync function git(repoPath: string, args: string[]): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", args, {\n cwd: resolve(repoPath),\n timeout: GIT_TIMEOUT,\n });\n return stdout.trim();\n}\n\nexport async function createBranch(\n repoPath: string,\n branch: string,\n baseBranch: string,\n): Promise<void> {\n await git(repoPath, [\"branch\", branch, baseBranch]);\n}\n\nexport async function pushBranch(repoPath: string, branch: string, remote: string): Promise<void> {\n await git(repoPath, [\"push\", remote, branch]);\n}\n\nexport async function fetchRemote(repoPath: string, remote: string): Promise<void> {\n await git(repoPath, [\"fetch\", remote]);\n}\n\nexport async function deleteBranch(repoPath: string, branch: string): Promise<void> {\n await git(repoPath, [\"branch\", \"-D\", branch]);\n}\n\nexport async function getCurrentBranch(repoPath: string): Promise<string> {\n return git(repoPath, [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n}\n\n/**\n * Resolve the branch name for a run.\n * If an explicit branch is provided, use it as-is.\n * Otherwise, generate a deterministic name from the repo's branchPrefix and runId.\n */\nexport function getBranchName(config: RepoConfig, runId: string, branch?: string): string {\n if (branch) return branch;\n const prefix = config.branchPrefix ?? \"feat\";\n const sanitized = runId.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n return `${prefix}/run-${sanitized}`;\n}\n\n/**\n * Check if a session clone has uncommitted changes (staged or unstaged).\n */\nexport async function hasUncommittedChanges(sessionPath: string): Promise<boolean> {\n const status = await git(sessionPath, [\"status\", \"--porcelain\"]);\n return status.length > 0;\n}\n\n/**\n * Auto-commit all changes in a session clone. Used as a safety net after agent\n * sessions to prevent losing work when the clone is cleaned up.\n */\nexport async function autoCommitChanges(sessionPath: string, runId: string): Promise<boolean> {\n const hasChanges = await hasUncommittedChanges(sessionPath);\n if (!hasChanges) return false;\n\n await git(sessionPath, [\"add\", \"-A\"]);\n await git(sessionPath, [\n \"commit\",\n \"-m\",\n `chore: auto-commit uncommitted changes from run ${runId}`,\n ]);\n\n return true;\n}\n\n/**\n * Push a branch from a session clone to a remote. Silently succeeds if\n * the branch has no new commits to push.\n */\nexport async function pushSessionBranch(\n sessionPath: string,\n branch: string,\n remote: string,\n): Promise<void> {\n await git(sessionPath, [\"push\", \"-u\", remote, branch]);\n}\n","import { resolve } from \"node:path\";\nimport type { ResolvedAgent } from \"@/types\";\n\n/**\n * SDK-compatible sandbox configuration.\n * Controls which tools an agent can use and which paths it can access.\n */\nexport interface SandboxConfig {\n /** Tools the agent is allowed to use */\n allowedTools: string[];\n /** Directories the agent can read from */\n readablePaths: string[];\n /** Directories the agent can write to (empty for readonly agents) */\n writablePaths: string[];\n /** Whether the agent has write access */\n writable: boolean;\n}\n\n/** Tools that modify the filesystem */\nconst WRITE_TOOLS = new Set([\"Write\", \"Edit\", \"NotebookEdit\"]);\n\n/**\n * Build an SDK-compatible sandbox configuration for an agent.\n *\n * - Writable agents: all their tools are allowed, write paths include the session clone\n * - Readonly agents: write tools are filtered out, no writable paths\n */\nexport function buildSandboxConfig(agent: ResolvedAgent, sessionPath?: string): SandboxConfig {\n const isWritable = agent.sandbox === \"writable\";\n const absSession = sessionPath ? resolve(sessionPath) : undefined;\n\n const allowedTools = isWritable\n ? agent.definition.tools\n : agent.definition.tools.filter((t) => !WRITE_TOOLS.has(t));\n\n const readablePaths = absSession ? [absSession] : [];\n const writablePaths = isWritable && absSession ? [absSession] : [];\n\n return {\n allowedTools,\n readablePaths,\n writablePaths,\n writable: isWritable,\n };\n}\n","import { appendFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Middleware } from \"@/types\";\n\nconst DEFAULT_FLUSH_INTERVAL_MS = 500;\nconst DEFAULT_FLUSH_SIZE = 20;\n\n/**\n * Audit log middleware.\n *\n * Buffers JSONL entries in memory and flushes to disk either when\n * the buffer reaches `flushSize` entries or every `flushIntervalMs`.\n * File per session. Uses `{ decision: \"async\" }` so it never blocks the chain.\n *\n * Call `flush()` to force-write remaining entries (e.g. on shutdown).\n */\nexport interface AuditLogMiddleware extends Middleware {\n flush: () => Promise<void>;\n}\n\nexport function auditLog(options: {\n dir: string;\n includeInput?: boolean;\n includeOutput?: boolean;\n flushIntervalMs?: number;\n flushSize?: number;\n}): AuditLogMiddleware {\n const {\n dir,\n includeInput = true,\n includeOutput = false,\n flushIntervalMs = DEFAULT_FLUSH_INTERVAL_MS,\n flushSize = DEFAULT_FLUSH_SIZE,\n } = options;\n\n let dirCreated = false;\n // sessionId → buffered lines\n const buffers = new Map<string, string[]>();\n let flushTimer: ReturnType<typeof setInterval> | undefined;\n\n async function ensureDir(): Promise<void> {\n if (!dirCreated) {\n await mkdir(dir, { recursive: true });\n dirCreated = true;\n }\n }\n\n async function flushAll(): Promise<void> {\n if (buffers.size === 0) return;\n await ensureDir();\n\n const writes: Promise<void>[] = [];\n for (const [sessionId, lines] of buffers) {\n const filePath = path.join(dir, `${sessionId}.jsonl`);\n writes.push(appendFile(filePath, lines.join(\"\"), \"utf-8\"));\n }\n buffers.clear();\n await Promise.all(writes);\n }\n\n async function flushSession(sessionId: string): Promise<void> {\n const lines = buffers.get(sessionId);\n if (!lines || lines.length === 0) return;\n await ensureDir();\n\n const filePath = path.join(dir, `${sessionId}.jsonl`);\n await appendFile(filePath, lines.join(\"\"), \"utf-8\");\n buffers.delete(sessionId);\n }\n\n return {\n name: \"audit-log\",\n on: \"PostToolUse\",\n async flush() {\n await flushAll();\n if (flushTimer !== undefined) {\n clearInterval(flushTimer);\n flushTimer = undefined;\n }\n },\n async handler(event, context) {\n const entry: Record<string, unknown> = {\n timestamp: new Date().toISOString(),\n sessionId: event.sessionId,\n agent: context.agent,\n toolName: event.toolName,\n };\n\n if (includeInput && event.input !== undefined) {\n entry.input = event.input;\n }\n\n if (includeOutput && event.output !== undefined) {\n entry.output = event.output;\n }\n\n const sessionId = event.sessionId;\n let lines = buffers.get(sessionId);\n if (!lines) {\n lines = [];\n buffers.set(sessionId, lines);\n }\n lines.push(`${JSON.stringify(entry)}\\n`);\n\n // Flush when buffer is full\n if (lines.length >= flushSize) {\n await flushSession(sessionId);\n }\n\n // Start periodic flush timer if not already running\n if (flushTimer === undefined && flushIntervalMs > 0) {\n flushTimer = setInterval(() => {\n void flushAll();\n }, flushIntervalMs);\n // Unref so it doesn't keep the process alive\n if (typeof flushTimer === \"object\" && \"unref\" in flushTimer) {\n flushTimer.unref();\n }\n }\n\n return { decision: \"async\", asyncTimeout: 5_000 };\n },\n };\n}\n","import type { Middleware } from \"@/types\";\n\n/**\n * Budget guard middleware.\n *\n * Checks daily cost against budget cap on every tool call.\n * If over budget, blocks with reason \"Daily budget exceeded\".\n * Uses the middleware context's `get(\"costToday\")` and `get(\"budgetCapUsd\")`.\n */\nexport function budgetGuard(): Middleware {\n return {\n name: \"budget-guard\",\n on: \"PreToolUse\",\n async handler(_event, context) {\n const costToday = context.get(\"costToday\");\n const budgetCapUsd = context.get(\"budgetCapUsd\");\n\n if (costToday !== undefined && budgetCapUsd !== undefined && costToday >= budgetCapUsd) {\n return {\n decision: \"block\",\n reason: \"Daily budget exceeded\",\n };\n }\n\n return { decision: \"pass\" };\n },\n };\n}\n","import type {\n HookCallback,\n HookCallbackMatcher,\n HookInput,\n HookJSONOutput,\n HookEvent as SDKHookEvent,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport type {\n HookEvent,\n Middleware,\n MiddlewareContext,\n MiddlewareEvent,\n MiddlewareResult,\n} from \"@/types\";\n\nexport interface MiddlewareChain {\n execute(event: MiddlewareEvent, context: MiddlewareContext): Promise<MiddlewareResult>;\n}\n\nfunction matchesTool(match: string | string[] | undefined, toolName: string | undefined): boolean {\n if (match === undefined) return true;\n if (toolName === undefined) return false;\n if (Array.isArray(match)) return match.includes(toolName);\n return match === toolName;\n}\n\nexport function buildMiddlewareChain(middleware: Middleware[]): MiddlewareChain {\n return {\n async execute(event: MiddlewareEvent, context: MiddlewareContext): Promise<MiddlewareResult> {\n let lastAsync: MiddlewareResult | undefined;\n\n for (const mw of middleware) {\n // Hook event matching\n if (mw.on !== event.hookEvent) continue;\n\n // Tool name matching\n if (!matchesTool(mw.match, event.toolName)) continue;\n\n const result = await mw.handler(event, context);\n\n switch (result.decision) {\n case \"block\":\n return result;\n case \"async\":\n lastAsync = result;\n break;\n case \"pass\":\n break;\n }\n }\n\n return lastAsync ?? { decision: \"pass\" };\n },\n };\n}\n\n/**\n * SDK hooks type — maps hook event names to callback matchers.\n */\nexport type SDKHooks = Partial<Record<SDKHookEvent, HookCallbackMatcher[]>>;\n\n/**\n * Convert a middleware chain to Agent SDK hooks format.\n *\n * Creates one HookCallbackMatcher per supported event (PreToolUse, PostToolUse, Notification).\n * The matcher delegates to the chain's execute method, translating SDK input to our\n * MiddlewareEvent format.\n */\nexport function buildSDKHooks(\n chain: MiddlewareChain,\n context: MiddlewareContext,\n middleware: Middleware[] = [],\n): SDKHooks {\n function makeCallback(hookEvent: HookEvent): HookCallback {\n return async (input: HookInput): Promise<HookJSONOutput> => {\n const event: MiddlewareEvent = {\n hookEvent,\n sessionId: input.session_id,\n toolName: \"tool_name\" in input ? (input.tool_name as string) : undefined,\n input: \"tool_input\" in input ? (input.tool_input as Record<string, unknown>) : undefined,\n output: \"tool_response\" in input ? String(input.tool_response) : undefined,\n message: \"message\" in input ? (input.message as string) : undefined,\n };\n\n const result = await chain.execute(event, context);\n\n switch (result.decision) {\n case \"block\":\n return { decision: \"block\", reason: result.reason };\n case \"async\":\n return { async: true, asyncTimeout: result.asyncTimeout };\n case \"pass\":\n return {};\n }\n };\n }\n\n // Only register hooks for events that have at least one middleware listener\n const usedEvents = new Set(middleware.map((mw) => mw.on));\n const allEvents: HookEvent[] = [\"PreToolUse\", \"PostToolUse\", \"Notification\"];\n\n const hooks: SDKHooks = {};\n for (const hookEvent of allEvents) {\n // When no middleware list is provided, register all events (backward-compatible)\n if (middleware.length === 0 || usedEvents.has(hookEvent)) {\n hooks[hookEvent] = [{ hooks: [makeCallback(hookEvent)] }];\n }\n }\n\n return hooks;\n}\n","import type { Middleware } from \"@/types\";\n\n/**\n * Loop detection middleware.\n *\n * Tracks Bash commands per session. If the same command appears\n * `threshold` times, blocks it and tells the agent to escalate.\n *\n * Call `cleanup(sessionId)` when a session ends to prevent memory leaks.\n */\nexport interface LoopDetectionMiddleware extends Middleware {\n cleanup: (sessionId: string) => void;\n}\n\nexport function loopDetection(options: {\n threshold: number;\n scope?: \"session\";\n}): LoopDetectionMiddleware {\n const { threshold } = options;\n const commandHistory = new Map<string, Map<string, number>>();\n\n return {\n name: \"loop-detection\",\n on: \"PreToolUse\",\n match: \"Bash\",\n cleanup(sessionId: string) {\n commandHistory.delete(sessionId);\n },\n async handler(event) {\n const sessionId = event.sessionId;\n const command =\n event.input && typeof event.input === \"object\" && \"command\" in event.input\n ? String(event.input.command)\n : \"\";\n\n if (!command) return { decision: \"pass\" };\n\n if (!commandHistory.has(sessionId)) {\n commandHistory.set(sessionId, new Map());\n }\n\n const sessionHistory = commandHistory.get(sessionId) ?? new Map<string, number>();\n const count = (sessionHistory.get(command) ?? 0) + 1;\n sessionHistory.set(command, count);\n\n if (count >= threshold) {\n return {\n decision: \"block\",\n reason: `Loop detected: you have run this exact command ${String(count)} times. STOP and escalate — do not retry the same approach.`,\n };\n }\n\n return { decision: \"pass\" };\n },\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Semaphore } from \"@/concurrency/semaphore\";\nimport type { McpServerConfig, NeoConfig, RepoConfig } from \"@/config\";\nimport { CostJournal } from \"@/cost/journal\";\nimport { NeoEventEmitter } from \"@/events\";\nimport { EventJournal } from \"@/events/journal\";\nimport { WebhookDispatcher } from \"@/events/webhook\";\nimport { createSessionClone, removeSessionClone } from \"@/isolation/clone\";\nimport { pushSessionBranch } from \"@/isolation/git\";\nimport { auditLog } from \"@/middleware/audit-log\";\nimport { budgetGuard } from \"@/middleware/budget-guard\";\nimport { loopDetection } from \"@/middleware/loop-detection\";\nimport { RunStore } from \"@/orchestrator/run-store\";\nimport { getJournalsDir, getSupervisorsDir } from \"@/paths\";\nimport { SessionExecutor } from \"@/runner/session-executor\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport { formatMemoriesForPrompt, MemoryStore } from \"@/supervisor/memory/index.js\";\nimport type {\n ActiveSession,\n CostEntry,\n DispatchInput,\n Middleware,\n NeoEvent,\n OrchestratorStatus,\n PersistedRun,\n ResolvedAgent,\n StepResult,\n TaskResult,\n} from \"@/types\";\n\n// ─── Constants ─────────────────────────────────────────\n\nconst MAX_PROMPT_SIZE = 100 * 1024; // 100 KB\nconst MAX_METADATA_DEPTH = 5;\nconst SHUTDOWN_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nconst textEncoder = new TextEncoder();\n\n// ─── Options ───────────────────────────────────────────\n\nexport interface OrchestratorOptions {\n middleware?: Middleware[] | undefined;\n journalDir?: string | undefined;\n /** Skip orphan recovery on start — workers should set this to true to avoid false orphan detection on concurrent launches. */\n skipOrphanRecovery?: boolean | undefined;\n}\n\n// ─── Internal dispatch context ─────────────────────────\n\ninterface DispatchContext {\n input: DispatchInput;\n runId: string;\n sessionId: string;\n startedAt: number;\n agent: ResolvedAgent;\n repoConfig: RepoConfig;\n activeSession: ActiveSession;\n}\n\n// ─── Idempotency ───────────────────────────────────────\n\ninterface IdempotencyEntry {\n result: TaskResult;\n expiresAt: number;\n}\n\n// ─── Orchestrator ──────────────────────────────────────\n\nexport class Orchestrator extends NeoEventEmitter {\n private readonly config: NeoConfig;\n private readonly semaphore: Semaphore;\n private readonly userMiddleware: Middleware[];\n private readonly registeredAgents = new Map<string, ResolvedAgent>();\n private readonly _activeSessions = new Map<string, ActiveSession>();\n private readonly idempotencyCache = new Map<string, IdempotencyEntry>();\n private readonly abortControllers = new Map<string, AbortController>();\n private readonly repoIndex = new Map<string, RepoConfig>();\n private readonly runStore = new RunStore();\n private readonly journalDir: string;\n private costJournal: CostJournal | null = null;\n private eventJournal: EventJournal | null = null;\n private webhookDispatcher: WebhookDispatcher | null = null;\n private memoryStore: MemoryStore | null = null;\n private _paused = false;\n private _costToday = 0;\n private _startedAt = 0;\n private _drainResolve: (() => void) | null = null;\n\n private readonly skipOrphanRecovery: boolean;\n\n constructor(config: NeoConfig, options: OrchestratorOptions = {}) {\n super();\n this.config = config;\n this.userMiddleware = options.middleware ?? [];\n this.journalDir = options.journalDir ?? getJournalsDir();\n this.skipOrphanRecovery = options.skipOrphanRecovery ?? false;\n for (const repo of config.repos) {\n const resolvedPath = path.resolve(repo.path);\n const normalizedRepo = { ...repo, path: resolvedPath };\n this.repoIndex.set(resolvedPath, normalizedRepo);\n }\n this.semaphore = new Semaphore(\n {\n maxSessions: config.concurrency.maxSessions,\n maxPerRepo: config.concurrency.maxPerRepo,\n queueMax: config.concurrency.queueMax,\n },\n {\n onEnqueue: (sessionId, repo, position) => {\n this.emit({\n type: \"queue:enqueue\",\n sessionId,\n repo,\n position,\n timestamp: new Date().toISOString(),\n });\n },\n onDequeue: (sessionId, repo, waitedMs) => {\n this.emit({\n type: \"queue:dequeue\",\n sessionId,\n repo,\n waitedMs,\n timestamp: new Date().toISOString(),\n });\n },\n },\n );\n }\n\n // ─── Registration ──────────────────────────────────────\n\n registerAgent(agent: ResolvedAgent): void {\n this.registeredAgents.set(agent.name, agent);\n }\n\n // ─── Dispatch ──────────────────────────────────────────\n\n async dispatch(input: DispatchInput): Promise<TaskResult> {\n const idempotencyKey = this.preDispatchChecks(input);\n const ctx = this.buildDispatchContext(input);\n\n // Acquire semaphore (blocks if at capacity)\n const abortController = new AbortController();\n this.abortControllers.set(ctx.sessionId, abortController);\n await this.semaphore.acquire(\n input.repo,\n ctx.sessionId,\n input.priority ?? \"medium\",\n abortController.signal,\n );\n ctx.activeSession.status = \"running\";\n\n const stepResult = await this.executeStep(ctx);\n return this.finalizeDispatch(ctx, stepResult, idempotencyKey);\n }\n\n // ─── Control ───────────────────────────────────────────\n\n pause(): void {\n this._paused = true;\n }\n\n resume(): void {\n this._paused = false;\n }\n\n async kill(sessionId: string): Promise<void> {\n const controller = this.abortControllers.get(sessionId);\n if (controller) {\n controller.abort(new Error(\"Session killed\"));\n }\n\n this._activeSessions.delete(sessionId);\n this.abortControllers.delete(sessionId);\n this.semaphore.release(sessionId);\n }\n\n async drain(): Promise<void> {\n this._paused = true;\n if (this._activeSessions.size === 0) return;\n return new Promise<void>((resolve) => {\n this._drainResolve = resolve;\n });\n }\n\n // ─── Getters ───────────────────────────────────────────\n\n get status(): OrchestratorStatus {\n return {\n paused: this._paused,\n activeSessions: [...this._activeSessions.values()],\n queueDepth: this.semaphore.queueDepth(),\n costToday: this._costToday,\n budgetCapUsd: this.config.budget.dailyCapUsd,\n budgetRemainingPct: this.computeBudgetRemainingPct(),\n uptime: this._startedAt > 0 ? Date.now() - this._startedAt : 0,\n };\n }\n\n get activeSessions(): ActiveSession[] {\n return [...this._activeSessions.values()];\n }\n\n // ─── Lifecycle ─────────────────────────────────────────\n\n async start(): Promise<void> {\n this._startedAt = Date.now();\n\n // Initialize journals\n this.costJournal = new CostJournal({ dir: this.journalDir });\n this.eventJournal = new EventJournal({ dir: this.journalDir });\n\n // Initialize webhook dispatcher with configured webhooks + auto-discovered supervisor webhooks\n const supervisorWebhooks = await this.discoverSupervisorWebhooks();\n\n const allWebhooks = [...this.config.webhooks, ...supervisorWebhooks];\n if (allWebhooks.length > 0) {\n this.webhookDispatcher = new WebhookDispatcher(allWebhooks);\n }\n\n // Log supervisor webhook discovery for debugging connectivity\n if (supervisorWebhooks.length > 0) {\n // biome-ignore lint/suspicious/noConsole: Intentional logging for webhook discovery\n console.log(\n `[neo] Discovered ${supervisorWebhooks.length} supervisor webhook(s): ${supervisorWebhooks.map((w) => w.url).join(\", \")}`,\n );\n }\n\n // Restore today's cost from journal\n this._costToday = await this.costJournal.getDayTotal();\n\n if (!this.skipOrphanRecovery) {\n await this.recoverOrphanedRuns();\n }\n\n await mkdir(this.config.sessions.dir, { recursive: true });\n }\n\n async shutdown(): Promise<void> {\n this._paused = true;\n\n if (this._activeSessions.size > 0) {\n await Promise.race([\n this.drain(),\n new Promise<void>((resolve) => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),\n ]);\n }\n\n for (const mw of this.userMiddleware) {\n if (\"flush\" in mw && typeof mw.flush === \"function\") {\n await (mw as { flush: () => Promise<void> }).flush();\n }\n if (\"cleanup\" in mw && typeof mw.cleanup === \"function\") {\n for (const session of this._activeSessions.values()) {\n (mw as { cleanup: (id: string) => void }).cleanup(session.sessionId);\n }\n }\n }\n\n this.emit({\n type: \"orchestrator:shutdown\",\n timestamp: new Date().toISOString(),\n });\n\n // Flush pending webhook deliveries — ensures terminal events\n // (session:complete/fail) reach the supervisor before process exits\n if (this.webhookDispatcher) {\n await this.webhookDispatcher.flush();\n }\n }\n\n // ─── Emit override (journal events) ───────────────────\n\n override emit(event: NeoEvent): void {\n super.emit(event);\n // Fire-and-forget event journal append\n if (this.eventJournal) {\n this.eventJournal.append(event).catch(() => {});\n }\n // Fire-and-forget webhook dispatch\n if (this.webhookDispatcher) {\n this.webhookDispatcher.dispatch(event);\n }\n }\n\n // ─── Static middleware factories ───────────────────────\n\n static middleware = {\n loopDetection: (options: { threshold: number; scope?: \"session\" }) => loopDetection(options),\n auditLog: (options: {\n dir: string;\n includeInput?: boolean;\n includeOutput?: boolean;\n flushIntervalMs?: number;\n flushSize?: number;\n }) => auditLog(options),\n budgetGuard: () => budgetGuard(),\n };\n\n // ─── Private: Dispatch phases ──────────────────────────\n\n private preDispatchChecks(input: DispatchInput): string | null {\n this.validateInput(input);\n\n const idempotencyKey = this.computeIdempotencyKey(input);\n if (idempotencyKey) {\n this.evictExpiredIdempotencyEntries();\n const cached = this.idempotencyCache.get(idempotencyKey);\n if (cached && cached.expiresAt > Date.now()) {\n throw new Error(\n `Duplicate dispatch rejected: runId '${input.runId ?? \"auto-generated\"}' already exists. Each dispatch must use a unique runId.`,\n );\n }\n }\n\n if (this._paused) {\n throw new Error(\n \"Dispatch rejected: orchestrator is paused. Call orchestrator.resume() before dispatching.\",\n );\n }\n\n return idempotencyKey;\n }\n\n private buildDispatchContext(input: DispatchInput): DispatchContext {\n const runId = input.runId ?? randomUUID();\n const sessionId = randomUUID();\n const agent = this.registeredAgents.get(input.agent);\n if (!agent) {\n const available = [...this.registeredAgents.keys()].join(\", \") || \"none\";\n throw new Error(\n `Agent \"${input.agent}\" not found. Available agents: ${available}. Register the agent first.`,\n );\n }\n const repoConfig = this.resolveRepo(input.repo);\n\n const activeSession: ActiveSession = {\n sessionId,\n runId,\n step: \"execute\",\n agent: agent.name,\n repo: input.repo,\n status: \"queued\",\n startedAt: new Date().toISOString(),\n };\n this._activeSessions.set(sessionId, activeSession);\n\n return {\n input,\n runId,\n sessionId,\n startedAt: Date.now(),\n agent,\n repoConfig,\n activeSession,\n };\n }\n\n private async executeStep(ctx: DispatchContext): Promise<StepResult> {\n const { input, runId, sessionId, startedAt, agent, repoConfig, activeSession } = ctx;\n let sessionPath: string | undefined;\n\n // Persist initial running state so `neo runs` shows this run immediately\n await this.persistRun({\n version: 1,\n runId,\n agent: agent.name,\n repo: input.repo,\n prompt: input.prompt,\n pid: process.pid,\n status: \"running\",\n steps: {},\n createdAt: activeSession.startedAt,\n updatedAt: new Date().toISOString(),\n metadata: input.metadata,\n });\n\n try {\n // Create isolated clone for ALL agents.\n // Uses the explicit branch if provided, otherwise falls back to the base branch.\n const branchName = (input.branch as string) || repoConfig.defaultBranch;\n const sessionDir = path.join(this.config.sessions.dir, runId);\n const info = await createSessionClone({\n repoPath: input.repo,\n branch: branchName,\n baseBranch: repoConfig.defaultBranch,\n sessionDir,\n });\n sessionPath = info.path;\n activeSession.sessionPath = sessionPath;\n\n const stepResult = await this.runAgentSession(ctx, sessionPath);\n this.emitCostEvents(sessionId, stepResult.costUsd, ctx);\n this.emitSessionComplete(ctx, stepResult);\n return stepResult;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitSessionFail(ctx, errorMsg);\n\n const failResult: StepResult = {\n status: \"failure\",\n sessionId,\n costUsd: 0,\n durationMs: Date.now() - startedAt,\n agent: agent.name,\n startedAt: activeSession.startedAt,\n completedAt: new Date().toISOString(),\n error: errorMsg,\n attempt: 1,\n };\n\n // Write episode to memory store\n try {\n const store = this.getMemoryStore();\n await store.write({\n type: \"episode\",\n scope: input.repo,\n content: `Run ${runId.slice(0, 8)} (${agent.name}): failed${failResult.error ? ` — ${failResult.error.slice(0, 150)}` : \"\"}`,\n source: agent.name,\n outcome: \"failure\",\n runId,\n });\n } catch {\n // Best-effort — don't fail the run if memory write fails\n }\n\n return failResult;\n } finally {\n // Auto-commit, push, and cleanup session clone\n if (sessionPath) {\n await this.finalizeSession(sessionPath, ctx);\n }\n\n this.semaphore.release(sessionId);\n this._activeSessions.delete(sessionId);\n this.abortControllers.delete(sessionId);\n\n if (this._activeSessions.size === 0 && this._drainResolve) {\n this._drainResolve();\n this._drainResolve = null;\n }\n }\n }\n\n /**\n * Push the branch (writable only), then remove the session clone.\n * Runs in `finally` so it executes on both success and failure.\n */\n private async finalizeSession(sessionPath: string, ctx: DispatchContext): Promise<void> {\n // Only push for writable agents — readonly agents have no changes to push\n if (ctx.agent.sandbox === \"writable\") {\n const branch = ctx.input.branch as string;\n const remote = ctx.repoConfig.pushRemote ?? \"origin\";\n try {\n await pushSessionBranch(sessionPath, branch, remote).catch(() => {\n // Push may fail (no remote, auth, etc.) — not critical\n });\n } catch {\n // Best-effort — don't let finalization errors mask the real result\n }\n }\n\n try {\n await removeSessionClone(sessionPath);\n } catch {\n // Session cleanup is best-effort\n }\n }\n\n private async runAgentSession(\n ctx: DispatchContext,\n sessionPath: string | undefined,\n ): Promise<StepResult> {\n const { input, runId, sessionId, agent, repoConfig, activeSession } = ctx;\n\n this.emit({\n type: \"session:start\",\n sessionId,\n runId,\n step: \"execute\",\n agent: agent.name,\n repo: input.repo,\n metadata: input.metadata,\n timestamp: new Date().toISOString(),\n });\n\n // Create SessionExecutor with config and context value getter\n const executor = new SessionExecutor(\n {\n initTimeoutMs: this.config.sessions.initTimeoutMs,\n maxDurationMs: this.config.sessions.maxDurationMs,\n maxRetries: this.config.recovery.maxRetries,\n backoffBaseMs: this.config.recovery.backoffBaseMs,\n },\n (key: string) => {\n if (key === \"costToday\") return this._costToday;\n if (key === \"budgetCapUsd\") return this.config.budget.dailyCapUsd;\n return undefined;\n },\n );\n\n // Build execution input\n const strategy = input.gitStrategy ?? repoConfig.gitStrategy ?? \"branch\";\n const mcpServers = this.resolveMcpServers(agent);\n const memoryContext = this.loadMemoryContext(input.repo);\n\n const result = await executor.execute(\n {\n runId,\n sessionId,\n agent,\n repoConfig,\n repoPath: input.repo,\n prompt: input.prompt,\n branch: input.branch,\n gitStrategy: strategy,\n sessionPath,\n metadata: input.metadata,\n startedAt: activeSession.startedAt,\n },\n {\n middleware: this.userMiddleware,\n mcpServers,\n memoryContext,\n onAttempt: (attempt, strategy) => {\n if (attempt > 1) {\n this.emit({\n type: \"session:fail\",\n sessionId,\n runId,\n error: `Retrying with strategy: ${strategy}`,\n attempt: attempt - 1,\n maxRetries: this.config.recovery.maxRetries,\n willRetry: true,\n metadata: input.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n },\n },\n );\n\n // Write episode to memory store\n try {\n const store = this.getMemoryStore();\n const isSuccess = result.status === \"success\";\n await store.write({\n type: \"episode\",\n scope: input.repo,\n content: `Run ${runId.slice(0, 8)} (${agent.name}): ${isSuccess ? \"completed\" : \"failed\"}${result.error ? ` — ${result.error.slice(0, 150)}` : \"\"}`,\n source: agent.name,\n outcome: isSuccess ? \"success\" : \"failure\",\n runId,\n });\n } catch {\n // Best-effort — don't fail the run if memory write fails\n }\n\n return result;\n }\n\n private async finalizeDispatch(\n ctx: DispatchContext,\n stepResult: StepResult,\n idempotencyKey: string | null,\n ): Promise<TaskResult> {\n const { input, runId, agent, activeSession } = ctx;\n\n const taskResult: TaskResult = {\n runId,\n agent: agent.name,\n repo: input.repo,\n status: stepResult.status === \"success\" ? \"success\" : \"failure\",\n steps: { execute: stepResult },\n branch:\n stepResult.status === \"success\" && activeSession.sessionPath ? input.branch : undefined,\n costUsd: stepResult.costUsd,\n durationMs: Date.now() - ctx.startedAt,\n timestamp: new Date().toISOString(),\n metadata: input.metadata,\n };\n\n if (stepResult.prUrl) {\n taskResult.prUrl = stepResult.prUrl;\n }\n if (stepResult.prNumber !== undefined) {\n taskResult.prNumber = stepResult.prNumber;\n }\n\n await this.persistRun({\n version: 1,\n runId,\n agent: agent.name,\n repo: input.repo,\n prompt: input.prompt,\n pid: process.pid,\n branch: taskResult.branch,\n status: taskResult.status === \"success\" ? \"completed\" : \"failed\",\n steps: taskResult.steps,\n createdAt: activeSession.startedAt,\n updatedAt: new Date().toISOString(),\n metadata: input.metadata,\n });\n\n if (idempotencyKey) {\n const ttl = this.config.idempotency?.ttlMs ?? 3_600_000;\n this.idempotencyCache.set(idempotencyKey, {\n result: taskResult,\n expiresAt: Date.now() + ttl,\n });\n }\n\n return taskResult;\n }\n\n // ─── Private: Memory injection ──────────────────────────\n\n private getMemoryStore(): MemoryStore {\n if (!this.memoryStore) {\n const supervisorDir = path.join(getSupervisorsDir(), \"supervisor\");\n this.memoryStore = new MemoryStore(path.join(supervisorDir, \"memory.sqlite\"));\n }\n return this.memoryStore;\n }\n\n private loadMemoryContext(repoPath: string): string | undefined {\n try {\n const store = this.getMemoryStore();\n const memories = store.query({\n scope: repoPath,\n types: [\"fact\", \"procedure\", \"feedback\"],\n limit: 25,\n sortBy: \"relevance\",\n });\n if (memories.length === 0) return undefined;\n store.markAccessed(memories.map((m) => m.id));\n return formatMemoriesForPrompt(memories);\n } catch {\n return undefined;\n }\n }\n\n // ─── Private: Event helpers ────────────────────────────\n\n private emitCostEvents(sessionId: string, sessionCost: number, ctx: DispatchContext): void {\n this._costToday += sessionCost;\n\n // Persist cost entry to journal (fire-and-forget)\n if (this.costJournal) {\n const costEntry: CostEntry = {\n timestamp: new Date().toISOString(),\n runId: ctx.runId,\n step: \"execute\",\n sessionId,\n agent: ctx.agent.name,\n costUsd: sessionCost,\n models: {},\n durationMs: Date.now() - ctx.startedAt,\n repo: ctx.input.repo,\n };\n this.costJournal.append(costEntry).catch(() => {});\n }\n\n this.emit({\n type: \"cost:update\",\n sessionId,\n sessionCost,\n todayTotal: this._costToday,\n budgetRemainingPct: this.computeBudgetRemainingPct(),\n timestamp: new Date().toISOString(),\n });\n\n const utilizationPct = (this._costToday / this.config.budget.dailyCapUsd) * 100;\n if (utilizationPct >= this.config.budget.alertThresholdPct) {\n this.emit({\n type: \"budget:alert\",\n todayTotal: this._costToday,\n capUsd: this.config.budget.dailyCapUsd,\n utilizationPct,\n timestamp: new Date().toISOString(),\n });\n }\n }\n\n private emitSessionComplete(ctx: DispatchContext, stepResult: StepResult): void {\n this.emit({\n type: \"session:complete\",\n sessionId: ctx.sessionId,\n runId: ctx.runId,\n status: \"success\",\n costUsd: stepResult.costUsd,\n durationMs: stepResult.durationMs,\n output: stepResult.output,\n metadata: ctx.input.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n\n private emitSessionFail(ctx: DispatchContext, errorMsg: string): void {\n this.emit({\n type: \"session:fail\",\n sessionId: ctx.sessionId,\n runId: ctx.runId,\n error: errorMsg,\n attempt: 1,\n maxRetries: this.config.recovery.maxRetries,\n willRetry: false,\n metadata: ctx.input.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n\n // ─── Private: Input validation ─────────────────────────\n\n private validateInput(input: DispatchInput): void {\n if (!input.prompt || input.prompt.trim().length === 0) {\n throw new Error(\"Validation error: prompt must be a non-empty string\");\n }\n if (textEncoder.encode(input.prompt).length > MAX_PROMPT_SIZE) {\n throw new Error(\n `Validation error: prompt exceeds maximum size of ${String(MAX_PROMPT_SIZE)} bytes`,\n );\n }\n\n if (!existsSync(input.repo)) {\n throw new Error(`Validation error: repo path does not exist: ${input.repo}`);\n }\n\n if (!this.registeredAgents.has(input.agent)) {\n throw new Error(`Validation error: agent \"${input.agent}\" not found in registry`);\n }\n\n if (input.metadata !== undefined) {\n if (!isPlainObject(input.metadata)) {\n throw new Error(\"Validation error: metadata must be a plain object\");\n }\n if (objectDepth(input.metadata) > MAX_METADATA_DEPTH) {\n throw new Error(\n `Validation error: metadata exceeds maximum nesting depth of ${String(MAX_METADATA_DEPTH)}`,\n );\n }\n }\n\n const resumeOptions = [input.step, input.from, input.retry].filter(Boolean);\n if (resumeOptions.length > 1) {\n throw new Error(\"Validation error: step, from, and retry are mutually exclusive\");\n }\n }\n\n // ─── Private: Helpers ──────────────────────────────────\n\n private evictExpiredIdempotencyEntries(): void {\n const now = Date.now();\n for (const [key, entry] of this.idempotencyCache) {\n if (entry.expiresAt <= now) {\n this.idempotencyCache.delete(key);\n }\n }\n }\n\n private computeIdempotencyKey(input: DispatchInput): string | null {\n const idempotency = this.config.idempotency;\n if (!idempotency?.enabled) return null;\n\n const key = idempotency.key ?? \"metadata\";\n if (key === \"prompt\") {\n return `${input.agent}:${input.repo}:${input.prompt}`;\n }\n return `${input.agent}:${input.repo}:${JSON.stringify(input.metadata ?? {})}`;\n }\n\n private resolveRepo(repoPath: string): RepoConfig {\n const repo = this.repoIndex.get(path.resolve(repoPath));\n if (repo) return repo;\n return {\n path: repoPath,\n defaultBranch: \"main\",\n branchPrefix: \"feat\",\n pushRemote: \"origin\",\n gitStrategy: \"branch\",\n };\n }\n\n private computeBudgetRemainingPct(): number {\n const cap = this.config.budget.dailyCapUsd;\n if (cap <= 0) return 0;\n return Math.max(0, ((cap - this._costToday) / cap) * 100);\n }\n\n // ─── Private: MCP server resolution ────────────────────\n\n private resolveMcpServers(agent: ResolvedAgent): Record<string, McpServerConfig> | undefined {\n const configServers = this.config.mcpServers;\n if (!configServers) return undefined;\n\n // Collect unique server names from agent definition\n const names = agent.definition.mcpServers;\n if (!names || names.length === 0) return undefined;\n\n const resolved: Record<string, McpServerConfig> = {};\n for (const name of names) {\n const serverConfig = configServers[name];\n if (serverConfig) {\n resolved[name] = serverConfig;\n }\n }\n\n return Object.keys(resolved).length > 0 ? resolved : undefined;\n }\n\n // ─── Private: Supervisor discovery ─────────────────────\n\n /** Discover running supervisor daemons and return webhook configs for their endpoints. */\n private async discoverSupervisorWebhooks(): Promise<NeoConfig[\"webhooks\"]> {\n const { readdir } = await import(\"node:fs/promises\");\n const supervisorsDir = getSupervisorsDir();\n if (!existsSync(supervisorsDir)) return [];\n\n const webhooks: NeoConfig[\"webhooks\"] = [];\n\n try {\n const entries = await readdir(supervisorsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n try {\n const statePath = path.join(supervisorsDir, entry.name, \"state.json\");\n const raw = await readFile(statePath, \"utf-8\");\n const state = JSON.parse(raw) as { status?: string; port?: number; pid?: number };\n\n if (state.status !== \"running\" || !state.port) continue;\n if (state.pid && !isProcessAlive(state.pid)) continue;\n\n webhooks.push({\n url: `http://localhost:${String(state.port)}/webhook`,\n events: [\"session:complete\", \"session:fail\", \"budget:alert\"],\n secret: this.config.supervisor.secret,\n timeoutMs: 5000,\n });\n } catch {\n // State file missing or corrupt — skip\n }\n }\n } catch {\n // Supervisors dir unreadable — skip\n }\n\n return webhooks;\n }\n\n // ─── Private: Run persistence ──────────────────────────\n\n private async persistRun(run: PersistedRun): Promise<void> {\n await this.runStore.persistRun(run);\n }\n\n private async recoverOrphanedRuns(): Promise<void> {\n const orphanedRuns = await this.runStore.recoverOrphanedRuns();\n\n // Emit session:fail for each orphaned run so the supervisor learns about them\n for (const run of orphanedRuns) {\n this.emit({\n type: \"session:fail\",\n sessionId: run.runId,\n runId: run.runId,\n error: \"Orphaned run: process died without completing\",\n attempt: 1,\n maxRetries: this.config.recovery.maxRetries,\n willRetry: false,\n metadata: run.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n }\n}\n\n// ─── Utility functions ─────────────────────────────────\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction objectDepth(obj: unknown, current = 0): number {\n if (!isPlainObject(obj)) return current;\n let max = current + 1;\n for (const value of Object.values(obj)) {\n const depth = objectDepth(value, current + 1);\n if (depth > max) max = depth;\n }\n return max;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getRepoRunsDir, getRunsDir, toRepoSlug } from \"@/paths\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport type { PersistedRun } from \"@/types\";\n\nexport interface RunStoreOptions {\n runsDir?: string | undefined;\n}\n\n/** Grace period before a run without PID can be considered orphaned (ms). */\nconst ORPHAN_GRACE_PERIOD_MS = 30_000;\n\n/**\n * Handles persistence and recovery of workflow runs.\n *\n * Runs are stored as JSON files in: ~/.neo/runs/<repo-slug>/<runId>.json\n * This enables cross-process resume and status queries via `neo runs`.\n */\nexport class RunStore {\n private readonly runsDir: string;\n private readonly createdDirs = new Set<string>();\n\n constructor(options: RunStoreOptions = {}) {\n this.runsDir = options.runsDir ?? getRunsDir();\n }\n\n /**\n * Persist a run to disk. Creates the repo subdirectory if needed.\n * Fails silently — run persistence is non-critical.\n */\n async persistRun(run: PersistedRun): Promise<void> {\n try {\n const slug = toRepoSlug({ path: run.repo });\n const repoDir = getRepoRunsDir(slug);\n if (!this.createdDirs.has(repoDir)) {\n await mkdir(repoDir, { recursive: true });\n this.createdDirs.add(repoDir);\n }\n const filePath = path.join(repoDir, `${run.runId}.json`);\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Non-critical — don't fail the dispatch if persistence fails\n }\n }\n\n /**\n * Find all runs that were left in \"running\" state but whose process died.\n * Returns them so the caller can emit failure events and update status.\n */\n async recoverOrphanedRuns(): Promise<PersistedRun[]> {\n if (!existsSync(this.runsDir)) return [];\n\n const orphaned: PersistedRun[] = [];\n\n try {\n const jsonFiles = await this.collectRunFiles();\n for (const filePath of jsonFiles) {\n const run = await this.recoverRunIfOrphaned(filePath);\n if (run) orphaned.push(run);\n }\n } catch {\n // Non-critical\n }\n\n return orphaned;\n }\n\n /**\n * Collect all .json run files from the runs directory tree.\n * Searches both top-level and repo subdirectories.\n */\n async collectRunFiles(): Promise<string[]> {\n const entries = await readdir(this.runsDir, { withFileTypes: true });\n const jsonFiles: string[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const subDir = path.join(this.runsDir, entry.name);\n const subFiles = await readdir(subDir);\n for (const f of subFiles) {\n if (f.endsWith(\".json\")) jsonFiles.push(path.join(subDir, f));\n }\n } else if (entry.name.endsWith(\".json\")) {\n jsonFiles.push(path.join(this.runsDir, entry.name));\n }\n }\n\n return jsonFiles;\n }\n\n /**\n * Check if a run file represents an orphaned run.\n * If so, update its status to \"failed\" and return it.\n */\n private async recoverRunIfOrphaned(filePath: string): Promise<PersistedRun | null> {\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n\n if (run.status !== \"running\") return null;\n\n // Never mark our own process's runs as orphaned\n if (run.pid && run.pid === process.pid) return null;\n\n // If the run has a PID and the process is still alive, skip it\n if (run.pid && isProcessAlive(run.pid)) return null;\n\n // Don't mark recently created runs as orphaned — the worker process\n // may not have written its PID yet (race condition on concurrent launches)\n const ageMs = Date.now() - new Date(run.createdAt).getTime();\n if (ageMs < ORPHAN_GRACE_PERIOD_MS) return null;\n\n run.status = \"failed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n\n return run;\n }\n}\n","/**\n * Checks whether a process with the given PID is currently running.\n *\n * Uses the POSIX signal 0 trick: `process.kill(pid, 0)` doesn't actually\n * send a signal but checks whether the process exists and the current\n * process has permission to signal it. If the process doesn't exist,\n * an ESRCH error is thrown.\n *\n * @param pid - The process ID to check. Must be a positive integer.\n * @returns `true` if the process is alive and accessible, `false` otherwise.\n *\n * @example\n * ```ts\n * import { isProcessAlive } from \"@/shared/process\";\n *\n * // Check if current process is alive (always true)\n * isProcessAlive(process.pid); // => true\n *\n * // Check if a non-existent process is alive\n * isProcessAlive(999999); // => false\n * ```\n */\nexport function isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) {\n return false;\n }\n\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n // EPERM means the process exists but we lack permission to signal it\n if (error instanceof Error && \"code\" in error && error.code === \"EPERM\") {\n return true;\n }\n // ESRCH means the process does not exist\n return false;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { GitStrategy } from \"@/config\";\nimport type { ResolvedAgent } from \"@/types\";\n\n// ─── Constants ─────────────────────────────────────────\n\nconst INSTRUCTIONS_PATH = \".neo/INSTRUCTIONS.md\";\n\n// ─── Repo instructions loader ──────────────────────────\n\nexport async function loadRepoInstructions(repoPath: string): Promise<string | undefined> {\n const filePath = path.join(repoPath, INSTRUCTIONS_PATH);\n try {\n return await readFile(filePath, \"utf-8\");\n } catch {\n return undefined;\n }\n}\n\n// ─── Git strategy prompt builder ───────────────────────\n\nexport function buildGitStrategyInstructions(\n strategy: GitStrategy,\n agent: ResolvedAgent,\n branch: string,\n baseBranch: string,\n remote: string,\n metadata?: Record<string, unknown>,\n): string | null {\n const prNumber = metadata?.prNumber as number | undefined;\n\n // Readonly agents: only inject PR comment instruction if a PR exists\n if (agent.sandbox !== \"writable\") {\n if (prNumber) {\n return `## Pull Request\\n\\nPR #${String(prNumber)} is open for this task. After your review, leave your findings as a comment: \\`gh pr comment ${String(prNumber)} --body \"...\"\\`.`;\n }\n return null;\n }\n\n // Writable agents: inject git workflow context\n if (strategy === \"pr\") {\n if (prNumber) {\n return `## Git workflow\\n\\nYou are on branch \\`${branch}\\`.\\nAn open PR exists: #${String(prNumber)}.\\nAfter committing, push your changes to the branch. The PR will be updated automatically.\\nLeave a review comment on the PR summarizing what you did: \\`gh pr comment ${String(prNumber)} --body \"...\"\\`.`;\n }\n return `## Git workflow\\n\\nYou are on branch \\`${branch}\\` (base: \\`${baseBranch}\\`).\\nAfter committing:\\n1. Push: \\`git push -u ${remote} ${branch}\\`\\n2. Create a PR against \\`${baseBranch}\\` — choose a title and description that reflect the work you completed. End the PR body with: \\`🤖 Generated with [neo](https://neotx.dev)\\`\\n3. Output the PR URL on a dedicated line: \\`PR_URL: <url>\\``;\n }\n\n // strategy === \"branch\"\n return `## Git workflow\\n\\nYou are on branch \\`${branch}\\` (base: \\`${baseBranch}\\`).\\nCommit your changes. The branch will be pushed automatically.`;\n}\n\n// ─── Reporting instructions for agents ──────────────────\n\nexport function buildReportingInstructions(_runId: string): string {\n return `## Reporting & Memory\n\nYou have two tools to communicate what you learn and do: \\`neo log\\` (real-time visibility) and \\`neo memory\\` (persistent knowledge for future agents). Use both deliberately throughout your work.\n\n### Progress reporting — \\`neo log\\`\n\nChain \\`neo log\\` with the command that triggered the event — never call it standalone.\n\n<log-types>\n| Type | When to use | Example |\n|------|------------|---------|\n| \\`milestone\\` | A meaningful goal is achieved (tests pass, build succeeds, feature complete) | \\`neo log milestone \"auth middleware passing all tests\"\\` |\n| \\`action\\` | You performed a significant action (push, PR, deploy) | \\`neo log action \"pushed 3 commits to feat/auth\"\\` |\n| \\`decision\\` | You made a non-obvious choice — record WHY | \\`neo log decision \"chose JWT over sessions — stateless, simpler for MVP\"\\` |\n| \\`blocker\\` | Something is preventing progress | \\`neo log blocker \"CI fails: missing DATABASE_URL in test env\"\\` |\n| \\`discovery\\` | You found something surprising or important about the codebase | \\`neo log discovery \"API rate limiter is disabled in dev — tests hit real endpoints\"\\` |\n| \\`progress\\` | General progress update | \\`neo log progress \"3/5 endpoints migrated\"\\` |\n</log-types>\n\n<log-rules>\n- **Chain with commands**: \\`pnpm test && neo log milestone \"tests passing\" || neo log blocker \"tests failing\"\\`\n- **Log decisions with reasoning**: the \"why\" is more valuable than the \"what\"\n- **Log blockers immediately**: do not continue silently — surface problems so the supervisor can act\n- **Log at natural boundaries**: after completing a subtask, before switching context, when hitting an obstacle\n</log-rules>\n\n### Memory — \\`neo memory\\`\n\nMemory is persistent knowledge injected into future agent prompts. Write a memory when you learn something that would change HOW the next agent approaches work on this repo.\n\n<memory-types>\n| Type | When to write | Example |\n|------|--------------|---------|\n| \\`fact\\` | Stable truth that affects workflow decisions | Build quirks, CI config, auth patterns, deployment constraints |\n| \\`procedure\\` | Non-obvious multi-step workflow learned from failure | \"Run X before Y otherwise Z breaks\" |\n</memory-types>\n\n<memory-decision-tree>\nBefore writing a memory, apply this test:\n1. Can \\`cat package.json\\`, \\`ls\\`, or reading the README answer this? → Do NOT memorize.\n2. Would knowing this change how you approach the task? → Write a \\`fact\\`.\n3. Did you fail before discovering this workflow? → Write a \\`procedure\\`.\n4. Is this just a detail about what you did (file counts, line numbers, component names)? → Do NOT memorize.\n</memory-decision-tree>\n\n<memory-examples type=\"good\">\n# Affects workflow — non-obvious build/CI constraints\nneo memory write --type fact --scope $NEO_REPOSITORY \"CI requires pnpm build before push — no auto-rebuild in pipeline\"\nneo memory write --type fact --scope $NEO_REPOSITORY \"Biome enforces complexity max 20 — extract helpers for large functions\"\n\n# Learned from failure — save the next agent from the same mistake\nneo memory write --type procedure --scope $NEO_REPOSITORY \"Run pnpm db:generate after any schema.prisma change — TypeScript types won't update otherwise\"\nneo memory write --type procedure --scope $NEO_REPOSITORY \"E2E tests need STRIPE_TEST_KEY in .env.test — tests hang silently without it\"\n</memory-examples>\n\n<memory-examples type=\"bad\">\n# NEVER write these — trivial or derivable\n# \"packages/core has 71 files\" → derivable from ls\n# \"Uses React 19\" → visible in package.json\n# \"Main entry is src/index.ts\" → visible in package.json\n# \"Tests use vitest\" → visible in config files\n</memory-examples>\n\n<when-to-write>\nWrite memories at these key moments:\n- **After resolving a non-obvious issue**: the fix revealed a constraint future agents should know\n- **After discovering a build/CI/deploy quirk**: the next agent will hit the same wall without this\n- **Before finishing your task**: review what you learned — anything that would save the next agent 10+ minutes?\n- **After a failed attempt**: if you tried something that seemed right but failed, document why\n</when-to-write>`;\n}\n\n// ─── Full prompt assembler ─────────────────────────────\n\nexport function buildFullPrompt(\n agentPrompt: string | undefined,\n repoInstructions: string | undefined,\n gitInstructions: string | null,\n taskPrompt: string,\n memoryContext?: string | undefined,\n cwdInstructions?: string | undefined,\n reportingInstructions?: string | undefined,\n): string {\n const sections: string[] = [];\n\n if (agentPrompt) sections.push(agentPrompt);\n if (cwdInstructions) sections.push(cwdInstructions);\n if (memoryContext) sections.push(memoryContext);\n if (repoInstructions) sections.push(`## Repository instructions\\n\\n${repoInstructions}`);\n if (gitInstructions) sections.push(gitInstructions);\n if (reportingInstructions) sections.push(reportingInstructions);\n sections.push(`## Task\\n\\n${taskPrompt}`);\n\n return sections.join(\"\\n\\n---\\n\\n\");\n}\n","import type { ZodType } from \"zod\";\n\nexport interface ParsedOutput {\n rawOutput: string;\n output?: unknown;\n parseError?: string;\n prUrl?: string;\n prNumber?: number;\n}\n\n/**\n * Extract JSON from agent output that may be wrapped in markdown code blocks.\n * Tries multiple strategies: raw JSON parse, then markdown code block extraction.\n */\nfunction extractJson(raw: string): unknown | undefined {\n // Strategy 1: Try parsing the entire string as JSON\n try {\n return JSON.parse(raw);\n } catch {\n // Not raw JSON, continue\n }\n\n // Strategy 2: Extract from markdown code blocks (```json ... ``` or ``` ... ```)\n const codeBlockRegex = /```(?:json)?\\s*\\n?([\\s\\S]*?)```/;\n const match = raw.match(codeBlockRegex);\n if (match?.[1]) {\n try {\n return JSON.parse(match[1].trim());\n } catch {\n // Invalid JSON inside code block\n }\n }\n\n return undefined;\n}\n\n// ─── PR URL extraction ──────────────────────────────────\n\nconst PR_URL_REGEX = /^PR_URL:\\s*(https?:\\/\\/\\S+)/m;\n\nexport function extractPrUrl(raw: string): { prUrl: string; prNumber?: number } | undefined {\n const match = raw.match(PR_URL_REGEX);\n if (!match?.[1]) return undefined;\n\n const prUrl = match[1];\n const numberMatch = prUrl.match(/\\/pull\\/(\\d+)/);\n\n if (numberMatch?.[1]) {\n return { prUrl, prNumber: Number.parseInt(numberMatch[1], 10) };\n }\n return { prUrl };\n}\n\n/**\n * Parse agent output, optionally validating against a Zod schema.\n * Also extracts structured markers like PR_URL from the output.\n *\n * - If no schema: returns rawOutput only\n * - If schema provided: extracts JSON from output, validates with schema\n * - On failure: returns rawOutput + parseError (caller decides whether to retry)\n */\nexport function parseOutput(raw: string, schema?: ZodType): ParsedOutput {\n const prInfo = extractPrUrl(raw);\n const base: ParsedOutput = { rawOutput: raw };\n if (prInfo) {\n base.prUrl = prInfo.prUrl;\n if (prInfo.prNumber !== undefined) {\n base.prNumber = prInfo.prNumber;\n }\n }\n\n if (!schema) {\n return base;\n }\n\n const extracted = extractJson(raw);\n if (extracted === undefined) {\n base.parseError = \"Failed to extract JSON from output\";\n return base;\n }\n\n const result = schema.safeParse(extracted);\n if (!result.success) {\n base.parseError = `Schema validation failed: ${result.error.message}`;\n return base;\n }\n\n base.output = result.data;\n return base;\n}\n","// ─── SDK Stream Message Types ────────────────────────────\n// Unified type definitions for Claude Agent SDK stream messages.\n// Both session.ts and heartbeat.ts import from this module.\n\n/**\n * Base SDK stream message shape.\n * All messages from the SDK stream have at least a type field.\n */\nexport interface SDKStreamMessage {\n type: string;\n subtype?: string;\n}\n\n/**\n * Init message emitted when a session starts.\n * Contains the session ID for tracking.\n */\nexport interface SDKInitMessage extends SDKStreamMessage {\n type: \"system\";\n subtype: \"init\";\n session_id: string;\n}\n\n/**\n * Result message emitted when a session completes.\n * Contains the final output, cost, and turn count.\n */\nexport interface SDKResultMessage extends SDKStreamMessage {\n type: \"result\";\n subtype: \"success\" | string;\n session_id: string;\n result: string;\n total_cost_usd: number;\n num_turns: number;\n}\n\n/**\n * Content block in an assistant message.\n */\nexport interface SDKContentBlock {\n type: string;\n thinking?: string;\n text?: string;\n}\n\n/**\n * Assistant message with content blocks.\n */\nexport interface SDKAssistantMessage extends SDKStreamMessage {\n type: \"assistant\";\n message?: {\n content?: SDKContentBlock[];\n };\n}\n\n/**\n * Tool use message from the assistant.\n */\nexport interface SDKToolUseMessage extends SDKStreamMessage {\n type: \"assistant\";\n subtype: \"tool_use\";\n tool: string;\n input?: unknown;\n}\n\n/**\n * Tool result message.\n */\nexport interface SDKToolResultMessage extends SDKStreamMessage {\n type: \"assistant\";\n subtype: \"tool_result\";\n result?: string;\n}\n\n// ─── Type Guards ─────────────────────────────────────────\n\n/**\n * Check if a message is an init message (session started).\n */\nexport function isInitMessage(msg: SDKStreamMessage): msg is SDKInitMessage {\n return msg.type === \"system\" && msg.subtype === \"init\";\n}\n\n/**\n * Check if a message is a result message (session completed).\n */\nexport function isResultMessage(msg: SDKStreamMessage): msg is SDKResultMessage {\n return msg.type === \"result\";\n}\n\n/**\n * Check if a message is an assistant message with content.\n */\nexport function isAssistantMessage(msg: SDKStreamMessage): msg is SDKAssistantMessage {\n return msg.type === \"assistant\" && !msg.subtype;\n}\n\n/**\n * Check if a message is a tool use message.\n */\nexport function isToolUseMessage(msg: SDKStreamMessage): msg is SDKToolUseMessage {\n return msg.type === \"assistant\" && msg.subtype === \"tool_use\";\n}\n\n/**\n * Check if a message is a tool result message.\n */\nexport function isToolResultMessage(msg: SDKStreamMessage): msg is SDKToolResultMessage {\n return msg.type === \"assistant\" && msg.subtype === \"tool_result\";\n}\n","import type { McpServerConfig } from \"@/config\";\nimport type { SandboxConfig } from \"@/isolation/sandbox\";\nimport { isInitMessage, isResultMessage, type SDKStreamMessage } from \"@/sdk-types\";\nimport type { ResolvedAgent } from \"@/types\";\n\n// ─── Types ──────────────────────────────────────────────\n\nexport interface SessionOptions {\n agent: ResolvedAgent;\n prompt: string;\n repoPath?: string;\n sessionPath?: string;\n sandboxConfig: SandboxConfig;\n hooks?: Record<string, unknown>;\n mcpServers?: Record<string, McpServerConfig>;\n env?: Record<string, string>;\n initTimeoutMs: number;\n maxDurationMs: number;\n resumeSessionId?: string | undefined;\n onEvent?: ((event: SessionEvent) => void) | undefined;\n}\n\nexport interface SessionResult {\n sessionId: string;\n output: string;\n costUsd: number;\n durationMs: number;\n turnCount: number;\n}\n\nexport type SessionEvent =\n | { type: \"session:start\"; sessionId: string }\n | { type: \"session:complete\"; sessionId: string; result: SessionResult }\n | { type: \"session:fail\"; sessionId: string; error: string };\n\n// ─── Helpers ────────────────────────────────────────────\n\nfunction checkAborted(signal: AbortSignal): void {\n if (signal.aborted) {\n const reason = signal.reason;\n throw reason instanceof Error ? reason : new Error(String(reason));\n }\n}\n\nfunction toSessionError(error: unknown, isTimeout: boolean, sessionId: string): SessionError {\n if (error instanceof SessionError) return error;\n const message = error instanceof Error ? error.message : String(error);\n return new SessionError(message, isTimeout ? \"timeout\" : \"unknown\", sessionId);\n}\n\n// ─── Query Options Builder ──────────────────────────────\n\nfunction buildQueryOptions(options: SessionOptions): Record<string, unknown> {\n const { sessionPath, sandboxConfig } = options;\n\n const queryOptions: Record<string, unknown> = {\n // Always pass cwd: session clone for writable agents, repo root for readonly.\n // Without this, readonly agents default to process.cwd() and may write to main tree.\n cwd: sessionPath ?? options.repoPath,\n // maxTurns: agent.maxTurns,\n allowedTools: sandboxConfig.allowedTools,\n // Workers run detached without a TTY — bypass interactive permission prompts.\n // Required pair: permissionMode alone is not enough, SDK also needs the flag.\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n // Load project-level CLAUDE.md so agents inherit project rules and conventions.\n settingSources: [\"user\", \"project\", \"local\"],\n // Don't persist agent sessions — they are ephemeral clones.\n persistSession: false,\n };\n\n if (options.resumeSessionId) {\n queryOptions.resume = options.resumeSessionId;\n }\n\n if (options.mcpServers && Object.keys(options.mcpServers).length > 0) {\n queryOptions.mcpServers = options.mcpServers;\n }\n\n if (options.env && Object.keys(options.env).length > 0) {\n // Merge with process.env so PATH, HOME, etc. are preserved.\n // Custom vars override process.env if there's a conflict.\n queryOptions.env = { ...process.env, ...options.env };\n }\n\n return queryOptions;\n}\n\n// ─── Session Runner ─────────────────────────────────────\n\nexport async function runSession(options: SessionOptions): Promise<SessionResult> {\n const { prompt, initTimeoutMs, maxDurationMs, onEvent } = options;\n\n const startTime = Date.now();\n let sessionId = \"\";\n\n const abortController = new AbortController();\n const initTimer = setTimeout(() => {\n abortController.abort(new Error(\"Session init timeout exceeded\"));\n }, initTimeoutMs);\n const maxDurationTimer = setTimeout(() => {\n abortController.abort(new Error(\"Session max duration exceeded\"));\n }, maxDurationMs);\n\n try {\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\");\n const queryOptions = buildQueryOptions(options);\n\n let output = \"\";\n let costUsd = 0;\n let turnCount = 0;\n\n // The prompt is already assembled by the orchestrator (agent prompt +\n // repo instructions + git strategy context + task). Session just passes it through.\n const stream = sdk.query({ prompt, options: queryOptions as never });\n\n for await (const message of stream) {\n checkAborted(abortController.signal);\n\n const msg = message as SDKStreamMessage;\n\n if (isInitMessage(msg)) {\n sessionId = msg.session_id;\n clearTimeout(initTimer);\n onEvent?.({ type: \"session:start\", sessionId });\n }\n\n if (isResultMessage(msg)) {\n output = msg.result ?? \"\";\n costUsd = msg.total_cost_usd ?? 0;\n turnCount = msg.num_turns ?? 0;\n sessionId = msg.session_id ?? sessionId;\n\n if (msg.subtype !== \"success\") {\n throw new SessionError(\n `Session ended with error: ${msg.subtype}`,\n msg.subtype,\n sessionId,\n );\n }\n }\n }\n\n const sessionResult: SessionResult = {\n sessionId,\n output,\n costUsd,\n durationMs: Date.now() - startTime,\n turnCount,\n };\n\n onEvent?.({ type: \"session:complete\", sessionId, result: sessionResult });\n return sessionResult;\n } catch (error) {\n const errorSessionId = sessionId || \"unknown\";\n const sessionError = toSessionError(error, abortController.signal.aborted, errorSessionId);\n\n onEvent?.({ type: \"session:fail\", sessionId: errorSessionId, error: sessionError.message });\n throw sessionError;\n } finally {\n clearTimeout(initTimer);\n clearTimeout(maxDurationTimer);\n }\n}\n\n// ─── Error class ────────────────────────────────────────\n\nexport class SessionError extends Error {\n constructor(\n message: string,\n public readonly errorType: string,\n public readonly sessionId: string,\n ) {\n super(message);\n this.name = \"SessionError\";\n }\n}\n","import {\n runSession,\n SessionError,\n type SessionOptions,\n type SessionResult,\n} from \"@/runner/session\";\n\n// ─── Types ──────────────────────────────────────────────\n\nexport interface RecoveryOptions extends SessionOptions {\n maxRetries: number;\n backoffBaseMs: number;\n nonRetryable?: string[];\n onAttempt?: (attempt: number, strategy: string) => void;\n}\n\n// ─── Default non-retryable errors ───────────────────────\n\nconst DEFAULT_NON_RETRYABLE = [\"error_max_turns\", \"budget_exceeded\"];\n\n// ─── Recovery strategy names ────────────────────────────\n\nfunction getStrategy(attempt: number): string {\n switch (attempt) {\n case 1:\n return \"normal\";\n case 2:\n return \"resume\";\n default:\n return \"fresh\";\n }\n}\n\n// ─── Sleep utility ──────────────────────────────────────\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ─── Error handling ─────────────────────────────────────\n\nfunction isNonRetryable(error: unknown, nonRetryable: string[]): boolean {\n return error instanceof SessionError && nonRetryable.includes(error.errorType);\n}\n\nfunction updateSessionId(error: unknown, current: string | undefined): string | undefined {\n if (error instanceof SessionError && error.sessionId !== \"unknown\") {\n return error.sessionId;\n }\n return current;\n}\n\nfunction buildFinalError(error: unknown, maxRetries: number): Error {\n if (error instanceof Error) {\n return new Error(`Recovery failed after ${maxRetries} attempts. Last error: ${error.message}`, {\n cause: error,\n });\n }\n return new Error(`Recovery failed after ${maxRetries} attempts`);\n}\n\n/**\n * Run a session with 3-level recovery escalation (ADR-020).\n *\n * Level 1 (attempt 1): Normal execution — new session\n * Level 2 (attempt 2): Resume session — pass resumeSessionId from level 1\n * Level 3 (attempt 3): Fresh session — abandon previous, start clean\n *\n * Non-retryable errors skip to immediate failure.\n * Backoff: backoffBaseMs * attempt between levels.\n */\nexport async function runWithRecovery(options: RecoveryOptions): Promise<SessionResult> {\n const {\n maxRetries,\n backoffBaseMs,\n nonRetryable = DEFAULT_NON_RETRYABLE,\n onAttempt,\n ...rest\n } = options;\n\n let lastSessionId: string | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const strategy = getStrategy(attempt);\n onAttempt?.(attempt, strategy);\n\n try {\n const result = await runSession({\n ...rest,\n resumeSessionId: strategy === \"resume\" ? lastSessionId : undefined,\n });\n return result;\n } catch (error) {\n lastSessionId = updateSessionId(error, lastSessionId);\n\n if (isNonRetryable(error, nonRetryable)) throw error;\n if (attempt === maxRetries) throw buildFinalError(error, maxRetries);\n\n // Next attempt will be \"fresh\" — clear session to start clean\n if (getStrategy(attempt + 1) === \"fresh\") {\n lastSessionId = undefined;\n }\n\n await sleep(backoffBaseMs * attempt);\n }\n }\n\n throw new Error(\"Recovery failed: unreachable\");\n}\n","import type { GitStrategy, McpServerConfig, RepoConfig } from \"@/config\";\nimport { buildSandboxConfig } from \"@/isolation/sandbox\";\nimport { buildMiddlewareChain, buildSDKHooks } from \"@/middleware/chain\";\nimport {\n buildFullPrompt,\n buildGitStrategyInstructions,\n buildReportingInstructions,\n loadRepoInstructions,\n} from \"@/orchestrator/prompt-builder\";\nimport { type ParsedOutput, parseOutput } from \"@/runner/output-parser\";\nimport { runWithRecovery } from \"@/runner/recovery\";\nimport type { Middleware, MiddlewareContext, ResolvedAgent, StepResult } from \"@/types\";\n\n// ─── Types ─────────────────────────────────────────────\n\nexport interface SessionExecutionInput {\n runId: string;\n sessionId: string;\n agent: ResolvedAgent;\n repoConfig: RepoConfig;\n repoPath: string;\n prompt: string;\n branch?: string | undefined;\n gitStrategy: GitStrategy;\n sessionPath?: string | undefined;\n metadata?: Record<string, unknown> | undefined;\n startedAt: string;\n}\n\nexport interface SessionExecutionConfig {\n initTimeoutMs: number;\n maxDurationMs: number;\n maxRetries: number;\n backoffBaseMs: number;\n}\n\nexport interface SessionExecutionDeps {\n middleware: Middleware[];\n mcpServers?: Record<string, McpServerConfig> | undefined;\n memoryContext?: string | undefined;\n onAttempt?: (attempt: number, strategy: string) => void;\n}\n\nexport interface SessionExecutionResult extends StepResult {\n parsed: ParsedOutput;\n}\n\n// ─── Middleware context builder ────────────────────────\n\nfunction buildMiddlewareContext(\n runId: string,\n step: string,\n agent: string,\n repo: string,\n getContextValue: (key: string) => unknown,\n): MiddlewareContext {\n const store = new Map<string, unknown>();\n return {\n runId,\n step,\n agent,\n repo,\n get: ((key: string) => {\n const value = getContextValue(key);\n if (value !== undefined) return value;\n return store.get(key);\n }) as MiddlewareContext[\"get\"],\n set: ((key: string, value: unknown) => {\n store.set(key, value);\n }) as MiddlewareContext[\"set\"],\n };\n}\n\n// ─── SessionExecutor ───────────────────────────────────\n\n/**\n * Encapsulates session execution logic: prompt building, SDK calls, and response processing.\n * Extracted from Orchestrator for better testability and separation of concerns.\n */\nexport class SessionExecutor {\n constructor(\n private readonly config: SessionExecutionConfig,\n private readonly getContextValue: (key: string) => unknown,\n ) {}\n\n /**\n * Execute an agent session with the given input and dependencies.\n * Handles prompt building, SDK invocation via recovery wrapper, and output parsing.\n */\n async execute(\n input: SessionExecutionInput,\n deps: SessionExecutionDeps,\n ): Promise<SessionExecutionResult> {\n const {\n runId,\n agent,\n repoConfig,\n repoPath,\n prompt: taskPrompt,\n branch,\n gitStrategy,\n sessionPath,\n metadata,\n startedAt,\n } = input;\n\n const { middleware, mcpServers, memoryContext, onAttempt } = deps;\n\n // Validate writable agents have a branch\n if (agent.sandbox === \"writable\" && !branch) {\n throw new Error(\n \"Validation error: --branch is required for writable agents. Provide an explicit branch name (e.g. --branch feat/PROJ-42-description).\",\n );\n }\n\n const branchName = agent.sandbox === \"writable\" ? (branch as string) : \"\";\n\n // Build sandbox config for agent\n const sandboxConfig = buildSandboxConfig(agent, sessionPath);\n\n // Build middleware chain and SDK hooks\n const chain = buildMiddlewareChain(middleware);\n const middlewareContext = buildMiddlewareContext(\n runId,\n \"execute\",\n agent.name,\n repoPath,\n this.getContextValue,\n );\n const hooks = buildSDKHooks(chain, middlewareContext, middleware);\n\n // Build the full prompt\n const repoInstructions = await loadRepoInstructions(repoPath);\n const gitInstructions = buildGitStrategyInstructions(\n gitStrategy,\n agent,\n branchName,\n repoConfig.defaultBranch,\n repoConfig.pushRemote ?? \"origin\",\n metadata,\n );\n\n const cwdInstructions = sessionPath\n ? `## Working directory\\n\\nYou are working in an isolated clone at: \\`${sessionPath}\\`\\nALWAYS run commands from this directory. NEVER cd to or operate on any other repository.`\n : undefined;\n\n const reportingInstructions = buildReportingInstructions(runId);\n\n const fullPrompt = buildFullPrompt(\n agent.definition.prompt,\n repoInstructions,\n gitInstructions,\n taskPrompt,\n memoryContext,\n cwdInstructions,\n reportingInstructions,\n );\n\n // Execute session with recovery\n const agentEnv: Record<string, string> = {\n NEO_RUN_ID: runId,\n NEO_AGENT_NAME: agent.name,\n NEO_REPOSITORY: repoPath,\n };\n\n const sessionResult = await runWithRecovery({\n agent,\n prompt: fullPrompt,\n repoPath,\n sandboxConfig,\n hooks,\n env: agentEnv,\n initTimeoutMs: this.config.initTimeoutMs,\n maxDurationMs: this.config.maxDurationMs,\n maxRetries: this.config.maxRetries,\n backoffBaseMs: this.config.backoffBaseMs,\n ...(sessionPath ? { sessionPath } : {}),\n ...(mcpServers ? { mcpServers } : {}),\n ...(onAttempt ? { onAttempt } : {}),\n });\n\n // Parse output\n const parsed = parseOutput(sessionResult.output);\n\n // Build result\n const result: SessionExecutionResult = {\n status: \"success\",\n sessionId: sessionResult.sessionId,\n output: parsed.output ?? parsed.rawOutput,\n rawOutput: sessionResult.output,\n costUsd: sessionResult.costUsd,\n durationMs: sessionResult.durationMs,\n agent: agent.name,\n startedAt,\n completedAt: new Date().toISOString(),\n attempt: 1,\n parsed,\n };\n\n if (parsed.prUrl) {\n result.prUrl = parsed.prUrl;\n }\n if (parsed.prNumber !== undefined) {\n result.prNumber = parsed.prNumber;\n }\n\n return result;\n }\n}\n\n// ─── Standalone prompt builders (re-exported for backward compatibility) ───\n\nexport {\n buildFullPrompt,\n buildGitStrategyInstructions,\n buildReportingInstructions,\n loadRepoInstructions,\n};\n","// ─── Embedder interface ──────────────────────────────────\n\nexport interface Embedder {\n embed(texts: string[]): Promise<number[][]>;\n readonly dimensions: number;\n}\n\n// ─── Local embedder (Transformers.js) ────────────────────\n\nlet extractorPromise: Promise<unknown> | null = null;\n\nfunction getExtractor(): Promise<unknown> {\n if (!extractorPromise) {\n extractorPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n return pipeline(\"feature-extraction\", \"Xenova/all-MiniLM-L6-v2\", {\n dtype: \"fp32\",\n });\n })();\n }\n return extractorPromise;\n}\n\nexport class LocalEmbedder implements Embedder {\n readonly dimensions = 384;\n\n async embed(texts: string[]): Promise<number[][]> {\n const extractor = (await getExtractor()) as (\n texts: string[],\n opts: { pooling: string; normalize: boolean },\n ) => Promise<{ tolist(): number[][] }>;\n const output = await extractor(texts, { pooling: \"mean\", normalize: true });\n return output.tolist();\n }\n}\n\n// ─── Cosine similarity ──────────────────────────────────\n\nexport function cosineSimilarity(a: number[], b: number[]): number {\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += (a[i] ?? 0) * (b[i] ?? 0);\n normA += (a[i] ?? 0) * (a[i] ?? 0);\n normB += (b[i] ?? 0) * (b[i] ?? 0);\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dot / denom;\n}\n","import { z } from \"zod\";\n\n// ─── Memory types ────────────────────────────────────────\n\nexport const memoryTypeSchema = z.enum([\n \"fact\",\n \"procedure\",\n \"episode\",\n \"focus\",\n \"feedback\",\n \"task\",\n]);\n\nexport type MemoryType = z.infer<typeof memoryTypeSchema>;\n\n// ─── Memory entry (persisted in SQLite) ──────────────────\n\nexport const memoryEntrySchema = z.object({\n id: z.string(),\n type: memoryTypeSchema,\n scope: z.string(), // \"global\" | repo path\n content: z.string(),\n source: z.string(), // \"developer\" | \"reviewer\" | \"supervisor\" | \"user\"\n tags: z.array(z.string()).default([]),\n\n // Lifecycle\n createdAt: z.string(),\n lastAccessedAt: z.string(),\n accessCount: z.number().default(0),\n\n // Optional per-type fields\n expiresAt: z.string().optional(), // focus TTL\n outcome: z.string().optional(), // episode: success/failure/blocked\n runId: z.string().optional(),\n category: z.string().optional(), // feedback: reviewer issue category\n severity: z.string().optional(),\n supersedes: z.string().optional(), // contradiction resolution\n});\n\nexport type MemoryEntry = z.infer<typeof memoryEntrySchema>;\n\n// ─── Write input (id and timestamps are auto-generated) ──\n\nexport const memoryWriteInputSchema = z.object({\n type: memoryTypeSchema,\n scope: z.string().default(\"global\"),\n content: z.string(),\n source: z.string().default(\"user\"),\n tags: z.array(z.string()).default([]),\n expiresAt: z.string().optional(),\n outcome: z.string().optional(),\n runId: z.string().optional(),\n category: z.string().optional(),\n severity: z.string().optional(),\n supersedes: z.string().optional(),\n});\n\nexport type MemoryWriteInput = z.input<typeof memoryWriteInputSchema>;\n\n// ─── Query options ───────────────────────────────────────\n\nexport interface MemoryQuery {\n scope?: string;\n types?: MemoryType[];\n since?: string; // ISO timestamp\n limit?: number;\n sortBy?: \"relevance\" | \"createdAt\" | \"accessCount\";\n tags?: string[];\n}\n\n// ─── Stats ───────────────────────────────────────────────\n\nexport interface MemoryStats {\n total: number;\n byType: Record<string, number>;\n byScope: Record<string, number>;\n}\n","import type { MemoryEntry } from \"./entry.js\";\n\nconst TYPE_LABELS: Record<string, string> = {\n fact: \"Fact\",\n procedure: \"How-to\",\n episode: \"Past run\",\n focus: \"Current focus\",\n feedback: \"Recurring issue\",\n};\n\nconst TYPE_ICONS: Record<string, string> = {\n fact: \"·\",\n procedure: \"→\",\n episode: \"◇\",\n focus: \"★\",\n feedback: \"⚠\",\n};\n\n/**\n * Format a list of memories for injection into an agent or supervisor prompt.\n * Groups by type, renders as concise markdown.\n */\nexport function formatMemoriesForPrompt(memories: MemoryEntry[]): string {\n if (memories.length === 0) return \"\";\n\n const grouped = new Map<string, MemoryEntry[]>();\n for (const m of memories) {\n const group = grouped.get(m.type) ?? [];\n group.push(m);\n grouped.set(m.type, group);\n }\n\n const sections: string[] = [];\n\n for (const [type, entries] of grouped) {\n const label = TYPE_LABELS[type] ?? type;\n const icon = TYPE_ICONS[type] ?? \"·\";\n const lines = entries.map((e) => {\n const confidence = e.accessCount >= 3 ? \"\" : \" (unconfirmed)\";\n return `${icon} ${e.content}${confidence}`;\n });\n sections.push(`### ${label}s\\n${lines.join(\"\\n\")}`);\n }\n\n return `## Known context for this repository\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport type { Embedder } from \"./embedder.js\";\nimport type { MemoryEntry, MemoryQuery, MemoryStats, MemoryWriteInput } from \"./entry.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\n// ─── MemoryStore ─────────────────────────────────────────\n\nexport class MemoryStore {\n private db: import(\"better-sqlite3\").Database;\n private embedder: Embedder | null;\n private hasVec: boolean;\n\n constructor(dbPath: string, embedder?: Embedder | null) {\n const dir = path.dirname(dbPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // better-sqlite3 is synchronous — import at module level would break ESM lazy loading\n const Database = esmRequire(\"better-sqlite3\");\n this.db = new Database(dbPath);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"foreign_keys = ON\");\n\n this.embedder = embedder ?? null;\n this.hasVec = false;\n\n this.initSchema();\n }\n\n // ─── Schema initialization ───────────────────────────\n\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('fact','procedure','episode','focus','feedback','task')),\n scope TEXT NOT NULL,\n content TEXT NOT NULL,\n source TEXT NOT NULL,\n tags TEXT DEFAULT '[]',\n created_at TEXT NOT NULL,\n last_accessed_at TEXT NOT NULL,\n access_count INTEGER DEFAULT 0,\n expires_at TEXT,\n outcome TEXT,\n run_id TEXT,\n category TEXT,\n severity TEXT,\n supersedes TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_mem_type_scope ON memories(type, scope);\n CREATE INDEX IF NOT EXISTS idx_mem_created ON memories(created_at);\n `);\n\n // Migrate CHECK constraint if table predates 'task' type\n this.migrateCheckConstraint();\n\n // FTS5 for full-text search\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n content,\n content='memories',\n content_rowid='rowid',\n tokenize='porter'\n );\n `);\n\n // Triggers to keep FTS in sync\n this.db.exec(`\n CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, content) VALUES (new.rowid, new.content);\n END;\n CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content) VALUES('delete', old.rowid, old.content);\n END;\n CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content) VALUES('delete', old.rowid, old.content);\n INSERT INTO memories_fts(rowid, content) VALUES (new.rowid, new.content);\n END;\n `);\n\n // sqlite-vec for vector search (optional — may not be installed)\n if (this.embedder) {\n try {\n const sqliteVec = esmRequire(\"sqlite-vec\");\n sqliteVec.load(this.db);\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(\n memory_id TEXT,\n embedding float[${this.embedder.dimensions}]\n );\n `);\n this.hasVec = true;\n } catch {\n // sqlite-vec not available — fall back to FTS\n this.hasVec = false;\n }\n }\n }\n\n /**\n * Migrate existing tables whose CHECK constraint predates the 'task' type.\n * SQLite doesn't allow ALTER CHECK, so we recreate the table if needed.\n */\n private migrateCheckConstraint(): void {\n const tableInfo = this.db\n .prepare(\"SELECT sql FROM sqlite_master WHERE type='table' AND name='memories'\")\n .get() as { sql: string } | undefined;\n if (!tableInfo || tableInfo.sql.includes(\"'task'\")) return;\n\n this.db.exec(`\n ALTER TABLE memories RENAME TO memories_old;\n\n CREATE TABLE memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('fact','procedure','episode','focus','feedback','task')),\n scope TEXT NOT NULL,\n content TEXT NOT NULL,\n source TEXT NOT NULL,\n tags TEXT DEFAULT '[]',\n created_at TEXT NOT NULL,\n last_accessed_at TEXT NOT NULL,\n access_count INTEGER DEFAULT 0,\n expires_at TEXT,\n outcome TEXT,\n run_id TEXT,\n category TEXT,\n severity TEXT,\n supersedes TEXT\n );\n\n INSERT INTO memories SELECT * FROM memories_old;\n DROP TABLE memories_old;\n `);\n }\n\n // ─── Write ───────────────────────────────────────────\n\n async write(input: MemoryWriteInput): Promise<string> {\n const id = `mem_${randomUUID().slice(0, 12)}`;\n const now = new Date().toISOString();\n\n this.db\n .prepare(\n `INSERT INTO memories (id, type, scope, content, source, tags, created_at, last_accessed_at, access_count, expires_at, outcome, run_id, category, severity, supersedes)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n input.type,\n input.scope ?? \"global\",\n input.content,\n input.source ?? \"user\",\n JSON.stringify(input.tags ?? []),\n now,\n now,\n input.expiresAt ?? null,\n input.outcome ?? null,\n input.runId ?? null,\n input.category ?? null,\n input.severity ?? null,\n input.supersedes ?? null,\n );\n\n // Embed and store vector\n if (this.embedder && this.hasVec) {\n try {\n const [vector] = await this.embedder.embed([input.content]);\n const rowid = this.db.prepare(\"SELECT rowid FROM memories WHERE id = ?\").get(id) as\n | { rowid: number }\n | undefined;\n if (rowid && vector) {\n this.db\n .prepare(\"INSERT INTO memories_vec (rowid, memory_id, embedding) VALUES (?, ?, ?)\")\n .run(rowid.rowid, id, new Float32Array(vector));\n }\n } catch {\n // Embedding failed — entry still saved without vector\n }\n }\n\n return id;\n }\n\n // ─── Update ──────────────────────────────────────────\n\n update(id: string, content: string): void {\n this.db.prepare(\"UPDATE memories SET content = ? WHERE id = ?\").run(content, id);\n\n // Re-embedding happens lazily on next search if needed\n // For now, remove stale vector\n if (this.hasVec) {\n const row = this.db.prepare(\"SELECT rowid FROM memories WHERE id = ?\").get(id) as\n | { rowid: number }\n | undefined;\n if (row) {\n this.db.prepare(\"DELETE FROM memories_vec WHERE rowid = ?\").run(row.rowid);\n }\n }\n }\n\n // ─── Update fields ───────────────────────────────────\n\n updateFields(id: string, fields: { content?: string; outcome?: string; runId?: string }): void {\n const sets: string[] = [];\n const params: unknown[] = [];\n if (fields.content !== undefined) {\n sets.push(\"content = ?\");\n params.push(fields.content);\n }\n if (fields.outcome !== undefined) {\n sets.push(\"outcome = ?\");\n params.push(fields.outcome);\n }\n if (fields.runId !== undefined) {\n sets.push(\"run_id = ?\");\n params.push(fields.runId);\n }\n if (sets.length === 0) return;\n params.push(id);\n this.db.prepare(`UPDATE memories SET ${sets.join(\", \")} WHERE id = ?`).run(...params);\n }\n\n // ─── Forget ──────────────────────────────────────────\n\n forget(id: string): void {\n const row = this.db.prepare(\"SELECT rowid FROM memories WHERE id = ?\").get(id) as\n | { rowid: number }\n | undefined;\n if (row && this.hasVec) {\n this.db.prepare(\"DELETE FROM memories_vec WHERE rowid = ?\").run(row.rowid);\n }\n this.db.prepare(\"DELETE FROM memories WHERE id = ?\").run(id);\n }\n\n // ─── Query (synchronous — structured filters) ───────\n\n query(opts: MemoryQuery = {}): MemoryEntry[] {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (opts.scope) {\n conditions.push(\"(scope = ? OR scope = 'global')\");\n params.push(opts.scope);\n }\n\n if (opts.types && opts.types.length > 0) {\n const placeholders = opts.types.map(() => \"?\").join(\",\");\n conditions.push(`type IN (${placeholders})`);\n params.push(...opts.types);\n }\n\n if (opts.since) {\n conditions.push(\"created_at > ?\");\n params.push(opts.since);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n\n let orderBy: string;\n switch (opts.sortBy) {\n case \"accessCount\":\n orderBy = \"ORDER BY access_count DESC\";\n break;\n case \"createdAt\":\n orderBy = \"ORDER BY created_at DESC\";\n break;\n default:\n orderBy =\n \"ORDER BY (access_count * MAX(0, 1.0 - (julianday('now') - julianday(last_accessed_at)) / 60.0)) DESC\";\n break;\n }\n\n const limit = opts.limit ? `LIMIT ${opts.limit}` : \"LIMIT 50\";\n\n const rows = this.db\n .prepare(`SELECT * FROM memories ${where} ${orderBy} ${limit}`)\n .all(...params) as RawMemoryRow[];\n\n return rows.map(rowToEntry);\n }\n\n // ─── Search (async — semantic or FTS) ────────────────\n\n async search(text: string, opts: MemoryQuery = {}): Promise<MemoryEntry[]> {\n // Try vector search first\n if (this.embedder && this.hasVec) {\n try {\n const [queryVec] = await this.embedder.embed([text]);\n const limit = opts.limit ?? 20;\n\n // Build scope/type filter for post-filtering\n const candidates = this.db\n .prepare(\n `SELECT m.*, v.distance\n FROM memories_vec v\n JOIN memories m ON m.rowid = v.rowid\n WHERE v.embedding MATCH ?\n ORDER BY v.distance\n LIMIT ?`,\n )\n .all(new Float32Array(queryVec as number[]), limit * 3) as (RawMemoryRow & {\n distance: number;\n })[];\n\n // Post-filter by scope and type\n const filtered = candidates.filter((row) => {\n if (opts.scope && row.scope !== opts.scope && row.scope !== \"global\") return false;\n if (\n opts.types &&\n opts.types.length > 0 &&\n !opts.types.includes(row.type as MemoryEntry[\"type\"])\n )\n return false;\n return true;\n });\n\n return filtered.slice(0, limit).map((row) => rowToEntry(row));\n } catch {\n // Fall through to FTS\n }\n }\n\n // Fallback: FTS5 full-text search\n const limit = opts.limit ?? 20;\n const ftsQuery = text\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w}\"`)\n .join(\" OR \");\n\n if (!ftsQuery) return this.query(opts);\n\n try {\n const rows = this.db\n .prepare(\n `SELECT m.*, rank\n FROM memories_fts fts\n JOIN memories m ON m.rowid = fts.rowid\n WHERE memories_fts MATCH ?\n ORDER BY rank\n LIMIT ?`,\n )\n .all(ftsQuery, limit) as RawMemoryRow[];\n\n const filtered = rows.filter((row) => {\n if (opts.scope && row.scope !== opts.scope && row.scope !== \"global\") return false;\n if (\n opts.types &&\n opts.types.length > 0 &&\n !opts.types.includes(row.type as MemoryEntry[\"type\"])\n )\n return false;\n return true;\n });\n\n return filtered.map(rowToEntry);\n } catch {\n // FTS query syntax error — fall back to LIKE\n return this.query(opts);\n }\n }\n\n // ─── Lifecycle ───────────────────────────────────────\n\n markAccessed(ids: string[]): void {\n if (ids.length === 0) return;\n const now = new Date().toISOString();\n const stmt = this.db.prepare(\n \"UPDATE memories SET access_count = access_count + 1, last_accessed_at = ? WHERE id = ?\",\n );\n const transaction = this.db.transaction(() => {\n for (const id of ids) {\n stmt.run(now, id);\n }\n });\n transaction();\n }\n\n decay(maxAgeDays = 30, minAccessCount = 3): number {\n // Delete stale low-access memories\n const staleResult = this.db\n .prepare(\n `DELETE FROM memories\n WHERE access_count < ?\n AND julianday('now') - julianday(last_accessed_at) > ?\n AND type NOT IN ('focus', 'task')`,\n )\n .run(minAccessCount, maxAgeDays);\n\n // Delete completed tasks older than 7 days\n const taskResult = this.db\n .prepare(\n `DELETE FROM memories\n WHERE type = 'task'\n AND outcome = 'done'\n AND julianday('now') - julianday(last_accessed_at) > 7`,\n )\n .run();\n\n return staleResult.changes + taskResult.changes;\n }\n\n expireEphemeral(): number {\n const result = this.db\n .prepare(\n `DELETE FROM memories\n WHERE type = 'focus'\n AND expires_at IS NOT NULL\n AND expires_at < ?`,\n )\n .run(new Date().toISOString());\n return result.changes;\n }\n\n // ─── Stats ───────────────────────────────────────────\n\n stats(): MemoryStats {\n const total = (\n this.db.prepare(\"SELECT COUNT(*) as count FROM memories\").get() as { count: number }\n ).count;\n\n const byTypeRows = this.db\n .prepare(\"SELECT type, COUNT(*) as count FROM memories GROUP BY type\")\n .all() as { type: string; count: number }[];\n const byType: Record<string, number> = {};\n for (const row of byTypeRows) {\n byType[row.type] = row.count;\n }\n\n const byScopeRows = this.db\n .prepare(\"SELECT scope, COUNT(*) as count FROM memories GROUP BY scope\")\n .all() as { scope: string; count: number }[];\n const byScope: Record<string, number> = {};\n for (const row of byScopeRows) {\n byScope[row.scope] = row.count;\n }\n\n return { total, byType, byScope };\n }\n\n // ─── Cleanup ─────────────────────────────────────────\n\n close(): void {\n this.db.close();\n }\n}\n\n// ─── Internal helpers ────────────────────────────────────\n\ninterface RawMemoryRow {\n id: string;\n type: string;\n scope: string;\n content: string;\n source: string;\n tags: string;\n created_at: string;\n last_accessed_at: string;\n access_count: number;\n expires_at: string | null;\n outcome: string | null;\n run_id: string | null;\n category: string | null;\n severity: string | null;\n supersedes: string | null;\n}\n\nfunction rowToEntry(row: RawMemoryRow): MemoryEntry {\n let tags: string[] = [];\n try {\n tags = JSON.parse(row.tags);\n } catch {\n tags = [];\n }\n\n return {\n id: row.id,\n type: row.type as MemoryEntry[\"type\"],\n scope: row.scope,\n content: row.content,\n source: row.source,\n tags,\n createdAt: row.created_at,\n lastAccessedAt: row.last_accessed_at,\n accessCount: row.access_count,\n expiresAt: row.expires_at ?? undefined,\n outcome: row.outcome ?? undefined,\n runId: row.run_id ?? undefined,\n category: row.category ?? undefined,\n severity: row.severity ?? undefined,\n supersedes: row.supersedes ?? undefined,\n };\n}\n","import { z } from \"zod\";\n\nexport type { Decision, DecisionOption } from \"./decisions.js\";\n// ─── Decision schemas (re-exported for centralized access) ────\nexport {\n decisionOptionSchema,\n decisionSchema,\n} from \"./decisions.js\";\n\n// ─── Wake reason (why daemon woke from idle) ─────────────\n\nexport const wakeReasonSchema = z.enum([\"events\", \"timer\", \"active_runs\", \"forced\"]);\n\nexport type WakeReason = z.infer<typeof wakeReasonSchema>;\n\n// ─── Base supervisor fields (shared between daemon state and API status) ──\n\n/**\n * Common fields shared between supervisorDaemonStateSchema and supervisorStatusSchema.\n * Extracted to avoid duplication and ensure consistency.\n */\nconst supervisorBaseFieldsSchema = z.object({\n pid: z.number(),\n sessionId: z.string(),\n startedAt: z.string(),\n heartbeatCount: z.number(),\n totalCostUsd: z.number(),\n todayCostUsd: z.number(),\n});\n\n// ─── Daemon state (persisted in state.json) ──────────────\n\nexport const supervisorDaemonStateSchema = supervisorBaseFieldsSchema.extend({\n port: z.number(),\n cwd: z.string(),\n lastHeartbeat: z.string().optional(),\n heartbeatCount: z.number().default(0),\n totalCostUsd: z.number().default(0),\n todayCostUsd: z.number().default(0),\n costResetDate: z.string().optional(),\n idleSkipCount: z.number().default(0),\n activeWorkSkipCount: z.number().default(0),\n status: z.enum([\"running\", \"draining\", \"stopped\"]).default(\"running\"),\n lastConsolidationHeartbeat: z.number().default(0),\n lastCompactionHeartbeat: z.number().default(0),\n lastConsolidationTimestamp: z.string().optional(),\n wakeReason: wakeReasonSchema.optional(),\n});\n\nexport type SupervisorDaemonState = z.infer<typeof supervisorDaemonStateSchema>;\n\n// ─── Incoming webhook event ──────────────────────────────\n\nexport const webhookIncomingEventSchema = z.object({\n id: z.string().optional(),\n source: z.string().optional(),\n event: z.string().optional(),\n payload: z.record(z.string(), z.unknown()).optional(),\n receivedAt: z.string(),\n processedAt: z.string().optional(),\n});\n\nexport type WebhookIncomingEvent = z.infer<typeof webhookIncomingEventSchema>;\n\n// ─── TUI / external inbox message ───────────────────────\n\nexport const inboxMessageSchema = z.object({\n id: z.string(),\n from: z.enum([\"tui\", \"api\", \"external\", \"agent\"]),\n text: z.string(),\n timestamp: z.string(),\n processedAt: z.string().optional(),\n});\n\nexport type InboxMessage = z.infer<typeof inboxMessageSchema>;\n\n// ─── Activity log entry ─────────────────────────────────\n\nexport const activityEntrySchema = z.object({\n id: z.string(),\n type: z.enum([\n \"heartbeat\",\n \"decision\",\n \"action\",\n \"error\",\n \"warning\",\n \"event\",\n \"message\",\n \"thinking\",\n \"plan\",\n \"dispatch\",\n \"tool_use\",\n ]),\n summary: z.string(),\n detail: z.unknown().optional(),\n timestamp: z.string(),\n});\n\nexport type ActivityEntry = z.infer<typeof activityEntrySchema>;\n\n// ─── Log buffer entry (written by neo log, read by heartbeat) ──\n\nexport const logBufferEntrySchema = z.object({\n id: z.string(),\n type: z.enum([\"progress\", \"action\", \"decision\", \"blocker\", \"milestone\", \"discovery\"]),\n message: z.string(),\n agent: z.string().optional(),\n runId: z.string().optional(),\n repo: z.string().optional(),\n target: z.enum([\"memory\", \"knowledge\", \"digest\"]),\n timestamp: z.string(),\n consolidatedAt: z.string().optional(),\n});\n\nexport type LogBufferEntry = z.infer<typeof logBufferEntrySchema>;\n\n// ─── Internal event kinds (timer-based, not external) ────\n\nexport const internalEventKindSchema = z.enum([\"consolidation_timer\", \"active_run_check\"]);\n\nexport type InternalEventKind = z.infer<typeof internalEventKindSchema>;\n\n// ─── Supervisor status (API response) ──────────────────\n\nexport const supervisorStatusSchema = supervisorBaseFieldsSchema.extend({\n status: z.enum([\"running\", \"idle\", \"stopping\"]),\n lastHeartbeat: z.string(),\n activeRunCount: z.number(),\n recentActivitySummary: z.array(z.string()),\n});\n\nexport type SupervisorStatus = z.infer<typeof supervisorStatusSchema>;\n\n// ─── Activity query options (API query params) ─────────\n\n/**\n * Filterable activity types for API queries.\n * This is a subset of activityEntrySchema.type — only types that make sense\n * for external filtering are included. Internal types like \"heartbeat\" and\n * \"thinking\" are excluded as they're implementation details.\n */\nexport const activityTypeFilterSchema = z.enum([\n \"decision\",\n \"action\",\n \"error\",\n \"event\",\n \"message\",\n \"plan\",\n \"dispatch\",\n]);\n\nexport type ActivityTypeFilter = z.infer<typeof activityTypeFilterSchema>;\n\nexport const activityQueryOptionsSchema = z.object({\n limit: z.number().int().min(1).max(500).default(50).optional(),\n offset: z.number().int().min(0).default(0).optional(),\n type: activityTypeFilterSchema.optional(),\n since: z.string().datetime().optional(),\n until: z.string().datetime().optional(),\n});\n\nexport type ActivityQueryOptions = z.infer<typeof activityQueryOptionsSchema>;\n\n// ─── Queued event (union of all event sources) ──────────\n\nexport type QueuedEvent =\n | { kind: \"webhook\"; data: WebhookIncomingEvent }\n | { kind: \"message\"; data: InboxMessage }\n | { kind: \"run_complete\"; runId: string; timestamp: string }\n | { kind: \"internal\"; eventKind: InternalEventKind; timestamp: string };\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { ensureDir } from \"@/shared/fs\";\n\n// ─── Schemas ─────────────────────────────────────────────\n\nexport const decisionOptionSchema = z.object({\n key: z.string(),\n label: z.string(),\n description: z.string().optional(),\n});\n\nexport const decisionSchema = z.object({\n id: z.string(),\n question: z.string(),\n context: z.string().optional(),\n options: z.array(decisionOptionSchema).optional(),\n type: z.string().default(\"generic\"),\n source: z.string(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.string(),\n expiresAt: z.string().optional(),\n defaultAnswer: z.string().optional(),\n answeredAt: z.string().optional(),\n answer: z.string().optional(),\n expiredAt: z.string().optional(),\n});\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type DecisionOption = z.infer<typeof decisionOptionSchema>;\nexport type Decision = z.infer<typeof decisionSchema>;\n\nexport type DecisionInput = Omit<\n Decision,\n \"id\" | \"createdAt\" | \"answeredAt\" | \"answer\" | \"expiredAt\"\n>;\n\n// ─── Store ───────────────────────────────────────────────\n\n/**\n * JSONL-backed store for decisions.\n * Append-only with in-place updates for answers and expiration.\n */\nexport class DecisionStore {\n private readonly filePath: string;\n private readonly dir: string;\n private readonly dirCache = new Set<string>();\n\n constructor(filePath: string) {\n this.filePath = filePath;\n this.dir = path.dirname(filePath);\n }\n\n /**\n * Create a new decision and persist it.\n * @returns The generated decision ID\n */\n async create(input: DecisionInput): Promise<string> {\n await ensureDir(this.dir, this.dirCache);\n\n const id = `dec_${randomUUID().replace(/-/g, \"\").slice(0, 20)}`;\n const decision: Decision = {\n ...input,\n id,\n createdAt: new Date().toISOString(),\n };\n\n await appendFile(this.filePath, `${JSON.stringify(decision)}\\n`, \"utf-8\");\n return id;\n }\n\n /**\n * Answer a decision by ID.\n * Reads all entries, updates the matching one, and rewrites the file.\n */\n async answer(id: string, answer: string): Promise<void> {\n const decisions = await this.readAll();\n const decision = decisions.find((d) => d.id === id);\n\n if (!decision) {\n throw new Error(`Decision not found: ${id}`);\n }\n\n if (decision.answer !== undefined) {\n throw new Error(`Decision already answered: ${id}`);\n }\n\n decision.answer = answer;\n decision.answeredAt = new Date().toISOString();\n\n await this.writeAll(decisions);\n }\n\n /**\n * Get all pending decisions (unanswered, not expired, not timed out).\n */\n async pending(): Promise<Decision[]> {\n const decisions = await this.readAll();\n const now = new Date().toISOString();\n\n return decisions.filter((d) => {\n if (d.answer !== undefined) return false;\n if (d.expiredAt !== undefined) return false;\n if (d.expiresAt && d.expiresAt < now) return false;\n return true;\n });\n }\n\n /**\n * Get answered decisions, optionally filtered by timestamp.\n * @param since - ISO timestamp to filter decisions answered after this time\n */\n async answered(since?: string): Promise<Decision[]> {\n const decisions = await this.readAll();\n\n return decisions.filter((d) => {\n if (d.answer === undefined) return false;\n if (since && d.answeredAt && d.answeredAt < since) return false;\n return true;\n });\n }\n\n /**\n * Get a specific decision by ID.\n */\n async get(id: string): Promise<Decision | null> {\n const decisions = await this.readAll();\n return decisions.find((d) => d.id === id) ?? null;\n }\n\n /**\n * Auto-answer expired decisions with their defaultAnswer.\n * Decisions without defaultAnswer are marked as expired (expiredAt).\n * @returns The decisions that were auto-answered or marked expired\n */\n async expire(): Promise<Decision[]> {\n const decisions = await this.readAll();\n const now = new Date().toISOString();\n const expired: Decision[] = [];\n\n for (const decision of decisions) {\n if (\n decision.answer === undefined &&\n decision.expiredAt === undefined &&\n decision.expiresAt &&\n decision.expiresAt < now\n ) {\n if (decision.defaultAnswer !== undefined) {\n decision.answer = decision.defaultAnswer;\n decision.answeredAt = now;\n } else {\n decision.expiredAt = now;\n }\n expired.push(decision);\n }\n }\n\n if (expired.length > 0) {\n await this.writeAll(decisions);\n }\n\n return expired;\n }\n\n // ─── Private helpers ─────────────────────────────────────\n\n private async readAll(): Promise<Decision[]> {\n let content: string;\n try {\n content = await readFile(this.filePath, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n\n const decisions: Decision[] = [];\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const parsed = decisionSchema.parse(JSON.parse(line));\n decisions.push(parsed);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for parse failures\n console.warn(\n `[DecisionStore] Skipping malformed JSONL line: ${error instanceof Error ? error.message : \"unknown error\"}`,\n );\n }\n }\n\n return decisions;\n }\n\n private async writeAll(decisions: Decision[]): Promise<void> {\n await ensureDir(this.dir, this.dirCache);\n const content = `${decisions.map((d) => JSON.stringify(d)).join(\"\\n\")}\\n`;\n await writeFile(this.filePath, content, \"utf-8\");\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, readFile, rename, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ActivityEntry } from \"./schemas.js\";\n\nconst ACTIVITY_FILE = \"activity.jsonl\";\nconst MAX_SIZE_BYTES = 10 * 1024 * 1024; // 10MB rotation threshold\n\nexport class ActivityLog {\n readonly filePath: string;\n private readonly dir: string;\n\n constructor(dir: string) {\n this.dir = dir;\n this.filePath = path.join(dir, ACTIVITY_FILE);\n }\n\n /**\n * Append a structured entry to the activity log.\n * Rotates the file if it exceeds MAX_SIZE_BYTES.\n */\n async append(entry: ActivityEntry): Promise<void> {\n await this.checkRotation();\n const line = `${JSON.stringify(entry)}\\n`;\n await appendFile(this.filePath, line, \"utf-8\");\n }\n\n /**\n * Create and append a new entry with auto-generated id and timestamp.\n */\n async log(type: ActivityEntry[\"type\"], summary: string, detail?: unknown): Promise<void> {\n await this.append({\n id: randomUUID(),\n type,\n summary,\n detail,\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * Read the last N entries from the activity log.\n */\n async tail(n: number): Promise<ActivityEntry[]> {\n let content: string;\n try {\n content = await readFile(this.filePath, \"utf-8\");\n } catch {\n return [];\n }\n\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const lastLines = lines.slice(-n);\n\n const entries: ActivityEntry[] = [];\n for (const line of lastLines) {\n try {\n entries.push(JSON.parse(line) as ActivityEntry);\n } catch {\n // Skip malformed lines\n }\n }\n return entries;\n }\n\n private async checkRotation(): Promise<void> {\n try {\n const stats = await stat(this.filePath);\n if (stats.size > MAX_SIZE_BYTES) {\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const rotatedPath = path.join(this.dir, `activity-${timestamp}.jsonl`);\n await rename(this.filePath, rotatedPath);\n }\n } catch {\n // File doesn't exist yet — no rotation needed\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type { GlobalConfig } from \"@/config\";\nimport { getSupervisorDecisionsPath, getSupervisorDir } from \"@/paths\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport { ActivityLog } from \"./activity-log.js\";\nimport { DecisionStore } from \"./decisions.js\";\nimport { EventQueue } from \"./event-queue.js\";\nimport { HeartbeatLoop } from \"./heartbeat.js\";\nimport type { SupervisorDaemonState, WebhookIncomingEvent } from \"./schemas.js\";\nimport { WebhookServer } from \"./webhook-server.js\";\n\nexport interface SupervisorDaemonOptions {\n name: string;\n config: GlobalConfig;\n /** Path to bundled default SUPERVISOR.md (e.g. from @neotx/agents) */\n defaultInstructionsPath?: string | undefined;\n}\n\n/**\n * Orchestrates all supervisor components: webhook server, event queue,\n * heartbeat loop, memory, and activity logging.\n */\nexport class SupervisorDaemon {\n private readonly name: string;\n private readonly config: GlobalConfig;\n private readonly dir: string;\n private readonly defaultInstructionsPath: string | undefined;\n private webhookServer: WebhookServer | null = null;\n private eventQueue: EventQueue | null = null;\n private heartbeatLoop: HeartbeatLoop | null = null;\n private activityLog: ActivityLog | null = null;\n private decisionStore: DecisionStore | null = null;\n private sessionId = \"\";\n\n constructor(options: SupervisorDaemonOptions) {\n this.name = options.name;\n this.config = options.config;\n this.dir = getSupervisorDir(options.name);\n this.defaultInstructionsPath = options.defaultInstructionsPath;\n }\n\n async start(): Promise<void> {\n // Create supervisor directory\n await mkdir(this.dir, { recursive: true });\n\n // Check lockfile for duplicate daemons\n const lockPath = path.join(this.dir, \"daemon.lock\");\n if (existsSync(lockPath)) {\n const lockPid = await this.readLockPid(lockPath);\n if (lockPid && isProcessAlive(lockPid)) {\n throw new Error(\n `Supervisor \"${this.name}\" already running (PID ${lockPid}). Use --kill first.`,\n );\n }\n // Stale lock — clean up\n await rm(lockPath, { force: true });\n }\n\n // Write lockfile atomically\n const tempLock = `${lockPath}.${process.pid}`;\n await writeFile(tempLock, String(process.pid), \"utf-8\");\n const { rename } = await import(\"node:fs/promises\");\n await rename(tempLock, lockPath);\n\n // Recover session ID from previous state or generate new one\n const existingState = await this.readState();\n if (existingState?.sessionId && existingState.status !== \"stopped\") {\n this.sessionId = existingState.sessionId;\n } else {\n this.sessionId = randomUUID();\n }\n\n // Initialize activity log\n this.activityLog = new ActivityLog(this.dir);\n\n // Initialize decision store\n this.decisionStore = new DecisionStore(getSupervisorDecisionsPath(this.name));\n\n // Initialize event queue\n this.eventQueue = new EventQueue({\n maxEventsPerSec: this.config.supervisor.maxEventsPerSec,\n });\n\n // Replay unprocessed events from disk\n const inboxPath = path.join(this.dir, \"inbox.jsonl\");\n const eventsPath = path.join(this.dir, \"events.jsonl\");\n await this.eventQueue.replayUnprocessed(inboxPath, eventsPath);\n\n // Start file watching\n await this.eventQueue.startWatching(inboxPath, eventsPath);\n\n // Start webhook server\n this.webhookServer = new WebhookServer({\n port: this.config.supervisor.port,\n secret: this.config.supervisor.secret,\n eventsPath,\n onEvent: (event) => {\n this.eventQueue?.push({ kind: \"webhook\", data: event });\n\n // Handle decision:answer webhook events\n this.handleDecisionAnswer(event).catch((err) => {\n this.activityLog?.log(\n \"error\",\n `Failed to handle decision:answer: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n\n // Convert session:complete/session:fail webhooks into run_complete events\n // so the heartbeat gets a structured signal that a run finished\n if (\n (event.event === \"session:complete\" || event.event === \"session:fail\") &&\n event.payload\n ) {\n const runId = typeof event.payload.runId === \"string\" ? event.payload.runId : undefined;\n if (runId) {\n this.eventQueue?.push({\n kind: \"run_complete\",\n runId,\n timestamp: event.receivedAt,\n });\n }\n }\n },\n getHealth: () => this.getHealthInfo(),\n });\n await this.webhookServer.start();\n\n // Write initial state\n await this.writeState({\n pid: process.pid,\n sessionId: this.sessionId,\n port: this.config.supervisor.port,\n cwd: homedir(),\n startedAt: new Date().toISOString(),\n lastHeartbeat: existingState?.lastHeartbeat,\n heartbeatCount: existingState?.heartbeatCount ?? 0,\n totalCostUsd: existingState?.totalCostUsd ?? 0,\n todayCostUsd: existingState?.todayCostUsd ?? 0,\n costResetDate: existingState?.costResetDate,\n idleSkipCount: existingState?.idleSkipCount ?? 0,\n activeWorkSkipCount: existingState?.activeWorkSkipCount ?? 0,\n status: \"running\",\n lastConsolidationHeartbeat: existingState?.lastConsolidationHeartbeat ?? 0,\n lastCompactionHeartbeat: existingState?.lastCompactionHeartbeat ?? 0,\n lastConsolidationTimestamp: existingState?.lastConsolidationTimestamp,\n });\n\n // Install signal handlers\n const shutdown = () => {\n // biome-ignore lint/suspicious/noConsole: Intentional daemon logging for signal handler errors\n this.stop().catch(console.error);\n };\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n await this.activityLog.log(\n \"event\",\n `Supervisor \"${this.name}\" started on port ${this.config.supervisor.port}`,\n );\n\n // Start heartbeat loop (blocks until stopped)\n const statePath = path.join(this.dir, \"state.json\");\n this.heartbeatLoop = new HeartbeatLoop({\n config: this.config,\n supervisorDir: this.dir,\n statePath,\n sessionId: this.sessionId,\n eventQueue: this.eventQueue,\n activityLog: this.activityLog,\n eventsPath,\n defaultInstructionsPath: this.defaultInstructionsPath,\n });\n\n await this.heartbeatLoop.start();\n }\n\n async stop(): Promise<void> {\n this.heartbeatLoop?.stop();\n this.eventQueue?.stopWatching();\n\n if (this.webhookServer) {\n await this.webhookServer.stop();\n }\n\n // Update state\n const state = await this.readState();\n if (state) {\n state.status = \"stopped\";\n await this.writeState(state);\n }\n\n // Remove lockfile\n const lockPath = path.join(this.dir, \"daemon.lock\");\n await rm(lockPath, { force: true });\n\n if (this.activityLog) {\n await this.activityLog.log(\"event\", `Supervisor \"${this.name}\" stopped`);\n }\n }\n\n private getHealthInfo(): Record<string, unknown> {\n return {\n status: \"ok\",\n name: this.name,\n pid: process.pid,\n uptime: process.uptime(),\n sessionId: this.sessionId,\n port: this.config.supervisor.port,\n };\n }\n\n private async readState(): Promise<SupervisorDaemonState | null> {\n const statePath = path.join(this.dir, \"state.json\");\n try {\n const raw = await readFile(statePath, \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch {\n return null;\n }\n }\n\n private async writeState(state: SupervisorDaemonState): Promise<void> {\n const statePath = path.join(this.dir, \"state.json\");\n await writeFile(statePath, JSON.stringify(state, null, 2), \"utf-8\");\n }\n\n private async readLockPid(lockPath: string): Promise<number | null> {\n try {\n const raw = await readFile(lockPath, \"utf-8\");\n const pid = Number.parseInt(raw.trim(), 10);\n return Number.isNaN(pid) ? null : pid;\n } catch {\n return null;\n }\n }\n\n /**\n * Handle decision:answer webhook events.\n * Extracts decisionId and answer from the payload and records the answer.\n */\n private async handleDecisionAnswer(event: WebhookIncomingEvent): Promise<void> {\n if (event.event !== \"decision:answer\") return;\n if (!this.decisionStore || !event.payload) return;\n\n const decisionId =\n typeof event.payload.decisionId === \"string\" ? event.payload.decisionId : undefined;\n const answer = typeof event.payload.answer === \"string\" ? event.payload.answer : undefined;\n\n if (!decisionId || !answer) {\n await this.activityLog?.log(\n \"error\",\n `decision:answer webhook missing required fields (decisionId: ${decisionId}, answer: ${answer})`,\n );\n return;\n }\n\n try {\n await this.decisionStore.answer(decisionId, answer);\n await this.activityLog?.log(\n \"decision\",\n `Decision ${decisionId} answered via webhook: \"${answer}\"`,\n );\n } catch (err) {\n await this.activityLog?.log(\n \"error\",\n `Failed to answer decision ${decisionId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","import { type FSWatcher, watch } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport type { InboxMessage, QueuedEvent, WebhookIncomingEvent } from \"./schemas.js\";\n\ninterface EventQueueOptions {\n maxEventsPerSec: number;\n}\n\nexport interface GroupedMessage {\n text: string;\n from: string;\n count: number;\n}\n\nexport interface GroupedEvents {\n messages: GroupedMessage[];\n webhooks: QueuedEvent[];\n runCompletions: QueuedEvent[];\n}\n\nexport interface DrainAndGroupResult {\n grouped: GroupedEvents;\n rawEvents: QueuedEvent[];\n}\n\n/**\n * In-memory event queue with deduplication, rate limiting, and file watching.\n *\n * Accumulates events from 3 sources:\n * - Webhooks (pushed directly by WebhookServer)\n * - Inbox messages (watched from inbox.jsonl)\n * - Run completions (watched from runs directory)\n *\n * The daemon drains this queue at each heartbeat.\n */\nexport class EventQueue {\n private readonly queue: QueuedEvent[] = [];\n private readonly seenIds = new Set<string>();\n private readonly maxSeenIds = 1000;\n private readonly maxEventsPerSec: number;\n private eventCountThisSecond = 0;\n private currentSecond = 0;\n private watchers: FSWatcher[] = [];\n private fileOffsets = new Map<string, number>();\n\n /** Resolve function to wake up the heartbeat loop when an event arrives */\n private wakeUp: (() => void) | null = null;\n\n constructor(options: EventQueueOptions) {\n this.maxEventsPerSec = options.maxEventsPerSec;\n }\n\n /**\n * Push an event into the queue. Applies dedup and rate limiting.\n */\n push(event: QueuedEvent): boolean {\n // Deduplication by event ID\n const id = this.getEventId(event);\n if (id && this.seenIds.has(id)) return false;\n\n // Rate limiting\n const now = Math.floor(Date.now() / 1000);\n if (now !== this.currentSecond) {\n this.currentSecond = now;\n this.eventCountThisSecond = 0;\n }\n if (this.eventCountThisSecond >= this.maxEventsPerSec) return false;\n this.eventCountThisSecond++;\n\n // Track seen IDs (LRU-style: evict oldest when full)\n if (id) {\n this.seenIds.add(id);\n if (this.seenIds.size > this.maxSeenIds) {\n const first = this.seenIds.values().next().value;\n if (first) this.seenIds.delete(first);\n }\n }\n\n this.queue.push(event);\n this.wakeUp?.();\n return true;\n }\n\n /**\n * Drain all queued events and return them. Clears the queue.\n */\n drain(): QueuedEvent[] {\n const events = [...this.queue];\n this.queue.length = 0;\n return events;\n }\n\n /**\n * Drain and group events: deduplicates messages by content,\n * keeps webhooks and run completions separate.\n * Returns both grouped events AND original raw events for later marking as processed.\n */\n drainAndGroup(): DrainAndGroupResult {\n const rawEvents = this.drain();\n\n const messageMap = new Map<string, GroupedMessage>();\n const webhooks: QueuedEvent[] = [];\n const runCompletions: QueuedEvent[] = [];\n\n for (const event of rawEvents) {\n if (event.kind === \"message\") {\n const key = event.data.text.trim().toLowerCase();\n const existing = messageMap.get(key);\n if (existing) {\n existing.count++;\n } else {\n messageMap.set(key, { text: event.data.text, from: event.data.from, count: 1 });\n }\n } else if (event.kind === \"webhook\") {\n webhooks.push(event);\n } else {\n runCompletions.push(event);\n }\n }\n\n return {\n grouped: {\n messages: [...messageMap.values()],\n webhooks,\n runCompletions,\n },\n rawEvents,\n };\n }\n\n size(): number {\n return this.queue.length;\n }\n\n /**\n * Start watching inbox.jsonl and events.jsonl for new entries.\n * New lines are parsed and pushed into the queue.\n */\n async startWatching(inboxPath: string, eventsPath: string): Promise<void> {\n // Ensure files exist before watching — fs.watch() throws on missing files\n for (const p of [inboxPath, eventsPath]) {\n try {\n await writeFile(p, \"\", { flag: \"a\" });\n } catch {\n // Non-critical: file creation may fail due to permissions or missing parent directory.\n // watchJsonlFile will handle this gracefully by skipping the watch.\n }\n }\n this.watchJsonlFile(inboxPath, \"message\");\n this.watchJsonlFile(eventsPath, \"webhook\");\n }\n\n stopWatching(): void {\n for (const w of this.watchers) w.close();\n this.watchers = [];\n this.fileOffsets.clear();\n }\n\n /**\n * Replay unprocessed events from disk on startup.\n */\n async replayUnprocessed(inboxPath: string, eventsPath: string): Promise<void> {\n await this.replayFile(inboxPath, \"message\");\n await this.replayFile(eventsPath, \"webhook\");\n }\n\n /**\n * Returns a promise that resolves when a new event arrives or timeout is reached.\n */\n waitForEvent(timeoutMs: number): Promise<void> {\n if (this.queue.length > 0) return Promise.resolve();\n return new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n this.wakeUp = null;\n resolve();\n }, timeoutMs);\n\n this.wakeUp = () => {\n clearTimeout(timer);\n this.wakeUp = null;\n resolve();\n };\n });\n }\n\n /**\n * Interrupt any pending waitForEvent — used during shutdown.\n */\n interrupt(): void {\n this.wakeUp?.();\n }\n\n private getEventId(event: QueuedEvent): string | undefined {\n if (event.kind === \"webhook\") return event.data.id;\n if (event.kind === \"message\") return event.data.id;\n if (event.kind === \"run_complete\") return `run:${event.runId}`;\n return undefined;\n }\n\n private watchJsonlFile(filePath: string, kind: \"message\" | \"webhook\"): void {\n try {\n const watcher = watch(filePath, () => {\n // Non-critical: file may have been deleted or become unreadable between watch trigger and read\n this.readNewLines(filePath, kind).catch(() => {});\n });\n this.watchers.push(watcher);\n } catch {\n // Non-critical: file may not exist yet — watcher will be set up when file is created\n }\n }\n\n private async readNewLines(filePath: string, kind: \"message\" | \"webhook\"): Promise<void> {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (_err) {\n // Non-critical: file may not exist or be temporarily unavailable during rotation\n // Silently return — the watcher will retry on next change event\n return;\n }\n\n const offset = this.fileOffsets.get(filePath) ?? 0;\n if (content.length <= offset) return;\n\n const newContent = content.slice(offset);\n this.fileOffsets.set(filePath, content.length);\n\n const lines = newContent.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (parsed.processedAt) continue; // Already processed\n\n if (kind === \"webhook\") {\n this.push({ kind: \"webhook\", data: parsed as unknown as WebhookIncomingEvent });\n } else {\n this.push({ kind: \"message\", data: parsed as unknown as InboxMessage });\n }\n } catch (_err) {\n // Non-critical: skip malformed JSON lines (may be partial writes or corrupted entries)\n }\n }\n }\n\n private async replayFile(filePath: string, kind: \"message\" | \"webhook\"): Promise<void> {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (_err) {\n // Non-critical on replay: file may not exist yet on first startup\n // Events will be captured when file is created and watcher triggers\n return;\n }\n\n // Set offset so watcher doesn't re-read\n this.fileOffsets.set(filePath, content.length);\n\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const unprocessed: string[] = [];\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (parsed.processedAt) continue;\n\n if (kind === \"webhook\") {\n this.push({ kind: \"webhook\", data: parsed as unknown as WebhookIncomingEvent });\n } else {\n this.push({ kind: \"message\", data: parsed as unknown as InboxMessage });\n }\n unprocessed.push(line);\n } catch (_err) {\n // Non-critical: skip malformed JSON lines during replay (may be partial writes)\n }\n }\n }\n\n /**\n * Mark events as processed by rewriting the source files.\n */\n async markProcessed(inboxPath: string, eventsPath: string, events: QueuedEvent[]): Promise<void> {\n const now = new Date().toISOString();\n\n for (const event of events) {\n if (event.kind === \"webhook\") {\n await this.markInFile(eventsPath, event.data.receivedAt, now);\n } else if (event.kind === \"message\") {\n await this.markInFile(inboxPath, event.data.timestamp, now);\n }\n }\n }\n\n private async markInFile(\n filePath: string,\n matchTimestamp: string,\n processedAt: string,\n ): Promise<void> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n let changed = false;\n\n const updated = lines.map((line) => {\n if (!line.trim()) return line;\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (\n (parsed.receivedAt === matchTimestamp || parsed.timestamp === matchTimestamp) &&\n !parsed.processedAt\n ) {\n parsed.processedAt = processedAt;\n changed = true;\n return JSON.stringify(parsed);\n }\n } catch (_err) {\n // Non-critical: keep malformed lines as-is (manual edits or corruption)\n }\n return line;\n });\n\n if (changed) {\n await writeFile(filePath, updated.join(\"\\n\"), \"utf-8\");\n this.fileOffsets.set(filePath, updated.join(\"\\n\").length);\n }\n } catch {\n // Non-critical: marking as processed may fail but events are already handled.\n // Worst case: duplicate processing on restart (idempotent operations).\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport { ConfigStore, ConfigWatcher, type GlobalConfig } from \"@/config\";\nimport { getDataDir, getRunsDir } from \"@/paths\";\nimport {\n isAssistantMessage,\n isInitMessage,\n isResultMessage,\n isToolResultMessage,\n isToolUseMessage,\n type SDKStreamMessage,\n} from \"@/sdk-types\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport type { PersistedRun } from \"@/types\";\nimport type { ActivityLog } from \"./activity-log.js\";\nimport { type Decision, DecisionStore } from \"./decisions.js\";\nimport type { EventQueue, GroupedEvents } from \"./event-queue.js\";\nimport { type IdleContext, IdleDetector } from \"./idle-detector.js\";\nimport { compactLogBuffer, markConsolidated, readUnconsolidated } from \"./log-buffer.js\";\nimport type { MemoryEntry } from \"./memory/entry.js\";\nimport { MemoryStore } from \"./memory/store.js\";\nimport {\n buildCompactionPrompt,\n buildConsolidationPrompt,\n buildIdlePrompt,\n buildStandardPrompt,\n isIdleHeartbeat,\n} from \"./prompt-builder.js\";\nimport type { LogBufferEntry, QueuedEvent, SupervisorDaemonState } from \"./schemas.js\";\nimport {\n type HeartbeatEvent,\n heartbeatEventSchema,\n type RunCompletedEvent,\n type RunDispatchedEvent,\n runCompletedEventSchema,\n runDispatchedEventSchema,\n type SupervisorStartedEvent,\n type SupervisorStoppedEvent,\n type SupervisorWebhookEvent,\n supervisorStartedEventSchema,\n supervisorStoppedEventSchema,\n} from \"./webhookEvents.js\";\n\n/** Consolidation runs every N heartbeats */\nconst DEFAULT_CONSOLIDATION_INTERVAL = 5;\n\n// ─── Consolidation logic ────────────────────────────────\n\n/**\n * Determine whether this heartbeat should be a consolidation cycle.\n * Consolidation runs every `consolidationInterval` heartbeats,\n * or earlier if there are pending unconsolidated entries (after at least 2 heartbeats).\n */\nexport function shouldConsolidate(\n heartbeatCount: number,\n lastConsolidationHeartbeat: number,\n consolidationInterval: number,\n hasPendingEntries: boolean,\n): boolean {\n const since = heartbeatCount - lastConsolidationHeartbeat;\n if (since >= consolidationInterval) return true;\n if (hasPendingEntries && since >= 2) return true;\n return false;\n}\n\n/**\n * Determine whether this heartbeat should run compaction.\n * Compaction is a deep cleanup pass that runs every ~50 heartbeats.\n */\nexport function shouldCompact(\n heartbeatCount: number,\n lastCompactionHeartbeat: number,\n compactionInterval = 50,\n): boolean {\n const since = heartbeatCount - lastCompactionHeartbeat;\n return since >= compactionInterval;\n}\n\n/** Grace period before a run without PID can be considered stale (ms). */\nexport const STALE_GRACE_PERIOD_MS = 30_000;\n\n/**\n * Determine if a persisted run is actually active (not stale).\n *\n * For \"running\" status, validates:\n * - If PID exists and process is alive → active\n * - If PID exists but process is dead → stale (ghost run)\n * - If no PID and within grace period → active (still starting up)\n * - If no PID and past grace period → stale (ghost run)\n *\n * For \"paused\" status: always considered active (waiting for user action).\n */\nexport function isRunActive(\n run: PersistedRun,\n isAlive: (pid: number) => boolean = isProcessAlive,\n now: number = Date.now(),\n): boolean {\n // Skip non-active statuses\n if (run.status !== \"running\" && run.status !== \"paused\") {\n return false;\n }\n\n // Paused runs are always considered active (waiting for user action)\n if (run.status === \"paused\") {\n return true;\n }\n\n // For running status, validate the run is actually alive\n // If PID exists and process is alive, it's active\n if (run.pid && isAlive(run.pid)) {\n return true;\n }\n\n // If PID exists but process is dead, it's a stale ghost run\n if (run.pid) {\n return false;\n }\n\n // No PID: check grace period (run may still be starting up)\n const ageMs = now - new Date(run.createdAt).getTime();\n\n return ageMs < STALE_GRACE_PERIOD_MS;\n}\n\n// ─── Helper types for runHeartbeat refactoring ───────────\n\ninterface BudgetCheckResult {\n todayCost: number;\n exceeded: boolean;\n}\n\ninterface SkipLogicInput {\n state: SupervisorDaemonState | null;\n totalEventCount: number;\n activeRuns: string[];\n hasPendingConsolidation: boolean;\n hasExpiredDecisions: boolean;\n}\n\ninterface SkipLogicResult {\n shouldSkip: boolean;\n resetCounters: boolean;\n}\n\ninterface HeartbeatModeResult {\n isConsolidation: boolean;\n isCompaction: boolean;\n unconsolidated: LogBufferEntry[];\n heartbeatCount: number;\n lastConsolidationTs: string | undefined;\n}\n\ninterface StateUpdateResult {\n stateUpdate: Partial<SupervisorDaemonState>;\n}\n\n// ─── HeartbeatLoop ───────────────────────────────────────\n\n/** Callback for emitting webhook events */\nexport type WebhookEventEmitter = (event: SupervisorWebhookEvent) => void | Promise<void>;\n\nexport interface HeartbeatLoopOptions {\n config: GlobalConfig;\n supervisorDir: string;\n statePath: string;\n sessionId: string;\n eventQueue: EventQueue;\n activityLog: ActivityLog;\n /** Path to the inbox/events directory for markProcessed() calls */\n eventsPath: string;\n /** Path to bundled default SUPERVISOR.md (e.g. from @neotx/agents) */\n defaultInstructionsPath?: string | undefined;\n memoryDbPath?: string | undefined;\n /** Optional callback to emit webhook events at lifecycle points */\n onWebhookEvent?: WebhookEventEmitter | undefined;\n /** Repository path for config watching (enables hot-reload) */\n repoPath?: string | undefined;\n /** Debounce time in ms for config file changes (default: 500) */\n configWatcherDebounceMs?: number | undefined;\n}\n\n/**\n * The core autonomous loop. At each iteration:\n * 1. Drain events from the queue\n * 2. Read log buffer entries\n * 3. Determine standard vs consolidation mode\n * 4. Build the appropriate prompt\n * 5. Call sdk.query() for Claude to reason and act\n * 6. Mark entries consolidated and compact log buffer (consolidation only)\n * 7. Log activity\n * 8. Wait for the next event or idle timeout\n */\nexport class HeartbeatLoop {\n private stopping = false;\n private consecutiveFailures = 0;\n private activeAbort: AbortController | null = null;\n private config: GlobalConfig;\n private readonly supervisorDir: string;\n private readonly statePath: string;\n private sessionId: string;\n private readonly eventQueue: EventQueue;\n private readonly activityLog: ActivityLog;\n private readonly _eventsPath: string;\n\n private customInstructions: string | undefined;\n private readonly defaultInstructionsPath: string | undefined;\n private memoryStore: MemoryStore | null = null;\n private readonly memoryDbPath: string | undefined;\n private readonly onWebhookEvent: WebhookEventEmitter | undefined;\n private decisionStore: DecisionStore | null = null;\n\n /** ConfigWatcher for hot-reload support */\n private configWatcher: ConfigWatcher | null = null;\n private configStore: ConfigStore | null = null;\n private readonly repoPath: string | undefined;\n private readonly configWatcherDebounceMs: number | undefined;\n\n constructor(options: HeartbeatLoopOptions) {\n this.config = options.config;\n this.supervisorDir = options.supervisorDir;\n this.statePath = options.statePath;\n this.sessionId = options.sessionId;\n this.eventQueue = options.eventQueue;\n this.activityLog = options.activityLog;\n this._eventsPath = options.eventsPath;\n this.defaultInstructionsPath = options.defaultInstructionsPath;\n this.memoryDbPath = options.memoryDbPath;\n this.onWebhookEvent = options.onWebhookEvent;\n this.repoPath = options.repoPath;\n this.configWatcherDebounceMs = options.configWatcherDebounceMs;\n }\n\n /** Path to the inbox/events directory for markProcessed() calls */\n get eventsPath(): string {\n return this._eventsPath;\n }\n\n private getMemoryStore(): MemoryStore | null {\n if (!this.memoryStore && this.memoryDbPath) {\n try {\n this.memoryStore = new MemoryStore(this.memoryDbPath);\n } catch {\n // Memory store unavailable — continue without it\n }\n }\n return this.memoryStore;\n }\n\n private getDecisionStore(): DecisionStore {\n if (!this.decisionStore) {\n this.decisionStore = new DecisionStore(path.join(this.supervisorDir, \"decisions.jsonl\"));\n }\n return this.decisionStore;\n }\n\n async start(): Promise<void> {\n this.customInstructions = await this.loadInstructions();\n\n // Initialize and start config watcher for hot-reload\n await this.initConfigWatcher();\n\n await this.activityLog.log(\"heartbeat\", \"Supervisor heartbeat loop started\");\n await this.emitSupervisorStarted();\n\n while (!this.stopping) {\n try {\n await this.runHeartbeat();\n this.consecutiveFailures = 0;\n } catch (error) {\n this.consecutiveFailures++;\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Heartbeat failed: ${msg}`, { error: msg });\n\n // Circuit breaker: exponential backoff after consecutive failures\n if (this.consecutiveFailures >= this.config.supervisor.maxConsecutiveFailures) {\n const backoffMs = Math.min(\n this.config.supervisor.eventTimeoutMs *\n 2 ** (this.consecutiveFailures - this.config.supervisor.maxConsecutiveFailures),\n 15 * 60 * 1000, // max 15 minutes\n );\n await this.activityLog.log(\n \"error\",\n `Circuit breaker: backing off ${Math.round(backoffMs / 1000)}s after ${this.consecutiveFailures} failures`,\n );\n await this.sleep(backoffMs);\n continue;\n }\n }\n\n if (this.stopping) break;\n\n // Wait for next event or idle timeout\n await this.eventQueue.waitForEvent(this.config.supervisor.eventTimeoutMs);\n }\n\n await this.emitSupervisorStopped(\"shutdown\");\n await this.activityLog.log(\"heartbeat\", \"Supervisor heartbeat loop stopped\");\n }\n\n stop(): void {\n this.stopping = true;\n this.activeAbort?.abort(new Error(\"Supervisor shutting down\"));\n this.eventQueue.interrupt();\n\n // Stop config watcher\n if (this.configWatcher) {\n this.configWatcher.stop();\n this.configWatcher = null;\n }\n }\n\n /**\n * Initialize and start the ConfigWatcher for hot-reload support.\n * Subscribes to config file changes and logs reload events.\n */\n private async initConfigWatcher(): Promise<void> {\n // Create a ConfigStore for the watcher\n this.configStore = new ConfigStore(this.repoPath);\n await this.configStore.load();\n\n // Build options only with defined values to satisfy exactOptionalPropertyTypes\n const watcherOptions =\n this.configWatcherDebounceMs !== undefined\n ? { debounceMs: this.configWatcherDebounceMs }\n : undefined;\n\n this.configWatcher = new ConfigWatcher(this.configStore, watcherOptions);\n\n // Subscribe to config changes\n this.configWatcher.on(\"change\", () => {\n this.handleConfigChange();\n });\n\n this.configWatcher.start();\n await this.activityLog.log(\"event\", \"ConfigWatcher started for hot-reload\");\n }\n\n /**\n * Handle config file changes. Propagates reloaded config to the running\n * loop and triggers an immediate heartbeat.\n */\n private handleConfigChange(): void {\n // Propagate reloaded config to the running loop\n if (this.configStore) {\n this.config = this.configStore.getAll();\n }\n\n // Log the config change\n this.activityLog.log(\"event\", \"Configuration reloaded (hot-reload)\").catch(() => {\n // Non-critical — logging errors should not crash the loop\n });\n\n // Interrupt the event queue wait to trigger an immediate heartbeat\n // This ensures the supervisor reacts quickly to config changes\n this.eventQueue.interrupt();\n }\n\n private async runHeartbeat(): Promise<void> {\n const startTime = Date.now();\n const heartbeatId = randomUUID();\n const state = await this.readState();\n const today = new Date().toISOString().slice(0, 10);\n\n // Check budget and return early if exceeded\n const budgetCheck = await this.checkBudgetExceeded(state, today);\n if (budgetCheck.exceeded) return;\n\n // Drain events and check for active work\n const { grouped, rawEvents } = this.eventQueue.drainAndGroup();\n const totalEventCount =\n grouped.messages.length + grouped.webhooks.length + grouped.runCompletions.length;\n const activeRuns = await this.getActiveRuns();\n\n // Process decision answers from inbox messages\n const decisionStore = this.getDecisionStore();\n await this.processDecisionAnswers(rawEvents, decisionStore);\n\n // Auto-answer expired decisions\n const expiredDecisions = await decisionStore.expire();\n const hasExpiredDecisions = expiredDecisions.length > 0;\n\n // Get pending and recently answered decisions for prompt context (only in autoDecide mode)\n const pendingDecisions = this.config.supervisor.autoDecide ? await decisionStore.pending() : [];\n const answeredDecisions = this.config.supervisor.autoDecide\n ? await decisionStore.answered(state?.lastHeartbeat)\n : [];\n\n // Check for pending consolidation entries\n const unconsolidatedEntries = await readUnconsolidated(this.supervisorDir);\n const hasPendingConsolidation = unconsolidatedEntries.length > 0;\n\n // Handle skip logic for idle/active-work scenarios\n const skipResult = await this.handleSkipLogic({\n state,\n totalEventCount,\n activeRuns,\n hasPendingConsolidation,\n hasExpiredDecisions,\n });\n if (skipResult.shouldSkip) return;\n if (skipResult.resetCounters) {\n await this.updateState({ idleSkipCount: 0, activeWorkSkipCount: 0 });\n }\n\n // Determine heartbeat mode\n const modeResult = await this.determineHeartbeatMode(state);\n\n // Build prompt and log start\n const { prompt, modeLabel } = await this.buildHeartbeatModePrompt({\n grouped,\n todayCost: budgetCheck.todayCost,\n heartbeatCount: modeResult.heartbeatCount,\n unconsolidated: modeResult.unconsolidated,\n isCompaction: modeResult.isCompaction,\n isConsolidation: modeResult.isConsolidation,\n activeRuns,\n pendingDecisions,\n answeredDecisions,\n lastHeartbeat: state?.lastHeartbeat,\n lastConsolidationTimestamp: modeResult.lastConsolidationTs,\n });\n await this.activityLog.log(\n \"heartbeat\",\n `Heartbeat #${modeResult.heartbeatCount} starting (${modeLabel})`,\n {\n heartbeatId,\n eventCount: totalEventCount,\n messages: grouped.messages.length,\n webhooks: grouped.webhooks.length,\n runCompletions: grouped.runCompletions.length,\n isConsolidation: modeResult.isConsolidation,\n },\n );\n\n // Call SDK with timeout + shutdown abort\n const { costUsd, turnCount } = await this.callSdk(prompt, heartbeatId);\n\n // Warn if SDK stream completed without any turns — indicates silent timeout\n if (turnCount === 0) {\n await this.activityLog.log(\n \"warning\",\n `Heartbeat #${modeResult.heartbeatCount} completed with turnCount=0. SDK stream may have timed out before any turns completed.`,\n { heartbeatId },\n );\n }\n\n // Mark events as processed so they are not replayed on restart\n if (rawEvents.length > 0) {\n const inboxPath = path.join(this.supervisorDir, \"inbox.jsonl\");\n await this.eventQueue.markProcessed(inboxPath, this.eventsPath, rawEvents);\n }\n\n // Post-response: mark entries consolidated and compact log buffer\n if (modeResult.isConsolidation) {\n const allIds = modeResult.unconsolidated.map((e) => e.id);\n if (allIds.length > 0) {\n await markConsolidated(this.supervisorDir, allIds);\n }\n await compactLogBuffer(this.supervisorDir);\n }\n\n // Build and apply state update\n const durationMs = Date.now() - startTime;\n const { stateUpdate } = this.buildStateUpdate({\n state,\n today,\n todayCost: budgetCheck.todayCost,\n costUsd,\n heartbeatCount: modeResult.heartbeatCount,\n isConsolidation: modeResult.isConsolidation,\n isCompaction: modeResult.isCompaction,\n });\n await this.updateState(stateUpdate);\n\n await this.activityLog.log(\n \"heartbeat\",\n `Heartbeat #${modeResult.heartbeatCount + 1} complete (${modeLabel})`,\n {\n heartbeatId,\n costUsd,\n durationMs,\n turnCount,\n isConsolidation: modeResult.isConsolidation,\n },\n );\n\n // Emit heartbeat completed webhook event\n await this.emitHeartbeatCompleted({\n heartbeatNumber: modeResult.heartbeatCount + 1,\n runsActive: activeRuns.length,\n todayUsd: budgetCheck.todayCost + costUsd,\n limitUsd: this.config.supervisor.dailyCapUsd,\n });\n\n // Emit run completed events for any run completions processed\n for (const event of rawEvents) {\n if (event.kind === \"run_complete\") {\n const runData = await this.readPersistedRun(event.runId);\n const emitOpts: Parameters<typeof this.emitRunCompleted>[0] = {\n runId: event.runId,\n status: runData?.status === \"failed\" ? \"failed\" : \"completed\",\n costUsd: runData?.totalCostUsd ?? 0,\n durationMs: runData?.durationMs ?? 0,\n };\n if (runData?.output) {\n emitOpts.output = runData.output;\n }\n await this.emitRunCompleted(emitOpts);\n }\n }\n }\n\n /**\n * Check if supervisor daily budget is exceeded.\n */\n private async checkBudgetExceeded(\n state: SupervisorDaemonState | null,\n today: string,\n ): Promise<BudgetCheckResult> {\n const todayCost = state?.costResetDate === today ? (state.todayCostUsd ?? 0) : 0;\n\n if (todayCost >= this.config.supervisor.dailyCapUsd) {\n await this.activityLog.log(\n \"error\",\n `Supervisor daily budget exceeded ($${todayCost.toFixed(2)} / $${this.config.supervisor.dailyCapUsd}). Skipping heartbeat.`,\n );\n await this.sleep(this.config.supervisor.eventTimeoutMs);\n return { todayCost, exceeded: true };\n }\n\n return { todayCost, exceeded: false };\n }\n\n /**\n * Handle skip logic for idle and active-work scenarios.\n * Uses IdleDetector to make skip decisions based on context.\n */\n private async handleSkipLogic(opts: SkipLogicInput): Promise<SkipLogicResult> {\n const { state, totalEventCount, activeRuns, hasPendingConsolidation, hasExpiredDecisions } =\n opts;\n const idleSkipCount = state?.idleSkipCount ?? 0;\n const activeWorkSkipCount = state?.activeWorkSkipCount ?? 0;\n const hasActiveWork = activeRuns.length > 0;\n\n // Calculate time since last heartbeat\n const lastHeartbeatMs = state?.lastHeartbeat\n ? new Date(state.lastHeartbeat).getTime()\n : Date.now();\n const timeSinceLastHeartbeatMs = Date.now() - lastHeartbeatMs;\n\n // Build context for IdleDetector\n const context: IdleContext = {\n eventCount: totalEventCount,\n activeRuns: activeRuns.length,\n hasPendingConsolidation,\n hasExpiredDecisions,\n timeSinceLastHeartbeatMs,\n idleSkipCount,\n activeWorkSkipCount,\n };\n\n // Create detector with current config values\n const detector = new IdleDetector({\n idleSkipMax: this.config.supervisor.idleSkipMax,\n activeWorkSkipMax: this.config.supervisor.activeWorkSkipMax,\n });\n\n const result = detector.shouldSkip(context);\n\n if (result.shouldSkip) {\n // Update skip counters based on whether there's active work\n if (hasActiveWork) {\n await this.updateState({\n activeWorkSkipCount: activeWorkSkipCount + 1,\n idleSkipCount: 0,\n });\n await this.activityLog.log(\n \"heartbeat\",\n `Active-work skip #${activeWorkSkipCount + 1}/${this.config.supervisor.activeWorkSkipMax} — ${result.reason}`,\n );\n } else {\n await this.updateState({\n idleSkipCount: idleSkipCount + 1,\n activeWorkSkipCount: 0,\n });\n await this.activityLog.log(\n \"heartbeat\",\n `Idle skip #${idleSkipCount + 1}/${this.config.supervisor.idleSkipMax} — ${result.reason}`,\n );\n }\n return { shouldSkip: true, resetCounters: false };\n }\n\n const needsReset = idleSkipCount > 0 || activeWorkSkipCount > 0;\n return { shouldSkip: false, resetCounters: needsReset };\n }\n\n /**\n * Determine heartbeat mode: compaction > consolidation > standard.\n */\n private async determineHeartbeatMode(\n state: SupervisorDaemonState | null,\n ): Promise<HeartbeatModeResult> {\n const heartbeatCount = state?.heartbeatCount ?? 0;\n const lastConsolidation = state?.lastConsolidationHeartbeat ?? 0;\n const lastCompaction = state?.lastCompactionHeartbeat ?? 0;\n const lastConsolidationTs = state?.lastConsolidationTimestamp;\n const unconsolidated = await readUnconsolidated(this.supervisorDir);\n\n const hasNewEntriesSinceLastConsolidation = lastConsolidationTs\n ? unconsolidated.some((e) => e.timestamp > lastConsolidationTs)\n : unconsolidated.length > 0;\n\n const hasPendingEntries = unconsolidated.length > 0;\n const isCompaction = shouldCompact(heartbeatCount, lastCompaction);\n const wouldConsolidate = shouldConsolidate(\n heartbeatCount,\n lastConsolidation,\n DEFAULT_CONSOLIDATION_INTERVAL,\n hasPendingEntries,\n );\n const isConsolidation =\n isCompaction || (wouldConsolidate && hasNewEntriesSinceLastConsolidation);\n\n return {\n isConsolidation,\n isCompaction,\n unconsolidated,\n heartbeatCount,\n lastConsolidationTs,\n };\n }\n\n /**\n * Build the state update object after heartbeat completion.\n */\n private buildStateUpdate(opts: {\n state: SupervisorDaemonState | null;\n today: string;\n todayCost: number;\n costUsd: number;\n heartbeatCount: number;\n isConsolidation: boolean;\n isCompaction: boolean;\n }): StateUpdateResult {\n const stateUpdate: Partial<SupervisorDaemonState> = {\n sessionId: this.sessionId,\n lastHeartbeat: new Date().toISOString(),\n heartbeatCount: opts.heartbeatCount + 1,\n totalCostUsd: (opts.state?.totalCostUsd ?? 0) + opts.costUsd,\n todayCostUsd: opts.todayCost + opts.costUsd,\n costResetDate: opts.today,\n };\n\n if (opts.isConsolidation) {\n stateUpdate.lastConsolidationHeartbeat = opts.heartbeatCount + 1;\n stateUpdate.lastConsolidationTimestamp = new Date().toISOString();\n }\n\n if (opts.isCompaction) {\n stateUpdate.lastCompactionHeartbeat = opts.heartbeatCount + 1;\n }\n\n return { stateUpdate };\n }\n\n /**\n * Build the prompt for the current heartbeat mode.\n */\n private async buildHeartbeatModePrompt(opts: {\n grouped: GroupedEvents;\n todayCost: number;\n heartbeatCount: number;\n unconsolidated: LogBufferEntry[];\n isCompaction: boolean;\n isConsolidation: boolean;\n activeRuns: string[];\n pendingDecisions: Decision[];\n answeredDecisions: Decision[];\n lastHeartbeat: string | undefined;\n lastConsolidationTimestamp: string | undefined;\n }): Promise<{ prompt: string; modeLabel: string }> {\n const mcpServerNames = this.config.mcpServers ? Object.keys(this.config.mcpServers) : [];\n const store = this.getMemoryStore();\n const memories: MemoryEntry[] = store ? store.query({ limit: 40, sortBy: \"relevance\" }) : [];\n const recentActions = await this.activityLog.tail(20);\n const sharedOpts = {\n repos: this.config.repos,\n grouped: opts.grouped,\n budgetStatus: {\n todayUsd: opts.todayCost,\n capUsd: this.config.supervisor.dailyCapUsd,\n remainingPct:\n ((this.config.supervisor.dailyCapUsd - opts.todayCost) /\n this.config.supervisor.dailyCapUsd) *\n 100,\n },\n activeRuns: opts.activeRuns,\n heartbeatCount: opts.heartbeatCount,\n mcpServerNames,\n customInstructions: this.customInstructions,\n supervisorDir: this.supervisorDir,\n memories,\n recentActions,\n pendingDecisions: opts.pendingDecisions,\n answeredDecisions: opts.answeredDecisions,\n autoDecide: this.config.supervisor.autoDecide,\n };\n\n if (opts.isCompaction) {\n return {\n prompt: buildCompactionPrompt({\n ...sharedOpts,\n lastConsolidationTimestamp: opts.lastConsolidationTimestamp,\n }),\n modeLabel: \"compaction\",\n };\n }\n\n if (opts.isConsolidation) {\n return {\n prompt: buildConsolidationPrompt({\n ...sharedOpts,\n lastConsolidationTimestamp: opts.lastConsolidationTimestamp,\n }),\n modeLabel: \"consolidation\",\n };\n }\n\n if (isIdleHeartbeat(sharedOpts)) {\n return {\n prompt: buildIdlePrompt(sharedOpts),\n modeLabel: \"idle\",\n };\n }\n\n return {\n prompt: buildStandardPrompt(sharedOpts),\n modeLabel: \"standard\",\n };\n }\n\n /**\n * Call the Claude SDK and stream results.\n *\n * Uses Promise.race to enable non-blocking abort detection. The standard\n * `for await (const message of stream)` pattern only checks the abort signal\n * AFTER each yield — if the SDK hangs (no messages), the abort never executes.\n * This implementation races each iterator.next() against an abort promise,\n * allowing immediate response to shutdown/timeout signals.\n */\n private async callSdk(\n prompt: string,\n heartbeatId: string,\n ): Promise<{ output: string; costUsd: number; turnCount: number }> {\n const abortController = new AbortController();\n this.activeAbort = abortController;\n const timeout = setTimeout(() => {\n abortController.abort(new Error(\"Heartbeat timeout exceeded\"));\n }, this.config.supervisor.heartbeatTimeoutMs);\n\n let output = \"\";\n let costUsd = 0;\n let turnCount = 0;\n\n try {\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\");\n\n // Build allowed tools list — include MCP tool patterns for configured servers\n const allowedTools: string[] = [\"Bash\", \"Read\"];\n if (this.config.mcpServers) {\n for (const name of Object.keys(this.config.mcpServers)) {\n allowedTools.push(`mcp__${name}__*`);\n }\n }\n\n const queryOptions: Record<string, unknown> = {\n cwd: homedir(),\n allowedTools,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n mcpServers: this.config.mcpServers ?? {},\n // Don't persist session history — each heartbeat is a fresh conversation.\n // Without this, supervisor restarts could replay old messages.\n persistSession: false,\n };\n\n const stream = sdk.query({ prompt, options: queryOptions as never });\n\n // Create abort promise that resolves when signal fires\n const abortPromise = new Promise<{ aborted: true }>((resolve) => {\n if (abortController.signal.aborted) {\n resolve({ aborted: true });\n return;\n }\n abortController.signal.addEventListener(\"abort\", () => resolve({ aborted: true }), {\n once: true,\n });\n });\n\n // Use Promise.race pattern for abortable stream iteration\n const iterator = stream[Symbol.asyncIterator]();\n try {\n while (true) {\n const raceResult = await Promise.race([iterator.next(), abortPromise]);\n\n // Check if abort triggered\n if (\"aborted\" in raceResult) {\n await this.activityLog.log(\"heartbeat\", \"Heartbeat aborted\", { heartbeatId });\n break;\n }\n\n // Normal iterator result\n const iterResult = raceResult as IteratorResult<unknown>;\n if (iterResult.done) break;\n\n const msg = iterResult.value as SDKStreamMessage;\n\n if (isInitMessage(msg)) {\n this.sessionId = msg.session_id;\n }\n\n if (isResultMessage(msg)) {\n output = msg.result ?? \"\";\n costUsd = msg.total_cost_usd ?? 0;\n turnCount = msg.num_turns ?? 0;\n }\n\n await this.logStreamMessage(msg, heartbeatId);\n }\n } finally {\n // Properly cleanup iterator when done or aborted\n await iterator.return?.();\n }\n } finally {\n clearTimeout(timeout);\n this.activeAbort = null;\n }\n\n return { output, costUsd, turnCount };\n }\n\n private async readState(): Promise<SupervisorDaemonState | null> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch {\n return null;\n }\n }\n\n private async updateState(updates: Partial<SupervisorDaemonState>): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const state = JSON.parse(raw) as SupervisorDaemonState;\n Object.assign(state, updates);\n await writeFile(this.statePath, JSON.stringify(state, null, 2), \"utf-8\");\n } catch {\n // Non-critical\n }\n }\n\n /**\n * Read persisted run files and return summaries of active (running/paused) runs.\n * Validates that \"running\" runs are actually alive by checking their PID.\n * Stale runs (dead PID past grace period) are filtered out to prevent ghost runs.\n */\n private async getActiveRuns(): Promise<string[]> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return [];\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n const active: string[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const subDir = path.join(runsDir, entry.name);\n const files = await readdir(subDir);\n\n for (const f of files) {\n if (!f.endsWith(\".json\")) continue;\n try {\n const raw = await readFile(path.join(subDir, f), \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n\n if (isRunActive(run)) {\n active.push(\n `${run.runId} [${run.status}] ${run.agent} on ${path.basename(run.repo)}`,\n );\n }\n } catch {\n // Corrupted or partial file — skip\n }\n }\n }\n\n return active;\n } catch {\n return [];\n }\n }\n\n /**\n * Load custom instructions from SUPERVISOR.md.\n * Resolution order:\n * 1. Explicit path via `supervisor.instructions` in config\n * 2. User default: ~/.neo/SUPERVISOR.md\n * 3. Bundled default from @neotx/agents (if path provided)\n */\n private async loadInstructions(): Promise<string | undefined> {\n const candidates: string[] = [];\n\n if (this.config.supervisor.instructions) {\n candidates.push(path.resolve(this.config.supervisor.instructions));\n }\n\n candidates.push(path.join(getDataDir(), \"SUPERVISOR.md\"));\n\n if (this.defaultInstructionsPath) {\n candidates.push(this.defaultInstructionsPath);\n }\n\n for (const filePath of candidates) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n await this.activityLog.log(\"event\", `Loaded instructions from ${filePath}`);\n return content;\n } catch {\n // File not found — try next candidate\n }\n }\n\n return undefined;\n }\n\n /** Route a single SDK stream message to the appropriate log handler. */\n private async logStreamMessage(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (isAssistantMessage(msg)) {\n await this.logContentBlocks(msg, heartbeatId);\n } else if (isToolUseMessage(msg)) {\n await this.logToolUse(msg, heartbeatId);\n } else if (isToolResultMessage(msg)) {\n await this.logToolResult(msg, heartbeatId);\n }\n }\n\n /** Log thinking and plan blocks from assistant content — no truncation. */\n private async logContentBlocks(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (!isAssistantMessage(msg)) return;\n const content = msg.message?.content;\n if (!content) return;\n\n for (const block of content) {\n if (block.type === \"thinking\" && block.thinking) {\n await this.activityLog.log(\"thinking\", block.thinking, { heartbeatId });\n }\n if (block.type === \"text\" && block.text) {\n await this.activityLog.log(\"plan\", block.text, { heartbeatId });\n break; // Only log first text block per message\n }\n }\n }\n\n /** Log tool use events — distinguish MCP tools from built-in tools. */\n private async logToolUse(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (!isToolUseMessage(msg)) return;\n const toolName = msg.tool;\n const isMcp = toolName.startsWith(\"mcp__\");\n await this.activityLog.log(\n isMcp ? \"tool_use\" : \"action\",\n isMcp ? toolName : `Tool use: ${toolName}`,\n { heartbeatId, tool: toolName, input: msg.input },\n );\n }\n\n /** Detect agent dispatches from bash tool results. */\n private async logToolResult(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (!isToolResultMessage(msg)) return;\n const result = msg.result ?? \"\";\n const runMatch = /Run\\s+(\\S+)\\s+dispatched/i.exec(result);\n const runId = runMatch?.[1];\n if (runId) {\n await this.activityLog.log(\"dispatch\", `Agent dispatched: ${runId}`, {\n heartbeatId,\n runId,\n });\n\n // Emit run dispatched webhook event\n // Extract additional info from the result if available.\n //\n // Expected tool result formats from `neo run` command output:\n // - \"Run <runId> dispatched\"\n // - \"agent: <name>\" or \"Agent: <name>\" or \"agent <name>\"\n // - \"repo: <path>\" or \"Repo: <path>\" or \"repo <path>\"\n // - \"branch: <name>\" or \"Branch: <name>\" or \"branch <name>\"\n //\n // These patterns are best-effort extraction. If the format changes,\n // values will default to \"unknown\" without breaking the event emission.\n const agentMatch = /agent[:\\s]+(\\S+)/i.exec(result);\n const repoMatch = /repo[:\\s]+(\\S+)/i.exec(result);\n const branchMatch = /branch[:\\s]+(\\S+)/i.exec(result);\n\n const agent = agentMatch?.[1] ?? \"unknown\";\n const repo = repoMatch?.[1] ?? \"unknown\";\n const branch = branchMatch?.[1] ?? \"unknown\";\n\n await this.emitRunDispatched({\n runId,\n agent,\n repo,\n branch,\n prompt: result.slice(0, 500),\n });\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Process decision:answer events from inbox messages.\n * Expected format: \"decision:answer <decisionId> <answer>\"\n */\n private async processDecisionAnswers(\n rawEvents: QueuedEvent[],\n store: DecisionStore,\n ): Promise<void> {\n for (const event of rawEvents) {\n if (event.kind !== \"message\") continue;\n\n const text = event.data.text.trim();\n const match = /^decision:answer\\s+(\\S+)\\s+(.+)$/i.exec(text);\n if (!match) continue;\n\n const decisionId = match[1];\n const answer = match[2];\n if (!decisionId || !answer) continue;\n\n try {\n await store.answer(decisionId, answer);\n await this.activityLog.log(\"event\", `Decision answered: ${decisionId}`, {\n decisionId,\n answer,\n });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Failed to answer decision ${decisionId}: ${msg}`, {\n decisionId,\n answer,\n });\n }\n }\n }\n\n /**\n * Read persisted run data to extract actual status, cost, and duration.\n * Returns null if the run file cannot be found or parsed.\n */\n private async readPersistedRun(runId: string): Promise<{\n status: PersistedRun[\"status\"];\n totalCostUsd: number;\n durationMs: number;\n output: string | undefined;\n } | null> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return null;\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const subDir = path.join(runsDir, entry.name);\n const runPath = path.join(subDir, `${runId}.json`);\n\n if (existsSync(runPath)) {\n const raw = await readFile(runPath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n\n // Calculate total cost from all steps\n const totalCostUsd = Object.values(run.steps).reduce(\n (sum, step) => sum + (step.costUsd ?? 0),\n 0,\n );\n\n // Calculate duration from createdAt to updatedAt\n const durationMs = new Date(run.updatedAt).getTime() - new Date(run.createdAt).getTime();\n\n // Get output from the last completed step\n const completedSteps = Object.values(run.steps).filter(\n (s) => s.status === \"success\" || s.status === \"failure\",\n );\n const lastStep = completedSteps[completedSteps.length - 1];\n const output =\n typeof lastStep?.rawOutput === \"string\" ? lastStep.rawOutput.slice(0, 1000) : undefined;\n\n return { status: run.status, totalCostUsd, durationMs, output };\n }\n }\n } catch {\n // Non-critical — return null if we can't read run data\n }\n\n return null;\n }\n\n // ─── Webhook event emission ───────────────────────────────\n\n /**\n * Emit a webhook event if a callback is configured.\n * Validates the event against its schema before emission.\n */\n private async emitWebhookEvent(event: SupervisorWebhookEvent): Promise<void> {\n if (!this.onWebhookEvent) return;\n\n try {\n // Validate event against schema before emission\n switch (event.type) {\n case \"supervisor_started\":\n supervisorStartedEventSchema.parse(event);\n break;\n case \"heartbeat\":\n heartbeatEventSchema.parse(event);\n break;\n case \"run_dispatched\":\n runDispatchedEventSchema.parse(event);\n break;\n case \"run_completed\":\n runCompletedEventSchema.parse(event);\n break;\n case \"supervisor_stopped\":\n supervisorStoppedEventSchema.parse(event);\n break;\n }\n\n await this.onWebhookEvent(event);\n } catch (error) {\n // Log validation/emission errors but don't fail the heartbeat\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Webhook event emission failed: ${msg}`, {\n eventType: event.type,\n });\n }\n }\n\n /** Emit SupervisorStartedEvent */\n private async emitSupervisorStarted(): Promise<void> {\n const event: SupervisorStartedEvent = {\n type: \"supervisor_started\",\n supervisorId: this.sessionId,\n startedAt: new Date().toISOString(),\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit SupervisorStoppedEvent */\n private async emitSupervisorStopped(\n reason: \"shutdown\" | \"budget_exceeded\" | \"error\" | \"manual\",\n ): Promise<void> {\n const event: SupervisorStoppedEvent = {\n type: \"supervisor_stopped\",\n supervisorId: this.sessionId,\n stoppedAt: new Date().toISOString(),\n reason,\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit HeartbeatEvent */\n private async emitHeartbeatCompleted(opts: {\n heartbeatNumber: number;\n runsActive: number;\n todayUsd: number;\n limitUsd: number;\n }): Promise<void> {\n const event: HeartbeatEvent = {\n type: \"heartbeat\",\n supervisorId: this.sessionId,\n heartbeatNumber: opts.heartbeatNumber,\n timestamp: new Date().toISOString(),\n runsActive: opts.runsActive,\n budget: {\n todayUsd: opts.todayUsd,\n limitUsd: opts.limitUsd,\n },\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit RunDispatchedEvent from tool result detection */\n private async emitRunDispatched(opts: {\n runId: string;\n agent: string;\n repo: string;\n branch: string;\n prompt: string;\n }): Promise<void> {\n const event: RunDispatchedEvent = {\n type: \"run_dispatched\",\n supervisorId: this.sessionId,\n runId: opts.runId,\n agent: opts.agent,\n repo: opts.repo,\n branch: opts.branch,\n prompt: opts.prompt.slice(0, 500), // Truncate to schema max\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit RunCompletedEvent when processing run_complete events */\n private async emitRunCompleted(opts: {\n runId: string;\n status: \"completed\" | \"failed\" | \"cancelled\";\n output?: string;\n costUsd: number;\n durationMs: number;\n }): Promise<void> {\n const event: RunCompletedEvent = {\n type: \"run_completed\",\n supervisorId: this.sessionId,\n runId: opts.runId,\n status: opts.status,\n output: opts.output?.slice(0, 1000), // Truncate to schema max\n costUsd: opts.costUsd,\n durationMs: opts.durationMs,\n };\n await this.emitWebhookEvent(event);\n }\n}\n","import { z } from \"zod\";\n\n// ─── Schemas ─────────────────────────────────────────────\n\nexport const idleDetectorConfigSchema = z.object({\n idleSkipMax: z.number(),\n activeWorkSkipMax: z.number(),\n});\n\nexport const idleContextSchema = z.object({\n eventCount: z.number(),\n activeRuns: z.number(),\n hasPendingConsolidation: z.boolean(),\n hasExpiredDecisions: z.boolean(),\n timeSinceLastHeartbeatMs: z.number(),\n idleSkipCount: z.number(),\n activeWorkSkipCount: z.number(),\n});\n\nexport const skipResultSchema = z.object({\n shouldSkip: z.boolean(),\n reason: z.string(),\n});\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type IdleDetectorConfig = z.infer<typeof idleDetectorConfigSchema>;\nexport type IdleContext = z.infer<typeof idleContextSchema>;\nexport type SkipResult = z.infer<typeof skipResultSchema>;\n\n// ─── Detector ────────────────────────────────────────────\n\n/**\n * Determines whether a supervisor heartbeat cycle should be skipped.\n * Extracts skip logic into a testable, single-responsibility class.\n */\nexport class IdleDetector {\n private readonly config: IdleDetectorConfig;\n\n constructor(config: IdleDetectorConfig) {\n this.config = config;\n }\n\n /**\n * Evaluate whether the current heartbeat should be skipped.\n * @returns SkipResult with shouldSkip flag and reason\n */\n shouldSkip(context: IdleContext): SkipResult {\n // Events pending — must process\n if (context.eventCount > 0) {\n return { shouldSkip: false, reason: \"events pending\" };\n }\n\n // Consolidation waiting — must process\n if (context.hasPendingConsolidation) {\n return { shouldSkip: false, reason: \"pending consolidation\" };\n }\n\n // Expired decisions — must process\n if (context.hasExpiredDecisions) {\n return { shouldSkip: false, reason: \"expired decisions\" };\n }\n\n // Active runs — check threshold\n if (context.activeRuns > 0) {\n if (context.activeWorkSkipCount >= this.config.activeWorkSkipMax) {\n return { shouldSkip: false, reason: \"active work skip threshold exceeded\" };\n }\n return { shouldSkip: true, reason: \"active runs, within threshold\" };\n }\n\n // Idle — check threshold\n if (context.idleSkipCount >= this.config.idleSkipMax) {\n return { shouldSkip: false, reason: \"idle skip threshold exceeded\" };\n }\n\n return { shouldSkip: true, reason: \"idle, within threshold\" };\n }\n}\n","import { appendFile, readFile, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { LogBufferEntry } from \"./schemas.js\";\n\nconst LOG_BUFFER_FILE = \"log-buffer.jsonl\";\nconst MAX_FILE_BYTES = 1024 * 1024; // 1MB cap\nconst COMPACTION_AGE_MS = 24 * 60 * 60 * 1000; // 24h\nconst MAX_ENTRIES_PER_RUN = 5;\nconst MAX_DIGEST_ENTRIES = 30;\n\n// ─── Type markers for digest formatting ─────────────────\n\nconst TYPE_MARKERS: Record<string, string> = {\n milestone: \"★\",\n decision: \"◆\",\n blocker: \"⚠\",\n progress: \"·\",\n action: \"→\",\n discovery: \"◇\",\n};\n\n// ─── Core read/write ────────────────────────────────────\n\nfunction bufferPath(dir: string): string {\n return path.join(dir, LOG_BUFFER_FILE);\n}\n\nfunction parseLines(content: string): LogBufferEntry[] {\n const entries: LogBufferEntry[] = [];\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n try {\n entries.push(JSON.parse(line) as LogBufferEntry);\n } catch {\n // Skip malformed lines\n }\n }\n return entries;\n}\n\n/**\n * Read all entries from log-buffer.jsonl.\n */\nexport async function readLogBuffer(dir: string): Promise<LogBufferEntry[]> {\n try {\n const content = await readFile(bufferPath(dir), \"utf-8\");\n return parseLines(content);\n } catch {\n return [];\n }\n}\n\n/**\n * Read entries with timestamp > since.\n */\nexport async function readLogBufferSince(dir: string, since: string): Promise<LogBufferEntry[]> {\n const entries = await readLogBuffer(dir);\n return entries.filter((e) => e.timestamp > since);\n}\n\n/**\n * Read entries where consolidatedAt is null/undefined.\n */\nexport async function readUnconsolidated(dir: string): Promise<LogBufferEntry[]> {\n const entries = await readLogBuffer(dir);\n return entries.filter((e) => !e.consolidatedAt);\n}\n\n/**\n * Set consolidatedAt on entries by id.\n * Rewrites the file with updated entries.\n */\nexport async function markConsolidated(dir: string, ids: string[]): Promise<void> {\n const filePath = bufferPath(dir);\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n return;\n }\n\n const idSet = new Set(ids);\n const now = new Date().toISOString();\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const updated: string[] = [];\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as LogBufferEntry;\n if (idSet.has(entry.id) && !entry.consolidatedAt) {\n entry.consolidatedAt = now;\n }\n updated.push(JSON.stringify(entry));\n } catch {\n updated.push(line);\n }\n }\n\n await writeFile(filePath, `${updated.join(\"\\n\")}\\n`, \"utf-8\");\n}\n\n/**\n * Remove entries with consolidatedAt older than 24h. Cap file at 1MB.\n */\nexport async function compactLogBuffer(dir: string): Promise<void> {\n const filePath = bufferPath(dir);\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch {\n return;\n }\n\n const now = Date.now();\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const kept: string[] = [];\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as LogBufferEntry;\n if (entry.consolidatedAt) {\n const consolidatedTime = new Date(entry.consolidatedAt).getTime();\n if (now - consolidatedTime > COMPACTION_AGE_MS) {\n continue; // Drop old consolidated entries\n }\n }\n kept.push(JSON.stringify(entry));\n } catch {\n // Drop malformed lines during compaction\n }\n }\n\n // Cap at 1MB — drop oldest entries first\n let result = `${kept.join(\"\\n\")}\\n`;\n while (Buffer.byteLength(result, \"utf-8\") > MAX_FILE_BYTES && kept.length > 0) {\n kept.shift();\n result = `${kept.join(\"\\n\")}\\n`;\n }\n\n await writeFile(filePath, result, \"utf-8\");\n}\n\n// ─── Digest helpers ──────────────────────────────────────\n\nfunction groupEntriesByRunId(entries: LogBufferEntry[]): Map<string, LogBufferEntry[]> {\n const groups = new Map<string, LogBufferEntry[]>();\n for (const entry of entries) {\n const key = entry.runId ?? \"unassigned\";\n const group = groups.get(key);\n if (group) {\n group.push(entry);\n } else {\n groups.set(key, [entry]);\n }\n }\n return groups;\n}\n\nfunction dedupeAdjacentEntries(entries: LogBufferEntry[]): LogBufferEntry[] {\n const deduped: LogBufferEntry[] = [];\n for (const entry of entries) {\n const last = deduped[deduped.length - 1];\n if (last && last.message === entry.message) continue;\n deduped.push(entry);\n }\n return deduped;\n}\n\n/**\n * Build a human-readable digest from log buffer entries.\n * Groups by runId, sorts chronologically, adds type markers,\n * deduplicates adjacent identical messages, truncates output.\n */\nexport function buildAgentDigest(entries: LogBufferEntry[]): string {\n if (entries.length === 0) return \"\";\n\n const groups = groupEntriesByRunId(entries);\n const lines: string[] = [];\n let totalCount = 0;\n\n for (const [runId, group] of groups) {\n group.sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n\n const deduped = dedupeAdjacentEntries(group);\n const limited = deduped.slice(0, MAX_ENTRIES_PER_RUN);\n\n const agentLabel = limited[0]?.agent ?? \"unknown\";\n lines.push(`[${runId}] (${agentLabel}):`);\n\n for (const entry of limited) {\n if (totalCount >= MAX_DIGEST_ENTRIES) break;\n const marker = TYPE_MARKERS[entry.type] ?? \"·\";\n lines.push(` ${marker} ${entry.message}`);\n totalCount++;\n }\n\n if (totalCount >= MAX_DIGEST_ENTRIES) {\n lines.push(\" ... (truncated)\");\n break;\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Append a single entry to the log buffer file.\n */\nexport async function appendLogBuffer(dir: string, entry: LogBufferEntry): Promise<void> {\n try {\n // Ensure directory exists (appendFile will create the file but not the dir)\n await appendFile(bufferPath(dir), `${JSON.stringify(entry)}\\n`, \"utf-8\");\n } catch {\n // Best-effort — don't crash the CLI if buffer write fails\n }\n}\n\n/**\n * Get file size of the log buffer (for monitoring).\n */\nexport async function getLogBufferSize(dir: string): Promise<number> {\n try {\n const stats = await stat(bufferPath(dir));\n return stats.size;\n } catch {\n return 0;\n }\n}\n","import type { RepoConfig } from \"@/config\";\nimport type { Decision } from \"./decisions.js\";\nimport type { GroupedEvents } from \"./event-queue.js\";\nimport type { MemoryEntry } from \"./memory/entry.js\";\nimport type { ActivityEntry, QueuedEvent } from \"./schemas.js\";\n\n// ─── Shared options ─────────────────────────────────────\n\nexport interface PromptOptions {\n repos: RepoConfig[];\n grouped: GroupedEvents;\n budgetStatus: {\n todayUsd: number;\n capUsd: number;\n remainingPct: number;\n };\n activeRuns: string[];\n heartbeatCount: number;\n mcpServerNames: string[];\n customInstructions?: string | undefined;\n supervisorDir: string;\n memories: MemoryEntry[];\n recentActions: ActivityEntry[];\n pendingDecisions?: Decision[] | undefined;\n answeredDecisions?: Decision[] | undefined;\n /** When true, supervisor answers decisions autonomously instead of waiting for human input */\n autoDecide?: boolean | undefined;\n}\n\nexport interface StandardPromptOptions extends PromptOptions {}\n\nexport interface ConsolidationPromptOptions extends PromptOptions {\n /** ISO timestamp of last consolidation — used to filter run history */\n lastConsolidationTimestamp?: string | undefined;\n}\n\n// ─── Role (identity only — behavioral rules go in <instructions>) ──\n\nconst ROLE = `You are the neo autonomous supervisor — accountable for delivery across parallel initiatives.\n\nYou do not write code directly; you ensure the right work is assigned, executed, reviewed, and completed by the right agent.`;\n\n// ─── Operating principles (behavioral contract — lives in <instructions>) ──\n\nconst OPERATING_PRINCIPLES = `### Operating principles\n\n- Own delivery end-to-end: any queued task without an active owner is your responsibility.\n- Operate like a strong engineering lead: provide clear context, dispatch deliberately, validate outcomes, and remove blockers quickly.\n- On run completion: read \\`neo runs <runId>\\`, verify acceptance criteria, then decide next action (done, follow-up, redispatch, escalate).\n- On run failure: diagnose root cause before retrying (prompt quality, branch conflict, known issue, environment/tooling), then fix the cause.\n- Prevent silent stalls: monitor long-running jobs, detect blocked work early, and actively unblock.\n- Keep initiative boundaries strict: decisions for initiative A must not be influenced by unrelated state from B.\n- Your user-visible channel is \\`neo log\\` only; produce concise tool calls (not reasoning/explanations) and avoid wasted tokens.\n- You may inspect repositories available via \\`neo repos\\`, read-only to launch agents.\n- Task hygiene is non-negotiable: update task outcomes EVERY heartbeat. A task without a current outcome is a blind spot.`;\n\n// ─── Commands reference (data — lives in <reference>) ───\n\nconst COMMANDS = `### Dispatching agents\n\\`\\`\\`bash\nneo run <agent> --prompt \"...\" --repo <path> --branch <name> [--priority critical|high|medium|low] [--meta '<json>']\n\\`\\`\\`\n\n| Flag | Required | Description |\n|------|----------|-------------|\n| \\`--prompt\\` | always | Task description for the agent |\n| \\`--repo\\` | always | Target repository path |\n| \\`--branch\\` | always | Branch name for the isolated clone |\n| \\`--priority\\` | optional | \\`critical\\`, \\`high\\`, \\`medium\\`, \\`low\\` |\n| \\`--meta\\` | **always** | JSON with \\`\"label\"\\` for identification + \\`\"ticketId\"\\`, \\`\"stage\"\\`, etc. |\n\nAll agents require \\`--branch\\`. Each agent session runs in an isolated clone on that branch.\nAlways include \\`--meta '{\"label\":\"T1-auth-middleware\",\"ticketId\":\"YC-42\",\"stage\":\"develop\"}'\\` so you can identify runs later.\n\n### Monitoring & reading agent output\n\\`\\`\\`bash\nneo runs --short # check recent runs\nneo runs --short --status running # check active runs are alive\nneo runs <runId> # full run details + agent output (MUST READ on completion)\nneo cost --short [--all] # check budget\n\\`\\`\\`\n\n\\`neo runs <runId>\\` returns the agent's full output. **ALWAYS read it when a run completes** — it contains structured JSON (PR URLs, issues, plans, milestones) that you need to decide next steps.\n\n### Memory\n\\`\\`\\`bash\nneo memory write --type fact --scope /path \"Stable fact about repo\"\nneo memory write --type focus --expires 2h \"Current working context\"\nneo memory write --type procedure --scope /path \"How to do X\"\nneo memory write --type task --scope /path --severity high --category \"neo runs <id>\" \"Task description\"\nneo memory update <id> --outcome in_progress|done|blocked|abandoned\nneo memory forget <id>\nneo memory search \"keyword\"\nneo memory list --type fact\n\\`\\`\\`\n\n### Configuration\n\\`\\`\\`bash\nneo config get <key> # read a value (dot notation)\nneo config set <key> <value> --global # update global config (~/.neo/config.yml)\nneo config list # show full merged config\n\\`\\`\\`\n\nKeys use dot notation (e.g., \\`budget.dailyCapUsd\\`, \\`supervisor.dailyCapUsd\\`, \\`concurrency.maxSessions\\`).\nChanges are hot-reloaded — the new values take effect at the next heartbeat.\n\nUse cases: raise budget cap mid-run, adjust concurrency, change heartbeat timeout.\n\n### Decisions\nWhen you need human input on something that cannot be decided autonomously:\n\\`\\`\\`bash\nneo decision create \"<question>\" --options \"key1:label1,key2:label2:description\" [--default <key>] [--expires-in 24h] [--context \"...\"]\nneo decision list # show pending decisions\nneo decision answer <id> <answer> # answer a decision (usually done by human via TUI)\n\\`\\`\\`\nThe decision ID is returned by \\`create\\`. If no answer arrives before expiration, the \\`--default\\` answer is applied automatically (or the decision expires without resolution).\n\n### Reporting\n\\`\\`\\`bash\nneo log <type> \"<message>\" # visible in TUI only\n\\`\\`\\``;\n\nconst COMMANDS_COMPACT = `### Commands (reference)\n\\`neo run <agent> --prompt \"...\" --repo <path> --branch <name> --meta '{\"label\":\"T1-auth\",...}'\\`\n\\`neo runs [--short | <runId>]\\` \\u00b7 \\`neo runs --short --status running\\` \\u00b7 \\`neo cost --short\\`\n\\`neo memory write|update|forget|search|list\\` \\u00b7 \\`neo log <type> \"<msg>\"\\`\n\\`neo config get <key>\\` \\u00b7 \\`neo config set <key> <value> --global\\` \\u00b7 \\`neo config list\\`\n\\`neo decision create \"<question>\" --options \"...\" [--default <key>]\\` \\u00b7 \\`neo decision list\\``;\n\n// ─── Instruction blocks ─────────────────────────────────\n\nconst HEARTBEAT_RULES = `### Heartbeat lifecycle\n\n<decision-tree>\n1. DEDUP FIRST — check focus for PROCESSED entries. Skip any runId already processed.\n2. MONITOR RUNS — \\`neo runs --short\\` to check active run status. If a run completed since last HB, read its output with \\`neo runs <runId>\\` BEFORE doing anything else.\n3. PENDING TASKS? — dispatch the next eligible task from work queue. Do not re-plan.\n4. EVENTS? — process run completions, messages, webhooks. Parse agent JSON output.\n5. FOLLOW-UPS? — check CI (\\`gh pr checks\\`), deferred dispatches.\n6. DISPATCH — route work to agents. Mark tasks \\`in_progress\\`, add ACTIVE to focus.\n7. UPDATE TASKS — review ALL in_progress/blocked tasks. For each: confirm status matches reality (run still active? PR merged? blocked resolved?). Update outcomes immediately — do not defer to next heartbeat.\n8. SERIALIZE & YIELD — rewrite focus (see <focus>), log your decisions, and yield. Do not poll.\n</decision-tree>\n\n<run-monitoring>\nRuns are your agents in the field. You MUST actively track them:\n- **On dispatch**: include a label in \\`--meta\\` for identification: \\`--meta '{\"label\":\"T6-csv-export\",\"ticketId\":\"YC-42\",...}'\\`\n- **On completion**: ALWAYS run \\`neo runs <runId>\\` to read the full output. Parse structured JSON (PR URLs, issues, plans). This is NOT optional — you cannot decide next steps without reading the output.\n- **On failure**: read the output to understand why. Decide: retry (blocked), abandon, or escalate.\n- **Active runs**: check \\`neo runs --short --status running\\` to verify your runs are still alive. If a run disappeared, investigate.\n</run-monitoring>\n\n<multi-task-initiatives>\n**Branch strategy:** one branch per initiative — all tasks push to the same branch sequentially (never in parallel). First task creates the branch; open PR after it completes. Later tasks add commits to the same PR. Independent initiatives CAN run in parallel on different branches.\n\n**Dispatch quality:** write a detailed \\`--prompt\\` with acceptance criteria, files to modify, and context from completed sibling tasks (commits, APIs added, files changed). When dispatching task N, summarize what tasks 1..N-1 produced.\n\n**Post-completion:** if agent opened a PR, dispatch \\`reviewer\\` in parallel with CI (do not wait). Update task outcome with concrete details (PR#, what was done) and update the initiative note.\n\n**Task tracking discipline:**\n- On dispatch: \\`neo memory update <id> --outcome in_progress\\` immediately — never dispatch without updating the task.\n- On run completion: update to \\`done\\` with details OR \\`blocked\\` with reason. Do this in the SAME heartbeat you read the run output.\n- On run failure: update to \\`blocked\\` with root cause. Never leave a failed run's task as \\`in_progress\\`.\n- Every heartbeat: cross-check active tasks against \\`neo runs --short\\`. If a run finished but the task is still \\`in_progress\\`, something was missed — fix it now.\n\n**Memory:** store key outputs as facts if they affect future tasks (e.g. \"T5 added dateRange param to fetchAllFstRecords\").\n</multi-task-initiatives>`;\n\nconst REPORTING_RULES = `### Reporting\n\n\\`neo log\\` is your ONLY visible output. Use telegraphic format.\n\n<log-format>\nneo log decision \"<ticket> \\u2192 <action> | <1-line reason>\"\nneo log action \"<agent> <repo>:<branch> run:<runId> | <context>\"\nneo log discovery \"<what> in <where>\"\n</log-format>\n\n<examples type=\"good\">\nneo log decision \"YC-42 \\u2192 developer | clear spec, complexity 3\"\nneo log action \"developer standards:feat/YC-42-auth run:5900a64a | task T1\"\nneo log discovery \"CI requires node 20 in api-service\"\n</examples>`;\n\nfunction buildMemoryRulesCore(supervisorDir: string): string {\n const notesDir = `${supervisorDir}/notes`;\n return `### Memory\n\n<memory-types>\n| Type | Store when | TTL |\n|------|-----------|-----|\n| \\`fact\\` | Stable truth affecting dispatch decisions | Permanent (decays) |\n| \\`procedure\\` | Same failure 3+ times | Permanent |\n| \\`focus\\` | After every dispatch/deferral | --expires required |\n| \\`task\\` | Any planned work (tickets, decompositions, follow-ups) | Until done/abandoned |\n| \\`feedback\\` | Same review complaint 3+ times | Permanent |\n</memory-types>\n\n<memory-rules>\n- Focus is free-form working memory — rewrite at end of EVERY heartbeat (see <focus>).\n- NEVER store: file counts, line numbers, completed work details, data available via \\`neo runs <id>\\`.\n- After PR merge: forget related facts unless they are reusable architectural truths.\n- Pattern escalation: same failure 3+ times \\u2192 write a \\`procedure\\`.\n- Every memory that references external context MUST include a retrieval command (in \\`--category\\` for tasks, in content for facts/procedures). You are stateless — if you can't retrieve it later, don't store it.\n</memory-rules>\n\n<task-workflow>\nQueue markers: \\u25cb pending \\u00b7 [ACTIVE] in_progress \\u00b7 [BLOCKED] blocked.\nCreate tasks for: incoming tickets, architect decompositions, sub-tickets, follow-ups, CI fixes.\n- \\`--tags \"initiative:<name>\"\\` — groups related tasks\n- \\`--tags \"depends:mem_<id>\"\\` — blocks until dependency is done\n- \\`--category\\` — retrieval command (MANDATORY). Examples: \\`\"neo runs <runId>\"\\` \\u00b7 \\`\"cat ${notesDir}/plan-feature.md\"\\` \\u00b7 \\`\"API-retrieve-a-page <notionPageId>\"\\`\nLifecycle: create → in_progress (on dispatch) → done | blocked | abandoned\n\n**Update frequency:** task outcomes MUST be updated in the same heartbeat as the triggering event. Never defer a task update to \"next heartbeat\" — by then you will have forgotten. Stale task states cause duplicate dispatches and wasted budget.\n\n**Mandatory cross-check:** before yielding, verify that:\n1. Every dispatched run has a corresponding \\`in_progress\\` task\n2. Every completed run has a corresponding \\`done\\` or \\`blocked\\` task\n3. No task is \\`in_progress\\` without an active run (unless manually worked)\n</task-workflow>\n\n<focus>\nYou are stateless between heartbeats. Focus is your scratchpad — the only thing future-you will read before acting.\n\nWrite it like a handoff note to yourself: what's happening, what you decided, what to do next, what to watch for. Free-form. No format imposed. The only rule: if you don't write it down, you lose it.\n\nRewrite focus at the END of every heartbeat. Never leave it empty after a heartbeat with activity.\n</focus>\n\n<notes>\nNotes directory: \\`${notesDir}/\\`\nUse notes for any initiative with 3+ tasks (persists across heartbeats).\n- Write: \\`cat > ${notesDir}/plan-<initiative>.md << 'EOF' ... EOF\\`\n- Link to tasks: \\`--category \"cat ${notesDir}/plan-<initiative>.md\"\\`\n- Update after each task: check off milestones, add PR numbers, note blockers\n- Delete when initiative is done\nUse cases: architect decompositions, initiative tracking, debugging across heartbeats, review checklists.\n</notes>`;\n}\n\nfunction buildMemoryRulesExamples(supervisorDir: string): string {\n const notesDir = `${supervisorDir}/notes`;\n return `<memory-examples>\nneo memory write --type focus --expires 2h \"ACTIVE: 5900a64a developer 'T1' branch:feat/x (cat ${notesDir}/plan-YC-2670-kanban.md)\"\nneo memory write --type fact --scope /repo \"main branch uses protected merges — agents must create PRs, never push directly\"\nneo memory write --type fact --scope /repo \"pnpm build must pass before push — CI does not rebuild, run 2g589f34a5a failed without it\"\nneo memory write --type procedure --scope /repo \"After architect run: parse milestones from JSON output, create one task per milestone with --tags initiative:<name>\"\nneo memory write --type procedure --scope /repo \"When developer run fails with ENOSPC: the repo has large fixtures — use --branch with shallow clone flag\"\nneo memory write --type feedback --scope /repo \"User wants PR descriptions in French even though code is in English\"\nneo memory write --type task --scope /repo --severity high --category \"neo runs 2g589f34a5a\" --tags \"initiative:auth-v2,depends:mem_xyz\" \"T1: Auth middleware\"\nneo memory update <id> --outcome in_progress|done|blocked|abandoned\nneo memory forget <id>\n</memory-examples>`;\n}\n\n// ─── Prompt assembly helpers ────────────────────────────\n//\n// Prompt structure follows Anthropic best practices:\n// <role> — Identity only (2 sentences)\n// <context> — Data top: focus → work state → knowledge → environment → events (query last)\n// <reference> — Command documentation (stable reference data)\n// <instructions> — All behavioral rules bottom: principles → lifecycle → reporting → memory → directive\n\nfunction buildRoleSection(heartbeatCount: number, label?: string): string {\n const suffix = label ? ` (${label})` : \"\";\n return `<role>\\n${ROLE}\\nHeartbeat #${heartbeatCount}${suffix}\\n</role>`;\n}\n\nfunction getCommandsSection(heartbeatCount: number): string {\n return heartbeatCount <= 3 ? COMMANDS : COMMANDS_COMPACT;\n}\n\nfunction buildReferenceSection(heartbeatCount: number): string {\n return `<reference>\\n${getCommandsSection(heartbeatCount)}\\n</reference>`;\n}\n\n/**\n * Build the focus section from memory entries.\n * Rendered at the top of <context> — first thing the supervisor reads to re-orient.\n */\nfunction buildFocusSection(memories: MemoryEntry[]): string {\n const focusEntries = memories.filter((m) => m.type === \"focus\");\n\n if (focusEntries.length > 0) {\n const lines = focusEntries.map((m) => `- ${m.content}`).join(\"\\n\");\n return `<focus>\\n${lines}\\n</focus>`;\n }\n\n return \"<focus>\\n(empty \\u2014 use neo memory write --type focus to set working context)\\n</focus>\";\n}\n\n// ─── Decision sections ──────────────────────────────────\n\n/**\n * Build the pending decisions section.\n * Shows decisions awaiting supervisor response with clear instructions.\n * When autoDecide is true, instructs the supervisor to answer decisions autonomously.\n */\nfunction buildPendingDecisionsSection(\n decisions: Decision[] | undefined,\n autoDecide = false,\n): string {\n if (!decisions || decisions.length === 0) {\n return \"\";\n }\n\n const lines: string[] = [];\n for (const d of decisions) {\n const expiry = d.expiresAt ? ` (expires: ${d.expiresAt})` : \"\";\n const defaultHint = d.defaultAnswer ? ` [default: ${d.defaultAnswer}]` : \"\";\n lines.push(`- **${d.id}**: ${d.question}${expiry}${defaultHint}`);\n\n if (d.options && d.options.length > 0) {\n for (const opt of d.options) {\n const desc = opt.description ? ` — ${opt.description}` : \"\";\n lines.push(` • \\`${opt.key}\\`: ${opt.label}${desc}`);\n }\n }\n\n if (d.context) {\n lines.push(` Context: ${d.context}`);\n }\n }\n\n const instruction = autoDecide\n ? `You are in **autoDecide** mode — answer each pending decision yourself based on available context, project knowledge, and best engineering judgment.\n\n\\`\\`\\`bash\nneo decision answer <decision_id> <answer>\n\\`\\`\\`\n\nFor each decision: analyze the options, consider the project context and risk, then answer decisively. Prefer safe, incremental choices when uncertain. Log your reasoning before answering.\n\n**Merge authority:** In autoDecide mode you MAY merge branches when the PR is ready (CI green, reviews approved). Use \\`gh pr merge\\` with the appropriate merge strategy.`\n : `To answer a decision, emit a \\`decision:answer\\` event:\n\\`\\`\\`bash\nneo event emit decision:answer --data '{\"id\":\"<decision_id>\",\"answer\":\"<option_key>\"}'\n\\`\\`\\``;\n\n return `Pending decisions (${decisions.length}):\n${lines.join(\"\\n\")}\n\n${instruction}`;\n}\n\n/**\n * Build the recent answered decisions section.\n * Provides context continuity by showing recently resolved decisions.\n */\nfunction buildAnsweredDecisionsSection(decisions: Decision[] | undefined): string {\n if (!decisions || decisions.length === 0) {\n return \"\";\n }\n\n const lines = decisions.map((d) => {\n const answeredBy = d.source ? ` (by ${d.source})` : \"\";\n return `- ${d.id}: \"${d.question}\" → **${d.answer}**${answeredBy}`;\n });\n\n return `Recent decisions (${decisions.length}):\\n${lines.join(\"\\n\")}`;\n}\n\n/**\n * Build the full context block shared by standard & consolidation prompts.\n * Order: focus (orientation) \\u2192 work state \\u2192 knowledge \\u2192 environment \\u2192 events (query last).\n * Compaction uses a subset via buildCompactionContext.\n */\nfunction buildFullContext(opts: PromptOptions): string {\n const parts: string[] = [];\n\n // 1. Focus — orientation (first thing read after role)\n parts.push(buildFocusSection(opts.memories));\n\n // 2. Work state — what's happening right now\n const workQueue = buildWorkQueueSection(opts.memories);\n if (workQueue) {\n parts.push(workQueue);\n }\n\n if (opts.activeRuns.length > 0) {\n parts.push(`Active runs:\\n${opts.activeRuns.map((r) => `- ${r}`).join(\"\\n\")}`);\n }\n\n const recentActions = buildRecentActionsSection(opts.recentActions);\n if (recentActions) {\n parts.push(recentActions);\n }\n\n // 2b. Decisions — pending questions requiring supervisor response\n const pendingDecisions = buildPendingDecisionsSection(opts.pendingDecisions, opts.autoDecide);\n if (pendingDecisions) {\n parts.push(pendingDecisions);\n }\n\n const answeredDecisions = buildAnsweredDecisionsSection(opts.answeredDecisions);\n if (answeredDecisions) {\n parts.push(answeredDecisions);\n }\n\n // 3. Knowledge — accumulated memory (facts, procedures, feedback)\n parts.push(buildKnowledgeSection(opts.memories));\n\n // 4. Environment — stable infra (repos, MCP, budget)\n parts.push(...buildEnvironmentSections(opts));\n\n // 5. Events — the \"query\" (last = highest attention per Anthropic guidelines)\n parts.push(`Events:\\n${buildEventsSection(opts.grouped)}`);\n\n return `<context>\\n${parts.join(\"\\n\\n\")}\\n</context>`;\n}\n\n/**\n * Build a lighter context for compaction heartbeats.\n * No active runs, no recent actions, no events — just memory for cleanup review.\n */\nfunction buildCompactionContext(opts: PromptOptions): string {\n const parts: string[] = [];\n\n parts.push(buildFocusSection(opts.memories));\n parts.push(buildKnowledgeSection(opts.memories));\n\n const workQueue = buildWorkQueueSection(opts.memories);\n if (workQueue) {\n parts.push(workQueue);\n }\n\n parts.push(...buildEnvironmentSections(opts));\n\n return `<context>\\n${parts.join(\"\\n\\n\")}\\n</context>`;\n}\n\n/**\n * Build the base instruction parts shared by all prompt variants.\n * Order: principles \\u2192 lifecycle \\u2192 reporting \\u2192 memory \\u2192 custom \\u2192 (caller adds directive last)\n */\nfunction buildBaseInstructions(\n opts: PromptOptions,\n options: { includeExamples: boolean },\n): string[] {\n const parts: string[] = [];\n parts.push(OPERATING_PRINCIPLES);\n parts.push(HEARTBEAT_RULES);\n parts.push(REPORTING_RULES);\n parts.push(buildMemoryRulesCore(opts.supervisorDir));\n\n if (options.includeExamples) {\n parts.push(buildMemoryRulesExamples(opts.supervisorDir));\n }\n\n if (opts.customInstructions) {\n parts.push(`### Custom instructions\\n${opts.customInstructions}`);\n }\n\n return parts;\n}\n\nfunction wrapInstructions(parts: string[]): string {\n return `<instructions>\\n${parts.join(\"\\n\\n\")}\\n</instructions>`;\n}\n\n// ─── Context section builders ───────────────────────────\n\nfunction buildEnvironmentSections(opts: PromptOptions): string[] {\n const parts: string[] = [];\n\n if (opts.repos.length > 0) {\n const repoList = opts.repos.map((r) => `- ${r.path} (branch: ${r.defaultBranch})`).join(\"\\n\");\n parts.push(`Repositories:\\n${repoList}`);\n }\n\n if (opts.mcpServerNames.length > 0) {\n const mcpList = opts.mcpServerNames.map((n) => `- ${n}`).join(\"\\n\");\n parts.push(`Integrations (MCP):\\n${mcpList}`);\n }\n\n parts.push(\n `Budget: $${opts.budgetStatus.todayUsd.toFixed(2)} / $${opts.budgetStatus.capUsd.toFixed(2)} (${opts.budgetStatus.remainingPct.toFixed(0)}% remaining)`,\n );\n\n return parts;\n}\n\n/**\n * Build the knowledge section: facts, procedures, and feedback.\n * Focus is excluded — it's rendered separately at context top level.\n */\nfunction buildKnowledgeSection(memories: MemoryEntry[]): string {\n const factEntries = memories.filter((m) => m.type === \"fact\");\n const procedureEntries = memories.filter((m) => m.type === \"procedure\");\n const feedbackEntries = memories.filter((m) => m.type === \"feedback\");\n\n const parts: string[] = [];\n\n // Known facts — grouped by scope with staleness signal\n if (factEntries.length > 0) {\n const byScope = new Map<string, MemoryEntry[]>();\n for (const m of factEntries) {\n const scope = m.scope === \"global\" ? \"global\" : (m.scope.split(\"/\").pop() ?? m.scope);\n const group = byScope.get(scope) ?? [];\n group.push(m);\n byScope.set(scope, group);\n }\n\n const scopeSections: string[] = [];\n for (const [scope, entries] of byScope) {\n const oldestAccess = Math.min(\n ...entries.map((m) => Date.now() - new Date(m.lastAccessedAt).getTime()),\n );\n const daysAgo = Math.floor(oldestAccess / 86_400_000);\n const staleHint = daysAgo >= 5 ? ` (last accessed ${daysAgo}d ago)` : \"\";\n const lines = entries\n .map((m) => {\n const confidence = m.accessCount >= 3 ? \"\" : \" (unconfirmed)\";\n return ` - ${m.content}${confidence}`;\n })\n .join(\"\\n\");\n scopeSections.push(` [${scope}]${staleHint} (${entries.length})\\n${lines}`);\n }\n parts.push(`Known facts:\\n${scopeSections.join(\"\\n\")}`);\n }\n\n // Procedures\n if (procedureEntries.length > 0) {\n const lines = procedureEntries.map((m) => `- ${m.content}`).join(\"\\n\");\n parts.push(`Procedures:\\n${lines}`);\n }\n\n // Recurring feedback\n if (feedbackEntries.length > 0) {\n const lines = feedbackEntries\n .map((m) => `- [${m.category ?? \"general\"}] ${m.content}`)\n .join(\"\\n\");\n parts.push(`Recurring review issues:\\n${lines}`);\n }\n\n return parts.join(\"\\n\\n\");\n}\n\n// ─── Work queue (tasks) ─────────────────────────────────\n\nconst DONE_OUTCOMES = new Set([\"done\", \"abandoned\"]);\nconst MAX_TASKS = 15;\n\ninterface TaskGroup {\n initiative: string | null;\n tasks: MemoryEntry[];\n}\n\nexport function buildWorkQueueSection(memories: MemoryEntry[]): string {\n const tasks = memories.filter((m) => m.type === \"task\" && !DONE_OUTCOMES.has(m.outcome ?? \"\"));\n const doneCount = countDoneTasks(memories);\n\n if (tasks.length === 0) {\n if (doneCount > 0) {\n return `Work queue (0 remaining, ${doneCount} done) \\u2014 all tasks complete. Pick up new work or wait for events.`;\n }\n return \"\";\n }\n\n const groups = groupTasksByInitiative(tasks);\n const lines = renderTaskGroups(groups);\n\n if (tasks.length > MAX_TASKS) {\n lines.push(` ... and ${tasks.length - MAX_TASKS} more pending`);\n }\n\n const header = `Work queue (${tasks.length} remaining, ${doneCount} done) \\u2014 dispatch the next eligible task:`;\n return `${header}\\n${lines.join(\"\\n\")}`;\n}\n\nfunction countDoneTasks(memories: MemoryEntry[]): number {\n return memories.filter((m) => m.type === \"task\" && DONE_OUTCOMES.has(m.outcome ?? \"\")).length;\n}\n\nfunction groupTasksByInitiative(tasks: MemoryEntry[]): TaskGroup[] {\n const initiativeMap = new Map<string, MemoryEntry[]>();\n const noInitiative: MemoryEntry[] = [];\n\n for (const task of tasks) {\n const tag = task.tags.find((t) => t.startsWith(\"initiative:\"));\n if (tag) {\n const key = tag.slice(\"initiative:\".length);\n const group = initiativeMap.get(key) ?? [];\n group.push(task);\n initiativeMap.set(key, group);\n } else {\n noInitiative.push(task);\n }\n }\n\n const groups: TaskGroup[] = [];\n for (const [initiative, taskList] of initiativeMap) {\n groups.push({ initiative, tasks: taskList });\n }\n if (noInitiative.length > 0) {\n groups.push({ initiative: null, tasks: noInitiative });\n }\n return groups;\n}\n\nconst SEVERITY_ORDER: Record<string, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\nfunction bySeverity(a: MemoryEntry, b: MemoryEntry): number {\n const aOrder = SEVERITY_ORDER[a.severity ?? \"medium\"] ?? 2;\n const bOrder = SEVERITY_ORDER[b.severity ?? \"medium\"] ?? 2;\n return aOrder - bOrder;\n}\n\nfunction partitionTasks(tasks: MemoryEntry[]): {\n active: MemoryEntry[];\n blocked: MemoryEntry[];\n pending: MemoryEntry[];\n} {\n const active: MemoryEntry[] = [];\n const blocked: MemoryEntry[] = [];\n const pending: MemoryEntry[] = [];\n for (const t of tasks) {\n if (t.outcome === \"in_progress\") active.push(t);\n else if (t.outcome === \"blocked\") blocked.push(t);\n else pending.push(t);\n }\n return { active, blocked, pending };\n}\n\nfunction renderInitiativeSummary(group: TaskGroup): string {\n const { active, pending } = partitionTasks(group.tasks);\n const nextEligible = [...pending].sort(bySeverity)[0];\n const cat = nextEligible?.category ? ` -> ${nextEligible.category}` : \"\";\n const nextLabel = nextEligible\n ? ` (next: ${nextEligible.content.slice(0, 30)}${nextEligible.content.length > 30 ? \"...\" : \"\"} [${nextEligible.severity ?? \"medium\"}])`\n : \"\";\n return `[${group.initiative}] ${active.length} active, ${pending.length} pending${nextLabel}${cat}`;\n}\n\nfunction renderCompactInitiative(group: TaskGroup, lines: string[], rendered: number): number {\n lines.push(` ${renderInitiativeSummary(group)}`);\n\n const { active, blocked, pending } = partitionTasks(group.tasks);\n const nextEligible = [...pending].sort(bySeverity)[0];\n\n for (const task of [...active, ...blocked]) {\n if (rendered >= MAX_TASKS) break;\n lines.push(` ${formatTaskLine(task)}`);\n rendered++;\n }\n\n // Show next eligible pending if no active/blocked tasks\n if (nextEligible && active.length === 0 && blocked.length === 0 && rendered < MAX_TASKS) {\n lines.push(` ${formatTaskLine(nextEligible)}`);\n rendered++;\n }\n\n return rendered;\n}\n\nfunction renderFlatGroup(\n group: TaskGroup,\n showHeader: boolean,\n lines: string[],\n rendered: number,\n): number {\n if (showHeader && group.initiative) {\n lines.push(` [${group.initiative}]`);\n }\n for (const task of group.tasks) {\n if (rendered >= MAX_TASKS) break;\n lines.push(` ${formatTaskLine(task)}`);\n rendered++;\n }\n return rendered;\n}\n\nfunction renderTaskGroups(groups: TaskGroup[]): string[] {\n const lines: string[] = [];\n let rendered = 0;\n\n for (const group of groups) {\n if (rendered >= MAX_TASKS) break;\n\n const useCompactMode = group.initiative && group.tasks.length >= 3;\n if (useCompactMode) {\n rendered = renderCompactInitiative(group, lines, rendered);\n } else {\n const showHeader = group.initiative !== null && groups.length > 1;\n rendered = renderFlatGroup(group, showHeader, lines, rendered);\n }\n }\n\n return lines;\n}\n\nfunction formatTaskLine(task: MemoryEntry): string {\n const marker = formatTaskMarker(task.outcome);\n const severity = task.severity ? `[${task.severity}] ` : \"\";\n const scope = task.scope !== \"global\" ? ` (${getBasename(task.scope)})` : \"\";\n const run = task.runId ? ` [run ${task.runId.slice(0, 8)}]` : \"\";\n const cat = task.category ? ` \\u2192 ${task.category}` : \"\";\n return `${marker} ${severity}${task.content}${scope}${run}${cat}`;\n}\n\nfunction formatTaskMarker(outcome: string | undefined): string {\n switch (outcome) {\n case \"in_progress\":\n return \"[ACTIVE]\";\n case \"blocked\":\n return \"[BLOCKED]\";\n default:\n return \"\\u25cb\";\n }\n}\n\nfunction getBasename(scopePath: string): string {\n const parts = scopePath.split(\"/\");\n return parts[parts.length - 1] || scopePath;\n}\n\n// ─── Recent actions ─────────────────────────────────────\n\nconst SIGNIFICANT_TYPES = new Set([\"decision\", \"action\", \"dispatch\", \"error\"]);\n\nfunction buildRecentActionsSection(entries: ActivityEntry[]): string {\n const significant = entries.filter((e) => SIGNIFICANT_TYPES.has(e.type));\n if (significant.length === 0) return \"\";\n\n const lines = significant.map((e) => {\n const ago = formatTimeAgo(Date.now() - new Date(e.timestamp).getTime());\n return `- [${e.type}] ${e.summary} (${ago})`;\n });\n\n return `Recent actions (your last heartbeats):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatTimeAgo(ms: number): string {\n if (ms < 60_000) return \"just now\";\n const minutes = Math.floor(ms / 60_000);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h${minutes % 60}m ago`;\n return `${Math.floor(hours / 24)}d ago`;\n}\n\n// ─── Events ─────────────────────────────────────────────\n\nfunction buildEventsSection(grouped: GroupedEvents): string {\n const { messages, webhooks, runCompletions } = grouped;\n const totalEvents = messages.length + webhooks.length + runCompletions.length;\n\n if (totalEvents === 0) {\n return \"No new events.\";\n }\n\n const parts: string[] = [];\n for (const msg of messages) {\n const countSuffix = msg.count > 1 ? ` (x${msg.count})` : \"\";\n parts.push(`Message from ${msg.from}${countSuffix}: ${msg.text}`);\n }\n for (const evt of webhooks) {\n parts.push(formatEvent(evt));\n }\n for (const evt of runCompletions) {\n parts.push(formatEvent(evt));\n }\n return `${totalEvents} pending event(s):\\n${parts.join(\"\\n\\n\")}`;\n}\n\nfunction formatEvent(event: QueuedEvent): string {\n switch (event.kind) {\n case \"webhook\":\n return `Webhook [${event.data.source ?? \"unknown\"}] ${event.data.event ?? \"\"}\\n\\`\\`\\`json\\n${JSON.stringify(event.data.payload ?? {}, null, 2)}\\n\\`\\`\\``;\n case \"message\":\n return `Message from ${event.data.from}: ${event.data.text}`;\n case \"run_complete\":\n return `Run completed: ${event.runId} (check with \\`neo runs\\`)`;\n case \"internal\":\n return `Internal event: ${event.eventKind}`;\n }\n}\n\n// ─── Event count helper ─────────────────────────────────\n\nfunction countEvents(grouped: GroupedEvents): number {\n return grouped.messages.length + grouped.webhooks.length + grouped.runCompletions.length;\n}\n\n// ─── Idle prompt (minimal — no events, no runs, no tasks) ─\n\n/**\n * Check if this heartbeat has nothing to do.\n */\nexport function isIdleHeartbeat(opts: PromptOptions): boolean {\n const hasWork = buildWorkQueueSection(opts.memories) !== \"\";\n return countEvents(opts.grouped) === 0 && opts.activeRuns.length === 0 && !hasWork;\n}\n\n/**\n * Build the idle prompt.\n * Used when there are no events, no active runs, and no pending tasks.\n * If repos are configured and budget allows, instructs the supervisor to dispatch a scout.\n */\nexport function buildIdlePrompt(opts: StandardPromptOptions): string {\n const budgetLine = `Budget: $${opts.budgetStatus.todayUsd.toFixed(2)} / $${opts.budgetStatus.capUsd.toFixed(2)} (${opts.budgetStatus.remainingPct.toFixed(0)}% remaining)`;\n const hasRepos = opts.repos.length > 0;\n const hasBudget = opts.budgetStatus.remainingPct > 10;\n const hasPendingDecisions = (opts.pendingDecisions?.length ?? 0) > 0;\n\n // If no repos or no budget, just yield\n if (!hasRepos || !hasBudget) {\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n</context>\n\n<directive>\nNothing to do. Run \\`neo log discovery \"idle\"\\` and yield. Do not produce any other output.\n</directive>`;\n }\n\n const repoList = opts.repos.map((r) => `- ${r.path} (branch: ${r.defaultBranch})`).join(\"\\n\");\n\n // If there are pending decisions from a previous scout\n if (hasPendingDecisions) {\n const pendingSection = buildPendingDecisionsSection(opts.pendingDecisions, opts.autoDecide);\n\n // In autoDecide mode, supervisor should answer decisions instead of waiting\n if (opts.autoDecide) {\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\n${pendingSection}\n\nRepositories:\n${repoList}\n</context>\n\n<reference>\n${getCommandsSection(opts.heartbeatCount)}\n</reference>\n\n<directive>\nIdle — but there are pending decisions to resolve. You are in **autoDecide** mode: answer each pending decision now using your best engineering judgment, then yield. You MAY merge branches when PRs are ready (CI green, reviews approved).\n</directive>`;\n }\n\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\n${pendingSection}\n\nRepositories:\n${repoList}\n</context>\n\n<directive>\nIdle — but there are pending decisions awaiting user response.\nRun \\`neo log discovery \"idle — waiting on ${String(opts.pendingDecisions?.length ?? 0)} pending decision(s)\"\\` and yield.\n</directive>`;\n }\n\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\nRepositories:\n${repoList}\n</context>\n\n<reference>\n${getCommandsSection(opts.heartbeatCount)}\n</reference>\n\n<directive>\nIdle — no work in progress. Use this downtime to dispatch a \\`scout\\` agent on one of your repositories.\n\nThe scout explores the codebase and surfaces bugs, improvements, security issues, and tech debt. It creates decisions (via \\`neo decision create\\`) for each critical or high-impact finding, so the user can choose what to act on.\n\n**Rules:**\n- Pick the repo that was least recently scouted (check your memory for previous scout runs).\n- Only ONE scout at a time — never dispatch multiple scouts in parallel.\n- Use \\`--branch main\\` (or the repo's default branch) — scouts are read-only.\n- Log your decision before dispatching.\n\n**Example:**\n\\`\\`\\`bash\nneo log decision \"Idle — dispatching scout on <repo>\"\nneo run scout --prompt \"Explore this repository. Surface bugs, improvements, security issues, and tech debt. Create decisions for critical and high-impact findings.\" \\\\\n --repo <path> \\\\\n --branch <default-branch> \\\\\n --meta '{\"stage\":\"scout\",\"label\":\"scout-<repo-name>\"}'\n\\`\\`\\`\n</directive>`;\n}\n\n// ─── Standard prompt ────────────────────────────────────\n\n/**\n * Build the standard heartbeat prompt (4 out of 5 heartbeats).\n *\n * Structure (Anthropic best practices: data top, instructions bottom):\n * <role> — Identity only\n * <context> — Focus \\u2192 work state \\u2192 knowledge \\u2192 environment \\u2192 events (query last)\n * <reference> — Command documentation\n * <instructions> — Principles \\u2192 lifecycle \\u2192 reporting \\u2192 memory \\u2192 directive\n */\nexport function buildStandardPrompt(opts: StandardPromptOptions): string {\n const instructionParts = buildBaseInstructions(opts, { includeExamples: false });\n const hasEvents = countEvents(opts.grouped) > 0;\n\n instructionParts.push(\n hasEvents\n ? \"Process events, dispatch eligible work, yield. Each heartbeat costs ~$0.10 \\u2014 be efficient.\"\n : \"No events. If pending work exists, dispatch it. Otherwise yield immediately.\",\n );\n\n return [\n buildRoleSection(opts.heartbeatCount),\n buildFullContext(opts),\n buildReferenceSection(opts.heartbeatCount),\n wrapInstructions(instructionParts),\n ].join(\"\\n\\n\");\n}\n\n// ─── Consolidation prompt ────────────────────────────────\n\n/**\n * Build the consolidation heartbeat prompt (1 out of 5 heartbeats).\n */\nexport function buildConsolidationPrompt(opts: ConsolidationPromptOptions): string {\n const instructionParts = buildBaseInstructions(opts, { includeExamples: true });\n\n instructionParts.push(\n `### Consolidation\nThis is a CONSOLIDATION heartbeat.\n\n**Idle guard**: if there are NO active runs AND no new events since last consolidation, log \"idle, no changes\" and yield immediately. Do NOT re-validate facts you already reviewed.\n\nIf there IS active work, your job:\n\n1. **Review memory** \\u2014 check facts and procedures for accuracy. Remove outdated entries. Resolve contradictions (keep newer). Remove facts about completed work (merged PRs, finished initiatives).\n2. **Update focus** \\u2014 rewrite focus using the MANDATORY structured format (ACTIVE/PENDING/WAITING/PROCESSED). Remove resolved items. Add new context.\n3. **Pattern escalation** \\u2014 if agents hit the same issue 3+ times (check recent actions), write a \\`procedure\\` to prevent recurrence.\n4. **Prune completed work** \\u2014 if a PR is merged or an initiative is done, forget related facts that are no longer actionable. Keep only reusable architectural truths.\n5. **Prune done tasks** \\u2014 forget tasks with outcome \\`done\\` or \\`abandoned\\` older than 7 days.`,\n );\n\n return [\n buildRoleSection(opts.heartbeatCount, \"CONSOLIDATION\"),\n buildFullContext(opts),\n buildReferenceSection(opts.heartbeatCount),\n wrapInstructions(instructionParts),\n ].join(\"\\n\\n\");\n}\n\n// ─── Compaction prompt ──────────────────────────────────\n\n/**\n * Build the compaction heartbeat prompt (every ~50 heartbeats).\n */\nexport function buildCompactionPrompt(opts: ConsolidationPromptOptions): string {\n const notesDir = `${opts.supervisorDir}/notes`;\n const instructionParts = buildBaseInstructions(opts, { includeExamples: true });\n\n instructionParts.push(`### Compaction\nThis is a COMPACTION heartbeat. Deep-clean your ENTIRE memory.\n\n1. **Remove stale facts** \\u2014 facts >7 days old with no recent reinforcement. Check the \"(last accessed Xd ago)\" hints in the facts section.\n2. **Remove completed-work facts** \\u2014 if all PRs for a repo initiative are merged/closed, forget related facts. Keep only reusable architectural truths (build system, CI config, tooling).\n3. **Remove trivial facts** \\u2014 file counts, line numbers, structural details that \\`ls\\` or \\`cat package.json\\` can answer. These waste context.\n4. **Merge duplicates** \\u2014 combine similar facts within the same scope into one.\n5. **Clean up focus** \\u2014 forget resolved items, rewrite remaining in structured format.\n6. **Prune done tasks** \\u2014 forget tasks with outcome \\`done\\` or \\`abandoned\\` older than 7 days.\n7. **Delete completed notes** from \\`${notesDir}/\\` directory.\n8. **Stay under 15 facts per scope** \\u2014 prioritize facts that affect dispatch decisions.\n\nFlag contradictions: if two facts contradict, keep the newer one.\n\n\\`\\`\\`bash\nneo memory list --type fact\nneo memory forget <stale-id>\n\\`\\`\\``);\n\n return [\n buildRoleSection(opts.heartbeatCount, \"COMPACTION\"),\n buildCompactionContext(opts),\n buildReferenceSection(opts.heartbeatCount),\n wrapInstructions(instructionParts),\n ].join(\"\\n\\n\");\n}\n","import { z } from \"zod\";\n\n// ─── Supervisor started event ────────────────────────────\n\nexport const supervisorStartedEventSchema = z.object({\n type: z.literal(\"supervisor_started\"),\n supervisorId: z.string(),\n startedAt: z.string().datetime(),\n});\n\nexport type SupervisorStartedEvent = z.infer<typeof supervisorStartedEventSchema>;\n\n// ─── Heartbeat event ─────────────────────────────────────\n\nexport const heartbeatEventSchema = z.object({\n type: z.literal(\"heartbeat\"),\n supervisorId: z.string(),\n heartbeatNumber: z.number().int().min(0),\n timestamp: z.string().datetime(),\n runsActive: z.number().int().min(0),\n budget: z.object({\n todayUsd: z.number().min(0),\n limitUsd: z.number().min(0),\n }),\n});\n\nexport type HeartbeatEvent = z.infer<typeof heartbeatEventSchema>;\n\n// ─── Run dispatched event ────────────────────────────────\n\nexport const runDispatchedEventSchema = z.object({\n type: z.literal(\"run_dispatched\"),\n supervisorId: z.string(),\n runId: z.string(),\n agent: z.string(),\n repo: z.string(),\n branch: z.string(),\n prompt: z.string().max(500), // truncated\n});\n\nexport type RunDispatchedEvent = z.infer<typeof runDispatchedEventSchema>;\n\n// ─── Run completed event ─────────────────────────────────\n\nexport const runCompletedEventSchema = z.object({\n type: z.literal(\"run_completed\"),\n supervisorId: z.string(),\n runId: z.string(),\n status: z.enum([\"completed\", \"failed\", \"cancelled\"]),\n output: z.string().max(1000).optional(), // truncated\n costUsd: z.number().min(0),\n durationMs: z.number().int().min(0),\n});\n\nexport type RunCompletedEvent = z.infer<typeof runCompletedEventSchema>;\n\n// ─── Supervisor stopped event ────────────────────────────\n\nexport const supervisorStoppedEventSchema = z.object({\n type: z.literal(\"supervisor_stopped\"),\n supervisorId: z.string(),\n stoppedAt: z.string().datetime(),\n reason: z.enum([\"shutdown\", \"budget_exceeded\", \"error\", \"manual\"]),\n});\n\nexport type SupervisorStoppedEvent = z.infer<typeof supervisorStoppedEventSchema>;\n\n// ─── Union of all webhook events ─────────────────────────\n\nexport const supervisorWebhookEventSchema = z.discriminatedUnion(\"type\", [\n supervisorStartedEventSchema,\n heartbeatEventSchema,\n runDispatchedEventSchema,\n runCompletedEventSchema,\n supervisorStoppedEventSchema,\n]);\n\nexport type SupervisorWebhookEvent = z.infer<typeof supervisorWebhookEventSchema>;\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { appendFile } from \"node:fs/promises\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { WebhookIncomingEvent } from \"./schemas.js\";\n\nconst MAX_BODY_SIZE = 1024 * 1024; // 1MB\n\ninterface WebhookServerOptions {\n port: number;\n secret?: string | undefined;\n eventsPath: string;\n onEvent: (event: WebhookIncomingEvent) => void;\n getHealth: () => Record<string, unknown>;\n}\n\n/**\n * Minimal HTTP server for receiving incoming webhooks.\n *\n * Routes:\n * POST /webhook — receive any JSON payload, persist to disk, push to queue\n * GET /health — liveness check with daemon status\n *\n * Uses raw http.createServer — zero external dependencies.\n */\nexport class WebhookServer {\n private server: Server | null = null;\n private readonly port: number;\n private readonly secret: string | undefined;\n private readonly eventsPath: string;\n private readonly onEvent: (event: WebhookIncomingEvent) => void;\n private readonly getHealth: () => Record<string, unknown>;\n\n constructor(options: WebhookServerOptions) {\n this.port = options.port;\n this.secret = options.secret;\n this.eventsPath = options.eventsPath;\n this.onEvent = options.onEvent;\n this.getHealth = options.getHealth;\n }\n\n async start(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.server = createServer((req, res) => {\n this.handleRequest(req, res).catch((err) => {\n this.sendJson(res, 500, { error: \"Internal server error\", detail: String(err) });\n });\n });\n\n this.server.on(\"error\", reject);\n\n this.server.listen(this.port, () => {\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n return new Promise<void>((resolve) => {\n if (!this.server) {\n resolve();\n return;\n }\n this.server.close(() => resolve());\n });\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url ?? \"/\";\n\n if (req.method === \"GET\" && url === \"/health\") {\n this.sendJson(res, 200, this.getHealth());\n return;\n }\n\n if (req.method === \"POST\" && url === \"/webhook\") {\n await this.handleWebhook(req, res);\n return;\n }\n\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n\n private async handleWebhook(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // Read body first (needed for both parsing and HMAC verification)\n const body = await this.readBody(req);\n if (body === null) {\n this.sendJson(res, 413, { error: \"Payload too large (max 1MB)\" });\n return;\n }\n\n // Validate HMAC signature if secret is configured\n if (this.secret) {\n const signature = req.headers[\"x-neo-signature\"] as string | undefined;\n if (!signature) {\n this.sendJson(res, 401, { error: \"Missing X-Neo-Signature header\" });\n return;\n }\n\n const expected = createHmac(\"sha256\", this.secret).update(body).digest(\"hex\");\n const expectedBuf = Buffer.from(expected, \"utf-8\");\n const actualBuf = Buffer.from(signature, \"utf-8\");\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {\n this.sendJson(res, 403, { error: \"Invalid signature\" });\n return;\n }\n }\n\n // Parse JSON\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch {\n this.sendJson(res, 400, { error: \"Invalid JSON\" });\n return;\n }\n\n const event: WebhookIncomingEvent = {\n id: typeof parsed.id === \"string\" ? parsed.id : undefined,\n source: typeof parsed.source === \"string\" ? parsed.source : undefined,\n event: typeof parsed.event === \"string\" ? parsed.event : undefined,\n payload: (parsed.payload as Record<string, unknown> | undefined) ?? parsed,\n receivedAt: new Date().toISOString(),\n };\n\n // Disk-first: persist before pushing to memory\n await appendFile(this.eventsPath, `${JSON.stringify(event)}\\n`, \"utf-8\");\n\n // Push to in-memory queue\n this.onEvent(event);\n\n this.sendJson(res, 200, { ok: true, id: event.id });\n }\n\n private readBody(req: IncomingMessage): Promise<string | null> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n let size = 0;\n\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_SIZE) {\n resolve(null);\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n\n req.on(\"end\", () => {\n resolve(Buffer.concat(chunks).toString(\"utf-8\"));\n });\n\n req.on(\"error\", () => resolve(null));\n });\n }\n\n private sendJson(res: ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n ActivityEntry,\n ActivityQueryOptions,\n SupervisorDaemonState,\n SupervisorStatus,\n} from \"./schemas.js\";\nimport { activityEntrySchema, supervisorDaemonStateSchema } from \"./schemas.js\";\n\nconst STATE_FILE = \"state.json\";\nconst ACTIVITY_FILE = \"activity.jsonl\";\n\n/**\n * Reads supervisor status from the daemon state file.\n * Returns null if the supervisor is not running or state file doesn't exist.\n */\nexport class StatusReader {\n readonly dataDir: string;\n private readonly statePath: string;\n private readonly activityPath: string;\n\n constructor(dataDir: string) {\n this.dataDir = dataDir;\n this.statePath = path.join(dataDir, STATE_FILE);\n this.activityPath = path.join(dataDir, ACTIVITY_FILE);\n }\n\n /**\n * Read and parse supervisor status from disk.\n * Returns null if the state file doesn't exist (supervisor not running).\n */\n async getStatus(): Promise<SupervisorStatus | null> {\n let raw: string;\n try {\n raw = await readFile(this.statePath, \"utf-8\");\n } catch {\n // File not found — supervisor not running\n return null;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n // Malformed JSON — treat as not running\n return null;\n }\n\n const result = supervisorDaemonStateSchema.safeParse(parsed);\n if (!result.success) {\n // Schema validation failed — state file is incompatible\n return null;\n }\n\n const daemon = result.data;\n\n // Map daemon status to API status\n const statusMap: Record<SupervisorDaemonState[\"status\"], SupervisorStatus[\"status\"]> = {\n running: \"running\",\n draining: \"stopping\",\n stopped: \"idle\",\n };\n\n // Read recent activity for summary\n const recentActivity = this.queryActivity({ limit: 5 });\n\n return {\n pid: daemon.pid,\n sessionId: daemon.sessionId,\n startedAt: daemon.startedAt,\n heartbeatCount: daemon.heartbeatCount,\n totalCostUsd: daemon.totalCostUsd,\n todayCostUsd: daemon.todayCostUsd,\n status: statusMap[daemon.status],\n lastHeartbeat: daemon.lastHeartbeat ?? daemon.startedAt,\n activeRunCount: 0, // TODO: count active runs from .neo/runs/\n recentActivitySummary: recentActivity.map((e) => `[${e.type}] ${e.summary}`),\n };\n }\n\n /**\n * Query activity entries with optional filtering.\n * Returns empty array if the activity file doesn't exist or is empty.\n */\n queryActivity(options: ActivityQueryOptions = {}): ActivityEntry[] {\n const { limit = 50, offset = 0, type, since, until } = options;\n\n let content: string;\n try {\n content = readFileSync(this.activityPath, \"utf-8\");\n } catch {\n // File not found — no activity yet\n return [];\n }\n\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n let entries: ActivityEntry[] = [];\n\n // Parse all valid entries\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line);\n const result = activityEntrySchema.safeParse(parsed);\n if (result.success) {\n entries.push(result.data);\n }\n } catch {\n // Skip malformed lines\n }\n }\n\n // Apply type filter\n if (type) {\n entries = entries.filter((e) => e.type === type);\n }\n\n // Apply date range filters\n if (since) {\n const sinceDate = new Date(since);\n entries = entries.filter((e) => new Date(e.timestamp) >= sinceDate);\n }\n\n if (until) {\n const untilDate = new Date(until);\n entries = entries.filter((e) => new Date(e.timestamp) <= untilDate);\n }\n\n // Apply offset and limit\n return entries.slice(offset, offset + limit);\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { removeSessionClone } from \"@/isolation/clone\";\nimport type { PersistedRun } from \"@/types\";\nimport type { ActivityLog } from \"./activity-log.js\";\n\n// ─── Constants ──────────────────────────────────────────\n\nconst GRACEFUL_TIMEOUT_MS = 30_000; // 30 seconds for graceful shutdown\nconst FORCE_KILL_DELAY_MS = 5_000; // 5 seconds before SIGKILL after SIGTERM\n\n// ─── Types ──────────────────────────────────────────────\n\nexport interface ShutdownOptions {\n /** Activity log for recording shutdown events */\n activityLog?: ActivityLog | undefined;\n /** Callback to invoke before shutdown begins */\n onShutdownStart?: () => void | Promise<void>;\n /** Callback to invoke after shutdown completes */\n onShutdownComplete?: () => void | Promise<void>;\n /** Timeout in milliseconds for graceful shutdown (default: 30s) */\n timeoutMs?: number | undefined;\n}\n\nexport interface ShutdownContext {\n /** Active child processes to terminate */\n childProcesses: Set<ChildProcess>;\n /** Active session clone paths to clean up */\n sessionPaths: Set<string>;\n /** Pending write operations to flush */\n pendingWrites: Set<Promise<void>>;\n /** Runs directory for marking runs as failed */\n runsDir?: string | undefined;\n}\n\nexport type ShutdownHandler = () => Promise<void>;\n\n// ─── ShutdownManager ────────────────────────────────────\n\n/**\n * Manages graceful shutdown for daemon and supervisor processes.\n *\n * Handles:\n * - SIGTERM and SIGINT signals\n * - Session clone cleanup\n * - Flushing pending writes\n * - Graceful child process termination\n *\n * Usage:\n * ```ts\n * const shutdown = new ShutdownManager({ activityLog });\n * shutdown.registerChildProcess(child);\n * shutdown.registerSession('/path/to/session');\n * shutdown.trackWrite(writePromise);\n * shutdown.install();\n * ```\n */\nexport class ShutdownManager {\n private readonly options: ShutdownOptions;\n private readonly context: ShutdownContext;\n private readonly handlers: Set<ShutdownHandler> = new Set();\n private isShuttingDown = false;\n private signalHandlersInstalled = false;\n private shutdownPromise: Promise<void> | null = null;\n\n constructor(options: ShutdownOptions = {}) {\n this.options = {\n timeoutMs: GRACEFUL_TIMEOUT_MS,\n ...options,\n };\n this.context = {\n childProcesses: new Set(),\n sessionPaths: new Set(),\n pendingWrites: new Set(),\n };\n }\n\n // ─── Registration ──────────────────────────────────────\n\n /**\n * Register a child process for graceful termination during shutdown.\n */\n registerChildProcess(child: ChildProcess): void {\n this.context.childProcesses.add(child);\n child.once(\"exit\", () => {\n this.context.childProcesses.delete(child);\n });\n }\n\n /**\n * Unregister a child process (e.g., after it has been terminated elsewhere).\n */\n unregisterChildProcess(child: ChildProcess): void {\n this.context.childProcesses.delete(child);\n }\n\n /**\n * Register a session clone path for cleanup during shutdown.\n */\n registerSession(sessionPath: string): void {\n this.context.sessionPaths.add(sessionPath);\n }\n\n /**\n * Unregister a session clone (e.g., after it has been cleaned up elsewhere).\n */\n unregisterSession(sessionPath: string): void {\n this.context.sessionPaths.delete(sessionPath);\n }\n\n /**\n * Track a pending write operation to flush during shutdown.\n * The promise is automatically removed when it settles.\n */\n trackWrite(writePromise: Promise<void>): void {\n this.context.pendingWrites.add(writePromise);\n writePromise.finally(() => {\n this.context.pendingWrites.delete(writePromise);\n });\n }\n\n /**\n * Register a custom shutdown handler.\n * Handlers are called in registration order during shutdown.\n */\n registerHandler(handler: ShutdownHandler): void {\n this.handlers.add(handler);\n }\n\n /**\n * Unregister a custom shutdown handler.\n */\n unregisterHandler(handler: ShutdownHandler): void {\n this.handlers.delete(handler);\n }\n\n /**\n * Set the runs directory for marking orphaned runs as failed.\n */\n setRunsDir(dir: string): void {\n this.context.runsDir = dir;\n }\n\n // ─── Installation ──────────────────────────────────────\n\n /**\n * Install signal handlers for SIGTERM and SIGINT.\n * Safe to call multiple times; handlers are only installed once.\n */\n install(): void {\n if (this.signalHandlersInstalled) return;\n\n const handler = (signal: string) => {\n this.initiateShutdown(signal).catch((error) => {\n // biome-ignore lint/suspicious/noConsole: Intentional daemon logging for shutdown errors\n console.error(`Shutdown error (${signal}):`, error);\n process.exit(1);\n });\n };\n\n process.on(\"SIGTERM\", () => handler(\"SIGTERM\"));\n process.on(\"SIGINT\", () => handler(\"SIGINT\"));\n\n this.signalHandlersInstalled = true;\n }\n\n /**\n * Manually trigger shutdown (e.g., from a stop() method).\n * Returns a promise that resolves when shutdown is complete.\n */\n async shutdown(): Promise<void> {\n return this.initiateShutdown(\"manual\");\n }\n\n // ─── Status ────────────────────────────────────────────\n\n /**\n * Check if shutdown is in progress.\n */\n get shuttingDown(): boolean {\n return this.isShuttingDown;\n }\n\n // ─── Internal ──────────────────────────────────────────\n\n private async initiateShutdown(signal: string): Promise<void> {\n // Ensure shutdown only runs once\n if (this.isShuttingDown) {\n return this.shutdownPromise ?? Promise.resolve();\n }\n\n this.isShuttingDown = true;\n this.shutdownPromise = this.executeShutdown(signal);\n return this.shutdownPromise;\n }\n\n private async executeShutdown(signal: string): Promise<void> {\n const { activityLog, onShutdownStart, onShutdownComplete, timeoutMs } = this.options;\n\n await activityLog?.log(\"event\", `Shutdown initiated (${signal})`);\n await onShutdownStart?.();\n\n // Race shutdown tasks against timeout\n const shutdownTasks = this.runShutdownTasks();\n const timeout = new Promise<void>((resolve) => {\n setTimeout(() => {\n activityLog?.log(\"error\", `Shutdown timeout (${timeoutMs}ms) exceeded, forcing exit`);\n resolve();\n }, timeoutMs);\n });\n\n await Promise.race([shutdownTasks, timeout]);\n\n await activityLog?.log(\"event\", \"Shutdown complete\");\n await onShutdownComplete?.();\n }\n\n private async runShutdownTasks(): Promise<void> {\n const { activityLog } = this.options;\n const { childProcesses, sessionPaths, pendingWrites, runsDir } = this.context;\n\n // Phase 1: Run custom handlers\n for (const handler of this.handlers) {\n try {\n await handler();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n await activityLog?.log(\"error\", `Shutdown handler failed: ${msg}`);\n }\n }\n\n // Phase 2: Flush pending writes\n if (pendingWrites.size > 0) {\n await activityLog?.log(\"event\", `Flushing ${pendingWrites.size} pending write(s)`);\n await Promise.allSettled([...pendingWrites]);\n }\n\n // Phase 3: Mark orphaned runs as failed\n if (runsDir) {\n await this.markOrphanedRunsFailed(runsDir, activityLog);\n }\n\n // Phase 4: Terminate child processes gracefully\n if (childProcesses.size > 0) {\n await activityLog?.log(\"event\", `Terminating ${childProcesses.size} child process(es)`);\n await this.terminateChildProcesses([...childProcesses], activityLog);\n }\n\n // Phase 5: Clean up session clones\n if (sessionPaths.size > 0) {\n await activityLog?.log(\"event\", `Cleaning up ${sessionPaths.size} session clone(s)`);\n await this.cleanupSessions([...sessionPaths], activityLog);\n }\n }\n\n private async terminateChildProcesses(\n processes: ChildProcess[],\n activityLog?: ActivityLog,\n ): Promise<void> {\n const terminations = processes.map(async (child) => {\n if (child.killed || child.exitCode !== null) {\n return; // Already terminated\n }\n\n const pid = child.pid;\n\n // Send SIGTERM first\n child.kill(\"SIGTERM\");\n\n // Wait for graceful exit or force kill\n await new Promise<void>((resolve) => {\n const forceKillTimer = setTimeout(() => {\n if (!child.killed && child.exitCode === null) {\n activityLog?.log(\"event\", `Force killing child process ${pid}`);\n child.kill(\"SIGKILL\");\n }\n resolve();\n }, FORCE_KILL_DELAY_MS);\n\n child.once(\"exit\", () => {\n clearTimeout(forceKillTimer);\n resolve();\n });\n });\n });\n\n await Promise.allSettled(terminations);\n }\n\n private async cleanupSessions(paths: string[], activityLog?: ActivityLog): Promise<void> {\n const cleanups = paths.map(async (sessionPath) => {\n try {\n await removeSessionClone(sessionPath);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n await activityLog?.log(\"error\", `Failed to cleanup session clone ${sessionPath}: ${msg}`);\n }\n });\n\n await Promise.allSettled(cleanups);\n }\n\n private async markOrphanedRunsFailed(runsDir: string, activityLog?: ActivityLog): Promise<void> {\n if (!existsSync(runsDir)) return;\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const subDir = path.join(runsDir, entry.name);\n const files = await readdir(subDir);\n\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n\n const filePath = path.join(subDir, file);\n await this.markRunAsFailed(filePath, activityLog);\n }\n }\n } catch {\n // Non-critical — best effort cleanup\n }\n }\n\n private async markRunAsFailed(filePath: string, activityLog?: ActivityLog): Promise<void> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n\n if (run.status !== \"running\") return;\n\n // Only mark as failed if this process owns the run\n if (run.pid && run.pid !== process.pid) return;\n\n run.status = \"failed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n\n await activityLog?.log(\"event\", `Marked orphaned run ${run.runId} as failed`);\n } catch {\n // Non-critical — file may be corrupt or locked\n }\n }\n}\n\n// ─── Utility Functions ──────────────────────────────────\n\n/**\n * Create and install a shutdown manager with the given options.\n * Returns the manager for registration of resources.\n */\nexport function createShutdownManager(options: ShutdownOptions = {}): ShutdownManager {\n const manager = new ShutdownManager(options);\n manager.install();\n return manager;\n}\n\n/**\n * Wait for a child process to exit with a timeout.\n * Returns true if the process exited, false if timeout was reached.\n */\nexport function waitForExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n if (child.killed || child.exitCode !== null) {\n resolve(true);\n return;\n }\n\n const timer = setTimeout(() => {\n resolve(false);\n }, timeoutMs);\n\n child.once(\"exit\", () => {\n clearTimeout(timer);\n resolve(true);\n });\n });\n}\n\n/**\n * Send SIGTERM to a child process and wait for exit, then SIGKILL if needed.\n * Returns true if the process exited gracefully, false if force killed.\n */\nexport async function terminateGracefully(\n child: ChildProcess,\n gracePeriodMs: number = FORCE_KILL_DELAY_MS,\n): Promise<boolean> {\n if (child.killed || child.exitCode !== null) {\n return true;\n }\n\n child.kill(\"SIGTERM\");\n const exited = await waitForExit(child, gracePeriodMs);\n\n if (!exited) {\n child.kill(\"SIGKILL\");\n await waitForExit(child, 1000);\n return false;\n }\n\n return true;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { getDataDir } from \"@/paths\";\n\n// ─── Webhook Entry Schema ───────────────────────────────\n\nexport const webhookEntrySchema = z.object({\n url: z.string().url(),\n events: z.array(z.string()).optional(),\n secret: z.string().optional(),\n timeoutMs: z.number().default(5000),\n createdAt: z.string().default(() => new Date().toISOString()),\n});\n\nexport type WebhookEntry = z.infer<typeof webhookEntrySchema>;\nexport type WebhookEntryInput = z.input<typeof webhookEntrySchema>;\n\n// ─── Webhooks Config Schema ─────────────────────────────\n\nconst webhooksConfigSchema = z.object({\n webhooks: z.array(webhookEntrySchema).default([]),\n});\n\ntype WebhooksConfig = z.infer<typeof webhooksConfigSchema>;\n\n// ─── File Path ──────────────────────────────────────────\n\nfunction getWebhooksConfigPath(): string {\n return path.join(getDataDir(), \"webhooks.json\");\n}\n\n// ─── Loaders ────────────────────────────────────────────\n\nasync function loadWebhooksConfig(): Promise<WebhooksConfig> {\n const configPath = getWebhooksConfigPath();\n\n if (!existsSync(configPath)) {\n return { webhooks: [] };\n }\n\n const raw = await readFile(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n return webhooksConfigSchema.parse(parsed);\n}\n\nasync function saveWebhooksConfig(config: WebhooksConfig): Promise<void> {\n const configPath = getWebhooksConfigPath();\n await mkdir(getDataDir(), { recursive: true });\n await writeFile(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\n// ─── CRUD Operations ────────────────────────────────────\n\n/**\n * Add a webhook endpoint to ~/.neo/webhooks.json.\n * Deduplicates by URL.\n */\nexport async function addWebhook(input: WebhookEntryInput): Promise<WebhookEntry> {\n const config = await loadWebhooksConfig();\n const entry = webhookEntrySchema.parse(input);\n\n const existing = config.webhooks.findIndex((w) => w.url === entry.url);\n if (existing >= 0) {\n config.webhooks[existing] = entry;\n } else {\n config.webhooks.push(entry);\n }\n\n await saveWebhooksConfig(config);\n return entry;\n}\n\n/**\n * Remove a webhook endpoint by URL.\n * Returns true if removed, false if not found.\n */\nexport async function removeWebhook(url: string): Promise<boolean> {\n const config = await loadWebhooksConfig();\n const initialLength = config.webhooks.length;\n\n config.webhooks = config.webhooks.filter((w) => w.url !== url);\n\n if (config.webhooks.length === initialLength) {\n return false;\n }\n\n await saveWebhooksConfig(config);\n return true;\n}\n\n/**\n * List all configured webhooks.\n */\nexport async function listWebhooks(): Promise<WebhookEntry[]> {\n const config = await loadWebhooksConfig();\n return config.webhooks;\n}\n\n// ─── Test Webhook Payload ───────────────────────────────\n\nexport interface WebhookTestPayload {\n type: \"test\";\n timestamp: string;\n runId: string;\n status: \"test\";\n summary: string;\n}\n\nexport interface WebhookTestResult {\n url: string;\n success: boolean;\n statusCode?: number;\n error?: string;\n durationMs: number;\n}\n\n/**\n * Send a test payload to all configured webhooks.\n * Returns results for each endpoint.\n */\nexport async function testWebhooks(): Promise<WebhookTestResult[]> {\n const webhooks = await listWebhooks();\n\n if (webhooks.length === 0) {\n return [];\n }\n\n const payload: WebhookTestPayload = {\n type: \"test\",\n timestamp: new Date().toISOString(),\n runId: `test-${Date.now()}`,\n status: \"test\",\n summary: \"Test webhook from neo CLI\",\n };\n\n const results = await Promise.all(\n webhooks.map(async (webhook): Promise<WebhookTestResult> => {\n const start = Date.now();\n const body = JSON.stringify(payload);\n\n try {\n const response = await fetch(webhook.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body,\n signal: AbortSignal.timeout(webhook.timeoutMs),\n });\n\n return {\n url: webhook.url,\n success: response.ok,\n statusCode: response.status,\n durationMs: Date.now() - start,\n };\n } catch (err) {\n return {\n url: webhook.url,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n durationMs: Date.now() - start,\n };\n }\n }),\n );\n\n return results;\n}\n","export const VERSION = \"0.1.0\";\n\n// ─── Orchestrator (public API) ──────────────────────────\n\nexport { loadAgentFile } from \"@/agents/loader\";\nexport { AgentRegistry } from \"@/agents/registry\";\nexport { resolveAgent } from \"@/agents/resolver\";\nexport {\n agentConfigSchema,\n agentModelSchema,\n agentSandboxSchema,\n agentToolEntrySchema,\n agentToolSchema,\n} from \"@/agents/schema\";\nexport type {\n SemaphoreCallbacks,\n SemaphoreConfig,\n} from \"@/concurrency/semaphore\";\n// ─── Concurrency ────────────────────────────────────────\nexport { Semaphore } from \"@/concurrency/semaphore\";\nexport type {\n GlobalConfig,\n McpServerConfig,\n NeoConfig,\n RepoConfig,\n RepoConfigInput,\n} from \"@/config\";\nexport {\n addRepoToGlobalConfig,\n ConfigStore,\n globalConfigSchema,\n listReposFromGlobalConfig,\n loadConfig,\n loadGlobalConfig,\n mcpServerConfigSchema,\n neoConfigSchema,\n removeRepoFromGlobalConfig,\n repoConfigSchema,\n repoOverrideConfigSchema,\n} from \"@/config\";\n// ─── Cost ──────────────────────────────────────────────\nexport { CostJournal } from \"@/cost/journal\";\n// ─── Events ────────────────────────────────────────────\nexport {\n EventJournal,\n matchesFilter,\n NeoEventEmitter,\n WebhookDispatcher,\n} from \"@/events\";\nexport type { SessionCloneInfo } from \"@/isolation/clone\";\n// ─── Isolation ──────────────────────────────────────────\nexport {\n createSessionClone,\n listSessionClones,\n removeSessionClone,\n} from \"@/isolation/clone\";\nexport {\n createBranch,\n deleteBranch,\n fetchRemote,\n getBranchName,\n getCurrentBranch,\n pushBranch,\n pushSessionBranch,\n} from \"@/isolation/git\";\nexport type { SandboxConfig } from \"@/isolation/sandbox\";\nexport { buildSandboxConfig } from \"@/isolation/sandbox\";\nexport type { AuditLogMiddleware } from \"@/middleware/audit-log\";\n// ─── Middleware ─────────────────────────────────────────\nexport { auditLog } from \"@/middleware/audit-log\";\nexport { budgetGuard } from \"@/middleware/budget-guard\";\nexport type { MiddlewareChain, SDKHooks } from \"@/middleware/chain\";\nexport { buildMiddlewareChain, buildSDKHooks } from \"@/middleware/chain\";\nexport type { LoopDetectionMiddleware } from \"@/middleware/loop-detection\";\nexport { loopDetection } from \"@/middleware/loop-detection\";\nexport type { OrchestratorOptions } from \"@/orchestrator\";\nexport { Orchestrator } from \"@/orchestrator\";\n// ─── Paths ─────────────────────────────────────────────\nexport {\n getDataDir,\n getJournalsDir,\n getRepoRunsDir,\n getRunDispatchPath,\n getRunLogPath,\n getRunsDir,\n getSupervisorActivityPath,\n getSupervisorDecisionsPath,\n getSupervisorDir,\n getSupervisorEventsPath,\n getSupervisorInboxPath,\n getSupervisorLockPath,\n getSupervisorStatePath,\n getSupervisorsDir,\n toRepoSlug,\n} from \"@/paths\";\nexport type { ParsedOutput } from \"@/runner/output-parser\";\n// ─── Runner ────────────────────────────────────────────\nexport { parseOutput } from \"@/runner/output-parser\";\nexport type { RecoveryOptions } from \"@/runner/recovery\";\nexport { runWithRecovery } from \"@/runner/recovery\";\nexport type {\n SessionEvent,\n SessionOptions,\n SessionResult,\n} from \"@/runner/session\";\nexport { runSession, SessionError } from \"@/runner/session\";\nexport type {\n SessionExecutionConfig,\n SessionExecutionDeps,\n SessionExecutionInput,\n SessionExecutionResult,\n} from \"@/runner/session-executor\";\nexport {\n buildFullPrompt,\n buildGitStrategyInstructions,\n buildReportingInstructions,\n loadRepoInstructions,\n SessionExecutor,\n} from \"@/runner/session-executor\";\n// ─── Process utilities ─────────────────────────────────\nexport { isProcessAlive } from \"@/shared/process\";\nexport type { SupervisorState } from \"@/supervisor\";\n// ─── Supervisor (legacy) ──────────────────────────────\nexport { supervisorStateSchema } from \"@/supervisor\";\n// ─── Decisions ─────────────────────────────────────────\nexport type {\n ActivityEntry,\n ActivityQueryOptions,\n Decision,\n DecisionInput,\n DecisionOption,\n HeartbeatLoopOptions,\n InboxMessage,\n QueuedEvent,\n SupervisorDaemonOptions,\n SupervisorDaemonState,\n SupervisorStatus,\n WebhookIncomingEvent,\n} from \"@/supervisor/index\";\n// ─── Supervisor (daemon) ──────────────────────────────\nexport {\n ActivityLog,\n activityEntrySchema,\n appendLogBuffer,\n DecisionStore,\n decisionOptionSchema,\n decisionSchema,\n EventQueue,\n HeartbeatLoop,\n inboxMessageSchema,\n StatusReader,\n SupervisorDaemon,\n supervisorDaemonStateSchema,\n supervisorStatusSchema,\n WebhookServer,\n webhookIncomingEventSchema,\n} from \"@/supervisor/index\";\nexport type {\n Embedder,\n MemoryEntry,\n MemoryQuery,\n MemoryStats,\n MemoryType,\n MemoryWriteInput,\n} from \"@/supervisor/memory/index\";\n// ─── Memory ───────────────────────────────────────────\nexport { LocalEmbedder, MemoryStore } from \"@/supervisor/memory/index\";\nexport * from \"@/types\";\n// ─── Webhook Config ────────────────────────────────────\nexport type {\n WebhookEntry,\n WebhookEntryInput,\n WebhookTestPayload,\n WebhookTestResult,\n} from \"@/webhook-config\";\nexport {\n addWebhook,\n listWebhooks,\n removeWebhook,\n testWebhooks,\n webhookEntrySchema,\n} from \"@/webhook-config\";\n"],"mappings":"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","names":["path","path","resolve","existsSync","readFile","path","parseYaml","path","z","path","homedir","parseYaml","homedir","parseYaml","homedir","join","parseYaml","readFile","path","existsSync","readFile","path","mkdir","readFile","EventEmitter","appendFile","appendFile","resolve","existsSync","mkdir","readdir","execFile","resolve","promisify","execFileAsync","GIT_TIMEOUT","resolve","appendFile","mkdir","path","ensureDir","randomUUID","existsSync","mkdir","readFile","path","existsSync","mkdir","readdir","readFile","writeFile","path","mkdir","path","writeFile","existsSync","readdir","readFile","readFile","path","resolve","z","randomUUID","existsSync","path","limit","path","resolve","mkdir","randomUUID","strategy","existsSync","readdir","readFile","z","randomUUID","appendFile","readFile","writeFile","path","z","z","path","randomUUID","appendFile","readFile","writeFile","z","randomUUID","appendFile","readFile","path","randomUUID","existsSync","mkdir","readFile","rm","writeFile","homedir","path","watch","readFile","writeFile","resolve","randomUUID","existsSync","readdir","readFile","writeFile","homedir","path","z","appendFile","readFile","stat","writeFile","path","path","readFile","readFile","writeFile","appendFile","z","path","randomUUID","homedir","resolve","readFile","writeFile","existsSync","readdir","createHmac","appendFile","resolve","mkdir","path","existsSync","rm","writeFile","rename","randomUUID","homedir","readFile","readFileSync","readFile","path","ACTIVITY_FILE","path","readFile","readFileSync","existsSync","readdir","readFile","writeFile","path","existsSync","mkdir","readFile","writeFile","path","z","z","path","existsSync","readFile","mkdir","writeFile"]}
1
+ {"version":3,"sources":["../src/agents/loader.ts","../src/agents/schema.ts","../src/agents/registry.ts","../src/agents/resolver.ts","../src/concurrency/queue.ts","../src/concurrency/semaphore.ts","../src/config.ts","../src/paths.ts","../src/config/schema.ts","../src/config/dotNotation.ts","../src/config/merge.ts","../src/config/ConfigStore.ts","../src/config/ConfigWatcher.ts","../src/config/parser.ts","../src/cost/journal.ts","../src/shared/date.ts","../src/shared/fs.ts","../src/events/emitter.ts","../src/events/journal.ts","../src/events/webhook.ts","../src/isolation/clone.ts","../src/isolation/git.ts","../src/isolation/sandbox.ts","../src/middleware/audit-log.ts","../src/middleware/budget-guard.ts","../src/middleware/chain.ts","../src/middleware/loop-detection.ts","../src/orchestrator.ts","../src/orchestrator/run-store.ts","../src/shared/process.ts","../src/orchestrator/prompt-builder.ts","../src/runner/output-parser.ts","../src/sdk-types.ts","../src/runner/session.ts","../src/runner/recovery.ts","../src/runner/session-executor.ts","../src/supervisor/memory/embedder.ts","../src/supervisor/memory/entry.ts","../src/supervisor/memory/format.ts","../src/supervisor/memory/store.ts","../src/supervisor/schemas.ts","../src/supervisor/decisions.ts","../src/supervisor/activity-log.ts","../src/supervisor/daemon.ts","../src/supervisor/event-queue.ts","../src/supervisor/heartbeat.ts","../src/supervisor/idle-detector.ts","../src/supervisor/log-buffer.ts","../src/supervisor/prompt-builder.ts","../src/supervisor/webhookEvents.ts","../src/supervisor/webhook-server.ts","../src/supervisor/StatusReader.ts","../src/supervisor/shutdown.ts","../src/webhook-config.ts","../src/index.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { AgentConfig } from \"@/agents/schema\";\nimport { agentConfigSchema } from \"@/agents/schema\";\n\n/**\n * Load a single agent definition from a YAML file.\n * If the `prompt` field points to a .md file, resolve it relative\n * to the YAML file's directory and read its content.\n */\nexport async function loadAgentFile(filePath: string): Promise<AgentConfig> {\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf-8\");\n } catch {\n throw new Error(`Agent file not found: ${filePath}`);\n }\n\n let parsed: unknown;\n try {\n parsed = parseYaml(raw);\n } catch (err) {\n throw new Error(\n `Invalid YAML in agent file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n const result = agentConfigSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Invalid agent config in ${filePath}:\\n${issues}`);\n }\n\n const config = result.data;\n\n // If prompt points to a .md file, read it\n if (config.prompt?.endsWith(\".md\")) {\n const promptPath = path.resolve(path.dirname(filePath), config.prompt);\n try {\n config.prompt = await readFile(promptPath, \"utf-8\");\n } catch (err) {\n // Expected error: prompt file not found\n throw new Error(\n `Prompt file not found: ${promptPath} (referenced in ${filePath}). Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return config;\n}\n","import { z } from \"zod\";\n\n// ─── Agent model enum ────────────────────────────────────\n\nexport const agentModelSchema = z.enum([\"opus\", \"sonnet\", \"haiku\"]);\n\n// ─── Agent tool enum ─────────────────────────────────────\n\nexport const agentToolSchema = z.enum([\n \"Read\",\n \"Write\",\n \"Edit\",\n \"Bash\",\n \"Glob\",\n \"Grep\",\n \"Agent\",\n \"WebSearch\",\n \"WebFetch\",\n \"NotebookEdit\",\n]);\n\n// ─── Agent tool entry (tool or $inherited token) ─────────\n\nexport const agentToolEntrySchema = z.union([agentToolSchema, z.literal(\"$inherited\")]);\n\n// ─── Agent sandbox enum ──────────────────────────────────\n\nexport const agentSandboxSchema = z.enum([\"writable\", \"readonly\"]);\n\n// ─── AgentConfig schema (from YAML) ─────────────────────\n\nexport const agentConfigSchema = z.object({\n name: z.string(),\n extends: z.string().optional(),\n description: z.string().optional(),\n model: agentModelSchema.optional(),\n tools: z.array(agentToolEntrySchema).optional(),\n prompt: z.string().optional(),\n promptAppend: z.string().optional(),\n sandbox: agentSandboxSchema.optional(),\n maxTurns: z.number().optional(),\n mcpServers: z.array(z.string()).optional(),\n});\n\n// ─── Derived types ───────────────────────────────────────\n\nexport type AgentConfig = z.infer<typeof agentConfigSchema>;\nexport type AgentModel = z.infer<typeof agentModelSchema>;\nexport type AgentTool = z.infer<typeof agentToolSchema>;\nexport type AgentToolEntry = z.infer<typeof agentToolEntrySchema>;\n","import { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { loadAgentFile } from \"@/agents/loader\";\nimport { resolveAgent } from \"@/agents/resolver\";\nimport type { AgentConfig } from \"@/agents/schema\";\nimport type { ResolvedAgent } from \"@/types\";\n\nexport class AgentRegistry {\n private readonly builtInDir: string;\n private readonly customDir: string | undefined;\n private agents = new Map<string, ResolvedAgent>();\n\n constructor(builtInDir: string, customDir?: string) {\n this.builtInDir = builtInDir;\n this.customDir = customDir;\n }\n\n async load(): Promise<void> {\n this.agents.clear();\n\n // Load built-in agents\n const builtInConfigs = await loadAgentsFromDir(this.builtInDir);\n const builtInMap = new Map<string, AgentConfig>();\n for (const config of builtInConfigs) {\n builtInMap.set(config.name, config);\n }\n\n // Resolve built-in agents\n for (const config of builtInConfigs) {\n const resolved = resolveAgent(config, builtInMap);\n // Force built-in source for agents loaded from the built-in dir\n this.agents.set(config.name, { ...resolved, source: \"built-in\" });\n }\n\n // Load custom agents (if directory exists)\n if (this.customDir) {\n let customConfigs: AgentConfig[];\n try {\n customConfigs = await loadAgentsFromDir(this.customDir);\n } catch (err) {\n // Custom dir doesn't exist — that's fine\n console.debug(\n `[registry] Custom agents dir not found: ${err instanceof Error ? err.message : String(err)}`,\n );\n customConfigs = [];\n }\n\n for (const config of customConfigs) {\n const resolved = resolveAgent(config, builtInMap);\n this.agents.set(config.name, resolved);\n }\n }\n }\n\n get(name: string): ResolvedAgent | undefined {\n return this.agents.get(name);\n }\n\n list(): ResolvedAgent[] {\n return [...this.agents.values()];\n }\n\n has(name: string): boolean {\n return this.agents.has(name);\n }\n}\n\nasync function loadAgentsFromDir(dir: string): Promise<AgentConfig[]> {\n const entries = await readdir(dir);\n const ymlFiles = entries.filter((f) => f.endsWith(\".yml\") || f.endsWith(\".yaml\"));\n\n const configs: AgentConfig[] = [];\n for (const file of ymlFiles) {\n const config = await loadAgentFile(path.join(dir, file));\n configs.push(config);\n }\n return configs;\n}\n","import type { AgentConfig, AgentTool } from \"@/agents/schema\";\nimport type { AgentDefinition, ResolvedAgent } from \"@/types\";\n\n/**\n * Resolve an agent config into a fully-merged ResolvedAgent.\n *\n * Resolution rules:\n * 1. No `extends` → agent must define all required fields\n * 2. With `extends: \"developer\"` → start from built-in, apply overrides\n * 3. Same name as built-in without `extends:` → treated as `extends: <name>` implicitly\n */\nexport function resolveAgent(\n config: AgentConfig,\n builtIns: Map<string, AgentConfig>,\n): ResolvedAgent {\n const extendsName =\n config.extends ??\n (builtIns.has(config.name) && config.extends === undefined ? config.name : undefined);\n\n if (extendsName !== undefined) {\n return resolveExtendedAgent(config, extendsName, builtIns);\n }\n\n return resolveCustomAgent(config);\n}\n\n// ─── Extended agent (inherits from built-in) ────────────\n\nfunction resolveExtendedAgent(\n config: AgentConfig,\n extendsName: string,\n builtIns: Map<string, AgentConfig>,\n): ResolvedAgent {\n const base = builtIns.get(extendsName);\n\n if (!base) {\n throw new Error(\n `Agent \"${config.name}\" extends \"${extendsName}\", but no built-in agent with that name exists.`,\n );\n }\n\n const tools = mergeTools(config.tools, base.tools);\n const prompt = mergePrompt(config.prompt, config.promptAppend, base.prompt);\n const mcpServers = mergeMcpServerNames(base.mcpServers, config.mcpServers);\n\n const definition: AgentDefinition = {\n description: config.description ?? base.description ?? \"\",\n prompt,\n tools,\n model: config.model ?? base.model ?? \"sonnet\",\n ...(mcpServers.length > 0 ? { mcpServers } : {}),\n };\n\n return {\n name: config.name,\n definition,\n sandbox: config.sandbox ?? base.sandbox ?? \"readonly\",\n ...(config.maxTurns !== undefined\n ? { maxTurns: config.maxTurns }\n : base.maxTurns !== undefined\n ? { maxTurns: base.maxTurns }\n : {}),\n source: config.name === extendsName && !config.extends ? \"built-in\" : \"extended\",\n };\n}\n\n// ─── Custom agent (no inheritance) ──────────────────────\n\nfunction resolveCustomAgent(config: AgentConfig): ResolvedAgent {\n if (!config.description) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"description\". Add a 'description' field to the agent YAML.`,\n );\n }\n if (!config.model) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"model\". Add a 'model' field (e.g., 'claude-sonnet-4-20250514').`,\n );\n }\n if (!config.tools) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"tools\". Add a 'tools' array to the agent YAML.`,\n );\n }\n if (!config.sandbox) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"sandbox\". Add a 'sandbox' field ('full' or 'permissive').`,\n );\n }\n if (!config.prompt) {\n throw new Error(\n `Agent \"${config.name}\" has no \"extends\" and no \"prompt\". Add a 'prompt' field or 'promptFile' reference.`,\n );\n }\n\n // Filter out $inherited from tools (shouldn't be there without extends, but be safe)\n const tools = config.tools.filter((t): t is AgentTool => t !== \"$inherited\");\n\n let prompt = config.prompt;\n if (config.promptAppend) {\n prompt = `${prompt}\\n\\n${config.promptAppend}`;\n }\n\n const definition: AgentDefinition = {\n description: config.description,\n prompt,\n tools,\n model: config.model,\n ...(config.mcpServers?.length ? { mcpServers: config.mcpServers } : {}),\n };\n\n return {\n name: config.name,\n definition,\n sandbox: config.sandbox,\n ...(config.maxTurns !== undefined ? { maxTurns: config.maxTurns } : {}),\n source: \"custom\",\n };\n}\n\n// ─── Helpers ────────────────────────────────────────────\n\nfunction mergeTools(configTools: AgentConfig[\"tools\"], baseTools: AgentConfig[\"tools\"]): string[] {\n if (!configTools) return (baseTools ?? []) as string[];\n if (configTools.includes(\"$inherited\")) {\n const newTools = configTools.filter((t) => t !== \"$inherited\");\n return [...(baseTools ?? []), ...newTools] as string[];\n }\n return configTools as string[];\n}\n\nfunction mergePrompt(\n configPrompt: string | undefined,\n promptAppend: string | undefined,\n basePrompt: string | undefined,\n): string {\n let prompt = configPrompt ?? basePrompt ?? \"\";\n if (promptAppend) {\n prompt = `${prompt}\\n\\n${promptAppend}`;\n }\n return prompt;\n}\n\nfunction mergeMcpServerNames(base: string[] | undefined, override: string[] | undefined): string[] {\n if (!base?.length && !override?.length) return [];\n return [...new Set([...(base ?? []), ...(override ?? [])])];\n}\n","import type { Priority } from \"@/types\";\n\nconst PRIORITY_ORDER: Record<Priority, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\ninterface QueueItem<T> {\n value: T;\n priority: Priority;\n insertionOrder: number;\n}\n\n/**\n * FIFO priority queue. Items with higher priority (critical > high > medium > low)\n * are dequeued first. Within the same priority level, FIFO order is maintained.\n */\nexport class PriorityQueue<T> {\n private readonly items: QueueItem<T>[] = [];\n private readonly maxSize: number;\n private insertionCounter = 0;\n\n constructor(maxSize: number) {\n this.maxSize = maxSize;\n }\n\n enqueue(value: T, priority: Priority): void {\n // Reset counter when queue is empty to prevent overflow after prolonged use\n if (this.items.length === 0) {\n this.insertionCounter = 0;\n }\n\n if (this.items.length >= this.maxSize) {\n throw new Error(`Queue full (${this.maxSize} items). Cannot enqueue.`);\n }\n\n const item: QueueItem<T> = {\n value,\n priority,\n insertionOrder: this.insertionCounter++,\n };\n\n // Insert in sorted position (binary search would be overkill for queue sizes ≤ 50)\n let inserted = false;\n for (let i = 0; i < this.items.length; i++) {\n const existing = this.items[i];\n if (existing && this.comparePriority(item, existing) < 0) {\n this.items.splice(i, 0, item);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n this.items.push(item);\n }\n }\n\n dequeue(): T | undefined {\n const item = this.items.shift();\n return item?.value;\n }\n\n peek(): T | undefined {\n return this.items[0]?.value;\n }\n\n get size(): number {\n return this.items.length;\n }\n\n get isEmpty(): boolean {\n return this.items.length === 0;\n }\n\n remove(predicate: (item: T) => boolean): boolean {\n const index = this.items.findIndex((entry) => predicate(entry.value));\n if (index === -1) return false;\n this.items.splice(index, 1);\n return true;\n }\n\n /** Dequeue the first item matching the predicate (respects priority order). */\n dequeueWhere(predicate: (item: T) => boolean): T | undefined {\n const index = this.items.findIndex((entry) => predicate(entry.value));\n if (index === -1) return undefined;\n const removed = this.items.splice(index, 1)[0];\n if (!removed) return undefined;\n return removed.value;\n }\n\n /** Compare by priority first, then by insertion order (FIFO within same priority). */\n private comparePriority(a: QueueItem<T>, b: QueueItem<T>): number {\n const priorityDiff = PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority];\n if (priorityDiff !== 0) return priorityDiff;\n return a.insertionOrder - b.insertionOrder;\n }\n}\n","import { PriorityQueue } from \"@/concurrency/queue\";\nimport type { Priority } from \"@/types\";\n\nexport interface SemaphoreConfig {\n maxSessions: number;\n maxPerRepo: number;\n queueMax?: number;\n}\n\nexport interface SemaphoreCallbacks {\n onEnqueue?: (sessionId: string, repo: string, position: number) => void;\n onDequeue?: (sessionId: string, repo: string, waitedMs: number) => void;\n}\n\ninterface WaitingEntry {\n sessionId: string;\n repo: string;\n resolve: () => void;\n reject: (reason: unknown) => void;\n enqueuedAt: number;\n _cleanupAbort?: () => void;\n}\n\n/**\n * Concurrency semaphore with global + per-repo limits and a priority queue.\n * When at capacity, `acquire()` blocks until a slot is available.\n */\nexport class Semaphore {\n private readonly maxSessions: number;\n private readonly maxPerRepo: number;\n private readonly queue: PriorityQueue<WaitingEntry>;\n private readonly callbacks: SemaphoreCallbacks;\n\n // sessionId → repo\n private readonly activeSessions = new Map<string, string>();\n // repo → count\n private readonly repoCounts = new Map<string, number>();\n\n constructor(config: SemaphoreConfig, callbacks: SemaphoreCallbacks = {}) {\n this.maxSessions = config.maxSessions;\n this.maxPerRepo = config.maxPerRepo;\n this.queue = new PriorityQueue<WaitingEntry>(config.queueMax ?? 50);\n this.callbacks = callbacks;\n }\n\n /**\n * Acquire a slot. Blocks (via promise) if at capacity.\n * Throws if the queue is full.\n */\n async acquire(\n repo: string,\n sessionId: string,\n priority: Priority = \"medium\",\n signal?: AbortSignal,\n ): Promise<void> {\n if (signal?.aborted) {\n throw signal.reason ?? new DOMException(\"The operation was aborted.\", \"AbortError\");\n }\n\n if (this.canAcquire(repo)) {\n this.allocate(repo, sessionId);\n return;\n }\n\n return new Promise<void>((resolve, reject) => {\n const entry: WaitingEntry = {\n sessionId,\n repo,\n resolve,\n reject,\n enqueuedAt: Date.now(),\n };\n\n this.queue.enqueue(entry, priority);\n this.callbacks.onEnqueue?.(sessionId, repo, this.queue.size);\n\n if (signal) {\n const onAbort = () => {\n this.queue.remove((e) => e === entry);\n reject(signal.reason ?? new DOMException(\"The operation was aborted.\", \"AbortError\"));\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n\n // Store cleanup so we can remove the listener on normal dequeue\n entry._cleanupAbort = () => signal.removeEventListener(\"abort\", onAbort);\n }\n });\n }\n\n /** Release a slot and process the next waiting entry. */\n release(sessionId: string): void {\n const repo = this.activeSessions.get(sessionId);\n if (!repo) return;\n\n this.activeSessions.delete(sessionId);\n const count = this.repoCounts.get(repo) ?? 0;\n if (count <= 1) {\n this.repoCounts.delete(repo);\n } else {\n this.repoCounts.set(repo, count - 1);\n }\n\n this.processQueue();\n }\n\n /** Non-blocking attempt to acquire a slot. Returns true if successful. */\n tryAcquire(repo: string, sessionId: string): boolean {\n if (!this.canAcquire(repo)) return false;\n this.allocate(repo, sessionId);\n return true;\n }\n\n /** Total number of active slots. */\n activeCount(): number {\n return this.activeSessions.size;\n }\n\n /** Number of active slots for a specific repo. */\n activeCountForRepo(repo: string): number {\n return this.repoCounts.get(repo) ?? 0;\n }\n\n /** Can a slot be acquired for this repo without blocking? */\n isAvailable(repo: string): boolean {\n return this.canAcquire(repo);\n }\n\n /** Current queue depth. */\n queueDepth(): number {\n return this.queue.size;\n }\n\n private canAcquire(repo: string): boolean {\n if (this.activeSessions.size >= this.maxSessions) return false;\n const repoCount = this.repoCounts.get(repo) ?? 0;\n return repoCount < this.maxPerRepo;\n }\n\n private allocate(repo: string, sessionId: string): void {\n this.activeSessions.set(sessionId, repo);\n this.repoCounts.set(repo, (this.repoCounts.get(repo) ?? 0) + 1);\n }\n\n private processQueue(): void {\n // Find the highest-priority entry whose repo has capacity\n const entry = this.queue.dequeueWhere((e) => this.canAcquire(e.repo));\n if (!entry) return;\n\n this.allocate(entry.repo, entry.sessionId);\n entry._cleanupAbort?.();\n const waitedMs = Date.now() - entry.enqueuedAt;\n this.callbacks.onDequeue?.(entry.sessionId, entry.repo, waitedMs);\n entry.resolve();\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport type { z } from \"zod\";\nimport { getDataDir, toRepoSlug } from \"@/paths\";\n\n// ─── Re-export all schemas and types from config module ──\n\nexport type {\n GitStrategy,\n GlobalConfig,\n McpServerConfig,\n NeoConfig,\n RepoConfig,\n RepoConfigInput,\n RepoOverrideConfig,\n} from \"@/config/index\";\nexport {\n budgetConfigSchema,\n ConfigStore,\n ConfigWatcher,\n concurrencyConfigSchema,\n gitStrategySchema,\n globalConfigSchema,\n journalConfigSchema,\n mcpServerConfigSchema,\n neoConfigSchema,\n recoveryConfigSchema,\n repoConfigSchema,\n repoOverrideConfigSchema,\n sessionsConfigSchema,\n supervisorConfigSchema,\n} from \"@/config/index\";\n\n// ─── Import schemas for internal use ─────────────────────\n\nimport type { NeoConfig, RepoConfig, RepoConfigInput } from \"@/config/index\";\nimport { globalConfigSchema, neoConfigSchema, repoConfigSchema } from \"@/config/index\";\n\n// ─── Default global config ──────────────────────────────\n\nconst DEFAULT_GLOBAL_CONFIG = {\n repos: [],\n concurrency: {\n maxSessions: 5,\n maxPerRepo: 4,\n queueMax: 50,\n },\n budget: {\n dailyCapUsd: 500,\n alertThresholdPct: 80,\n },\n};\n\n// ─── YAML loader helper ─────────────────────────────────\n\nfunction parseYamlFile(raw: string, filePath: string): unknown {\n try {\n return parseYaml(raw);\n } catch (err) {\n throw new Error(\n `Invalid YAML in ${filePath}: ${err instanceof Error ? err.message : String(err)}. Check YAML syntax at the indicated line.`,\n );\n }\n}\n\nfunction formatZodErrors(issues: z.ZodIssue[], filePath: string): string {\n const formatted = issues.map((i) => ` - ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\");\n return `Invalid config in ${filePath}:\\n${formatted}`;\n}\n\n// ─── Config loaders ─────────────────────────────────────\n\n/**\n * Load NeoConfig from a single file (legacy compatibility).\n */\nexport async function loadConfig(configPath: string): Promise<NeoConfig> {\n let raw: string;\n try {\n raw = await readFile(configPath, \"utf-8\");\n } catch (err) {\n // Expected error: config file not found\n throw new Error(\n `Config file not found: ${configPath}. Run 'neo init' to get started. (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n\n const parsed = parseYamlFile(raw, configPath);\n\n const result = neoConfigSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(formatZodErrors(result.error.issues, configPath));\n }\n\n return result.data;\n}\n\n/**\n * Load the global config from ~/.neo/config.yml.\n * Creates the file with defaults if it does not exist.\n */\nexport async function loadGlobalConfig(): Promise<NeoConfig> {\n const configPath = path.join(getDataDir(), \"config.yml\");\n\n if (!existsSync(configPath)) {\n await mkdir(getDataDir(), { recursive: true });\n await writeFile(configPath, stringifyYaml(DEFAULT_GLOBAL_CONFIG), \"utf-8\");\n return globalConfigSchema.parse(DEFAULT_GLOBAL_CONFIG);\n }\n\n const raw = await readFile(configPath, \"utf-8\");\n const parsed = parseYamlFile(raw, configPath);\n\n const result = globalConfigSchema.safeParse(parsed);\n if (!result.success) {\n throw new Error(formatZodErrors(result.error.issues, configPath));\n }\n\n return result.data;\n}\n\n// ─── Repo CRUD operations ───────────────────────────────\n\n/**\n * Add a repo to ~/.neo/config.yml. Deduplicates by resolved path.\n */\nexport async function addRepoToGlobalConfig(repo: RepoConfigInput): Promise<void> {\n const config = await loadGlobalConfig();\n const resolvedPath = path.resolve(repo.path);\n const parsed = repoConfigSchema.parse({ ...repo, path: resolvedPath });\n\n const existing = config.repos.findIndex((r) => path.resolve(r.path) === resolvedPath);\n if (existing >= 0) {\n config.repos[existing] = parsed;\n } else {\n config.repos.push(parsed);\n }\n\n const configPath = path.join(getDataDir(), \"config.yml\");\n await writeFile(configPath, stringifyYaml(config), \"utf-8\");\n}\n\n/**\n * Remove a repo from ~/.neo/config.yml by path, name, or slug.\n */\nexport async function removeRepoFromGlobalConfig(pathOrName: string): Promise<boolean> {\n const config = await loadGlobalConfig();\n const resolvedPath = path.resolve(pathOrName);\n const initialLength = config.repos.length;\n\n config.repos = config.repos.filter(\n (r) =>\n path.resolve(r.path) !== resolvedPath &&\n r.name !== pathOrName &&\n toRepoSlug(r) !== pathOrName,\n );\n\n if (config.repos.length === initialLength) return false;\n\n const configPath = path.join(getDataDir(), \"config.yml\");\n await writeFile(configPath, stringifyYaml(config), \"utf-8\");\n return true;\n}\n\n/**\n * List all registered repos from ~/.neo/config.yml.\n */\nexport async function listReposFromGlobalConfig(): Promise<RepoConfig[]> {\n const config = await loadGlobalConfig();\n return config.repos;\n}\n","import { homedir } from \"node:os\";\nimport path from \"node:path\";\n\n/**\n * Global data directory for runtime artifacts (journals, runs).\n * Located at ~/.neo, similar to how Claude Code uses ~/.claude.\n */\nexport function getDataDir(): string {\n return path.join(homedir(), \".neo\");\n}\n\nexport function getJournalsDir(): string {\n return path.join(getDataDir(), \"journals\");\n}\n\nexport function getRunsDir(): string {\n return path.join(getDataDir(), \"runs\");\n}\n\n/**\n * Derive a filesystem-safe slug from a repo config.\n * Uses `name` if present, otherwise `basename(path)`.\n */\nexport function toRepoSlug(repo: { name?: string | undefined; path: string }): string {\n const raw = repo.name ?? path.basename(repo.path);\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9._-]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/**\n * Runs directory for a specific repo: ~/.neo/runs/<slug>/\n */\nexport function getRepoRunsDir(repoSlug: string): string {\n return path.join(getRunsDir(), repoSlug);\n}\n\n/**\n * Path to the dispatch request file for a detached run.\n */\nexport function getRunDispatchPath(repoSlug: string, runId: string): string {\n return path.join(getRepoRunsDir(repoSlug), `${runId}.dispatch.json`);\n}\n\n/**\n * Path to the log file for a detached run.\n */\nexport function getRunLogPath(repoSlug: string, runId: string): string {\n return path.join(getRepoRunsDir(repoSlug), `${runId}.log`);\n}\n\n/**\n * Directory for all supervisor instances: ~/.neo/supervisors/\n */\nexport function getSupervisorsDir(): string {\n return path.join(getDataDir(), \"supervisors\");\n}\n\n/**\n * Directory for a specific supervisor instance: ~/.neo/supervisors/<name>/\n */\nexport function getSupervisorDir(name: string): string {\n return path.join(getSupervisorsDir(), name);\n}\n\n/**\n * Path to a supervisor state file: ~/.neo/supervisors/<name>/state.json\n */\nexport function getSupervisorStatePath(name: string): string {\n return path.join(getSupervisorDir(name), \"state.json\");\n}\n\nexport function getSupervisorActivityPath(name: string): string {\n return path.join(getSupervisorDir(name), \"activity.jsonl\");\n}\n\nexport function getSupervisorInboxPath(name: string): string {\n return path.join(getSupervisorDir(name), \"inbox.jsonl\");\n}\n\nexport function getSupervisorEventsPath(name: string): string {\n return path.join(getSupervisorDir(name), \"events.jsonl\");\n}\n\nexport function getSupervisorLockPath(name: string): string {\n return path.join(getSupervisorDir(name), \"daemon.lock\");\n}\n\nexport function getSupervisorDecisionsPath(name: string): string {\n return path.join(getSupervisorDir(name), \"decisions.jsonl\");\n}\n","import { z } from \"zod\";\n\n// ─── McpServerConfig schemas ─────────────────────────────\n\nconst httpMcpServerSchema = z.object({\n type: z.literal(\"http\"),\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n});\n\nconst stdioMcpServerSchema = z.object({\n type: z.literal(\"stdio\"),\n command: z.string(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n});\n\nexport const mcpServerConfigSchema = z.discriminatedUnion(\"type\", [\n httpMcpServerSchema,\n stdioMcpServerSchema,\n]);\n\n// ─── RepoConfig schema (single repo entry) ──────────────\n\nexport const gitStrategySchema = z.enum([\"pr\", \"branch\"]).default(\"branch\");\n\nexport type GitStrategy = z.infer<typeof gitStrategySchema>;\n\nexport const repoConfigSchema = z.object({\n path: z.string(),\n name: z.string().optional(),\n defaultBranch: z.string().default(\"main\"),\n branchPrefix: z.string().default(\"feat\"),\n pushRemote: z.string().default(\"origin\"),\n gitStrategy: gitStrategySchema,\n});\n\n// ─── Concurrency config schema ───────────────────────────\n\nexport const concurrencyConfigSchema = z\n .object({\n maxSessions: z.number().default(5),\n maxPerRepo: z.number().default(4),\n queueMax: z.number().default(50),\n })\n .default({ maxSessions: 5, maxPerRepo: 4, queueMax: 50 });\n\n// ─── Budget config schema ────────────────────────────────\n\nexport const budgetConfigSchema = z\n .object({\n dailyCapUsd: z.number().default(500),\n alertThresholdPct: z.number().default(80),\n })\n .default({ dailyCapUsd: 500, alertThresholdPct: 80 });\n\n// ─── Recovery config schema ──────────────────────────────\n\nexport const recoveryConfigSchema = z\n .object({\n maxRetries: z.number().default(3),\n backoffBaseMs: z.number().default(30_000),\n })\n .default({ maxRetries: 3, backoffBaseMs: 30_000 });\n\n// ─── Sessions config schema ──────────────────────────────\n\nexport const sessionsConfigSchema = z\n .object({\n initTimeoutMs: z.number().default(120_000),\n maxDurationMs: z.number().default(3_600_000),\n dir: z.string().default(\"/tmp/neo-sessions\"),\n })\n .default({ initTimeoutMs: 120_000, maxDurationMs: 3_600_000, dir: \"/tmp/neo-sessions\" });\n\n// ─── Journal config schema ───────────────────────────────\n\nexport const journalConfigSchema = z\n .object({\n maxCostJournalSizeBytes: z.number().default(100 * 1024 * 1024), // 100MB\n maxEventJournalSizeBytes: z.number().default(500 * 1024 * 1024), // 500MB\n })\n .default({\n maxCostJournalSizeBytes: 100 * 1024 * 1024,\n maxEventJournalSizeBytes: 500 * 1024 * 1024,\n });\n\n// ─── Supervisor config schema ────────────────────────────\n\nexport const supervisorConfigSchema = z\n .object({\n port: z.number().default(7777),\n secret: z.string().optional(),\n heartbeatTimeoutMs: z.number().default(300_000),\n maxConsecutiveFailures: z.number().default(3),\n maxEventsPerSec: z.number().default(10),\n dailyCapUsd: z.number().default(50),\n /** How often consolidation runs (ms) */\n consolidationIntervalMs: z.number().default(300_000),\n /** How often compaction runs (ms) */\n compactionIntervalMs: z.number().default(3_600_000),\n /** Safety timeout for waitForWork (ms) */\n eventTimeoutMs: z.number().default(300_000),\n instructions: z.string().optional(),\n /** Max consecutive idle loop iterations before supervisor pauses polling */\n idleSkipMax: z.number().default(20),\n /** Max consecutive active-work loop iterations before supervisor yields */\n activeWorkSkipMax: z.number().default(3),\n /** When true, supervisor answers pending decisions autonomously instead of waiting for human input */\n autoDecide: z.boolean().default(false),\n })\n .default({\n port: 7777,\n heartbeatTimeoutMs: 300_000,\n maxConsecutiveFailures: 3,\n maxEventsPerSec: 10,\n dailyCapUsd: 50,\n consolidationIntervalMs: 300_000,\n compactionIntervalMs: 3_600_000,\n eventTimeoutMs: 300_000,\n idleSkipMax: 20,\n activeWorkSkipMax: 3,\n autoDecide: false,\n });\n\n// ─── Global config schema (~/.neo/config.yml) ───────────\n// This is now the single source of truth — repos are registered here.\n\nexport const globalConfigSchema = z.object({\n repos: z.array(repoConfigSchema).default([]),\n\n concurrency: concurrencyConfigSchema,\n\n budget: budgetConfigSchema,\n\n recovery: recoveryConfigSchema,\n\n sessions: sessionsConfigSchema,\n\n journal: journalConfigSchema.optional(),\n\n webhooks: z\n .array(\n z.object({\n url: z.string().url(),\n events: z.array(z.string()).optional(),\n secret: z.string().optional(),\n timeoutMs: z.number().default(5000),\n }),\n )\n .default([]),\n\n supervisor: supervisorConfigSchema,\n\n memory: z\n .object({\n embeddings: z.boolean().default(true),\n })\n .default({ embeddings: true }),\n\n mcpServers: z.record(z.string(), mcpServerConfigSchema).optional(),\n claudeCodePath: z.string().optional(),\n\n idempotency: z\n .object({\n enabled: z.boolean().default(true),\n key: z.enum([\"metadata\", \"prompt\"]).default(\"metadata\"),\n ttlMs: z.number().default(3_600_000),\n })\n .optional(),\n});\n\n// ─── NeoConfig = GlobalConfig (single schema now) ────────\n\nexport const neoConfigSchema = globalConfigSchema;\n\n// ─── Repo override config schema ─────────────────────────\n// Partial subset for repo-level overrides.\n// Only allows: concurrency, budget, recovery, sessions keys.\n\nexport const repoOverrideConfigSchema = z\n .object({\n concurrency: concurrencyConfigSchema.unwrap().partial().optional(),\n budget: budgetConfigSchema.unwrap().partial().optional(),\n recovery: recoveryConfigSchema.unwrap().partial().optional(),\n sessions: sessionsConfigSchema.unwrap().partial().optional(),\n })\n .partial();\n\n// ─── Derived types ───────────────────────────────────────\n\nexport type NeoConfig = z.infer<typeof neoConfigSchema>;\nexport type GlobalConfig = NeoConfig;\nexport type RepoConfig = z.infer<typeof repoConfigSchema>;\nexport type RepoConfigInput = z.input<typeof repoConfigSchema>;\nexport type McpServerConfig = z.infer<typeof mcpServerConfigSchema>;\nexport type RepoOverrideConfig = z.infer<typeof repoOverrideConfigSchema>;\n","import type { NeoConfig } from \"./schema\";\n\n/**\n * Retrieves a nested value from config using dot notation.\n *\n * @param config - The configuration object\n * @param path - Dot-separated path (e.g., \"budget.dailyCapUsd\")\n * @returns The value at the path, or undefined if not found\n *\n * @example\n * getConfigValue(config, \"budget.dailyCapUsd\") // 500\n * getConfigValue(config, \"missing.path\") // undefined\n */\nexport function getConfigValue(config: NeoConfig, path: string): unknown {\n if (path === \"\") {\n return config;\n }\n\n const keys = path.split(\".\");\n let current: unknown = config;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined;\n }\n\n if (typeof current !== \"object\") {\n return undefined;\n }\n\n current = (current as Record<string, unknown>)[key];\n }\n\n return current;\n}\n\n/**\n * Sets a nested value in config using dot notation, returning a new config object.\n * Creates intermediate objects as needed.\n *\n * @param config - The configuration object\n * @param path - Dot-separated path (e.g., \"budget.dailyCapUsd\")\n * @param value - The value to set\n * @returns A new config object with the value set (immutable update)\n *\n * @example\n * setConfigValue(config, \"budget.dailyCapUsd\", 1000)\n * setConfigValue(config, \"new.nested.key\", \"value\")\n */\nexport function setConfigValue(config: NeoConfig, path: string, value: unknown): NeoConfig {\n if (path === \"\") {\n // Empty path means replace entire config\n return value as NeoConfig;\n }\n\n const keys = path.split(\".\");\n return setNestedValue(config, keys, value) as NeoConfig;\n}\n\n/**\n * Recursively builds a new object with the value set at the given key path.\n */\nfunction setNestedValue(obj: unknown, keys: readonly string[], value: unknown): unknown {\n const key = keys[0];\n if (key === undefined) {\n return value;\n }\n\n const rest = keys.slice(1);\n\n // Get current object or create empty object if missing/invalid\n const current: Record<string, unknown> =\n obj !== null && typeof obj === \"object\" ? { ...(obj as Record<string, unknown>) } : {};\n\n if (rest.length === 0) {\n // Last key - set the value\n current[key] = value;\n } else {\n // Intermediate key - recurse\n current[key] = setNestedValue(current[key], rest, value);\n }\n\n return current;\n}\n","import type { NeoConfig, RepoOverrideConfig } from \"./schema\";\nimport {\n budgetConfigSchema,\n concurrencyConfigSchema,\n journalConfigSchema,\n recoveryConfigSchema,\n sessionsConfigSchema,\n} from \"./schema\";\n\n// ─── Default configuration ─────────────────────────────────\n\n/**\n * Default configuration values.\n * Used as base layer when merging configs.\n */\nexport const defaultConfig: NeoConfig = {\n repos: [],\n concurrency: concurrencyConfigSchema.parse(undefined),\n budget: budgetConfigSchema.parse(undefined),\n recovery: recoveryConfigSchema.parse(undefined),\n sessions: sessionsConfigSchema.parse(undefined),\n journal: journalConfigSchema.parse(undefined),\n webhooks: [],\n supervisor: {\n port: 7777,\n heartbeatTimeoutMs: 300_000,\n maxConsecutiveFailures: 3,\n maxEventsPerSec: 10,\n dailyCapUsd: 50,\n consolidationIntervalMs: 300_000,\n compactionIntervalMs: 3_600_000,\n eventTimeoutMs: 300_000,\n idleSkipMax: 20,\n activeWorkSkipMax: 3,\n autoDecide: false,\n },\n memory: { embeddings: true },\n};\n\n// ─── Deep merge utility ────────────────────────────────────\n\n/**\n * Deep merges two objects, with source values taking precedence.\n * Arrays are replaced, not merged.\n */\nfunction deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key of Object.keys(source) as Array<keyof T>) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (sourceValue === undefined) {\n continue;\n }\n\n if (\n sourceValue !== null &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue !== null &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n // Recursively merge nested objects\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>,\n ) as T[keyof T];\n } else {\n // Replace primitive values and arrays\n result[key] = sourceValue as T[keyof T];\n }\n }\n\n return result;\n}\n\n// ─── Deep freeze utility ────────────────────────────────────\n\n/**\n * Recursively freezes an object and all nested objects.\n */\nfunction deepFreeze<T>(obj: T): Readonly<T> {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n\n // Freeze arrays and their elements\n if (Array.isArray(obj)) {\n for (const item of obj) {\n deepFreeze(item);\n }\n return Object.freeze(obj) as Readonly<T>;\n }\n\n // Freeze object properties recursively\n for (const value of Object.values(obj)) {\n deepFreeze(value);\n }\n\n return Object.freeze(obj) as Readonly<T>;\n}\n\n// ─── Config merging ────────────────────────────────────────\n\n/**\n * Merges multiple config layers with precedence: repo > global > defaults.\n *\n * @param defaults - Base configuration defaults\n * @param globalConfig - Global config from ~/.neo/config.yml (optional)\n * @param repoConfig - Repo-level overrides from <repo>/.neo/config.yml (optional)\n * @returns Fully resolved, frozen NeoConfig\n *\n * @example\n * const config = mergeConfigs(defaultConfig, globalConfig, repoOverrides);\n */\nexport function mergeConfigs(\n defaults: NeoConfig,\n globalConfig?: Partial<NeoConfig> | null,\n repoConfig?: RepoOverrideConfig | null,\n): Readonly<NeoConfig> {\n // Start with defaults\n let result = { ...defaults };\n\n // Merge global config (second priority)\n if (globalConfig) {\n result = deepMerge(result, globalConfig);\n }\n\n // Merge repo overrides (highest priority)\n if (repoConfig) {\n result = deepMerge(result, repoConfig as Partial<NeoConfig>);\n }\n\n return deepFreeze(result);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { getConfigValue } from \"./dotNotation\";\nimport { defaultConfig, mergeConfigs } from \"./merge\";\nimport type { NeoConfig, RepoOverrideConfig } from \"./schema\";\nimport { neoConfigSchema, repoOverrideConfigSchema } from \"./schema\";\n\n// ─── ConfigStore ───────────────────────────────────────────\n\n/**\n * Configuration store that loads and merges config files.\n *\n * Config precedence (highest to lowest):\n * 1. Repo config: <repoPath>/.neo/config.yml\n * 2. Global config: ~/.neo/config.yml\n * 3. Default values (hardcoded)\n *\n * @example\n * const store = new ConfigStore('/path/to/repo');\n * await store.load();\n * const dailyCap = store.get<number>('budget.dailyCapUsd');\n */\nexport class ConfigStore {\n private repoPath: string | undefined;\n private config: NeoConfig | null = null;\n\n constructor(repoPath?: string) {\n this.repoPath = repoPath;\n }\n\n // ─── Public API ────────────────────────────────────────\n\n /**\n * Loads and merges config files from all locations.\n * Must be called before get() or getAll().\n */\n async load(): Promise<void> {\n const globalConfig = await this.loadGlobalConfig();\n const repoConfig = await this.loadRepoConfig();\n\n this.config = mergeConfigs(defaultConfig, globalConfig, repoConfig);\n }\n\n /**\n * Gets a config value using dot notation.\n *\n * @param key - Dot-separated path (e.g., \"budget.dailyCapUsd\")\n * @returns The value at the path\n * @throws Error if load() has not been called\n *\n * @example\n * store.get<number>('budget.dailyCapUsd') // 500\n * store.get<string>('sessions.dir') // '/tmp/neo-sessions'\n */\n get<T>(key: string): T {\n if (this.config === null) {\n throw new Error(\"ConfigStore not loaded. Call load() first.\");\n }\n\n return getConfigValue(this.config, key) as T;\n }\n\n /**\n * Returns the full merged configuration.\n *\n * @throws Error if load() has not been called\n */\n getAll(): NeoConfig {\n if (this.config === null) {\n throw new Error(\"ConfigStore not loaded. Call load() first.\");\n }\n\n return this.config;\n }\n\n /**\n * Returns the repository path, if one was provided.\n * Used by ConfigWatcher to determine which files to watch.\n */\n getRepoPath(): string | undefined {\n return this.repoPath;\n }\n\n // ─── Private loaders ───────────────────────────────────\n\n /**\n * Loads global config from ~/.neo/config.yml\n */\n private async loadGlobalConfig(): Promise<NeoConfig | null> {\n const globalPath = join(homedir(), \".neo\", \"config.yml\");\n const raw = await this.loadFile(globalPath);\n\n if (raw === null) {\n return null;\n }\n\n // Validate and parse with defaults\n const parsed = neoConfigSchema.safeParse(raw);\n if (!parsed.success) {\n console.warn(`[neo] Failed to parse config at ${globalPath}:`, parsed.error.message);\n return null;\n }\n\n return parsed.data;\n }\n\n /**\n * Loads repo-level overrides from <repoPath>/.neo/config.yml\n */\n private async loadRepoConfig(): Promise<RepoOverrideConfig | null> {\n if (!this.repoPath) {\n return null;\n }\n\n const repoConfigPath = join(this.repoPath, \".neo\", \"config.yml\");\n const raw = await this.loadFile(repoConfigPath);\n\n if (raw === null) {\n return null;\n }\n\n // Validate repo overrides (partial subset)\n const parsed = repoOverrideConfigSchema.safeParse(raw);\n if (!parsed.success) {\n console.warn(`[neo] Failed to parse config at ${repoConfigPath}:`, parsed.error.message);\n return null;\n }\n\n return parsed.data;\n }\n\n /**\n * Loads and parses a YAML config file.\n *\n * @param filePath - Absolute path to the config file\n * @returns Parsed YAML content or null if file doesn't exist\n */\n private async loadFile(filePath: string): Promise<Record<string, unknown> | null> {\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const parsed = parseYaml(content);\n\n if (parsed === null || typeof parsed !== \"object\") {\n return null;\n }\n\n return parsed as Record<string, unknown>;\n } catch {\n // Parse errors are silently ignored — missing/invalid files return null\n return null;\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { type FSWatcher, watch } from \"chokidar\";\nimport type { ConfigStore } from \"./ConfigStore\";\n\n// ─── ConfigWatcher ─────────────────────────────────────────\n\n/**\n * Watches config files and reloads the store on changes.\n *\n * Emits 'change' event after successful reload.\n * Uses debouncing to handle rapid saves (e.g., editor auto-save).\n *\n * @example\n * const store = new ConfigStore('/path/to/repo');\n * await store.load();\n *\n * const watcher = new ConfigWatcher(store, { debounceMs: 300 });\n * watcher.on('change', () => console.log('Config reloaded'));\n * watcher.start();\n *\n * // Later: stop watching\n * watcher.stop();\n */\nexport class ConfigWatcher extends EventEmitter {\n private readonly store: ConfigStore;\n private readonly debounceMs: number;\n private readonly repoPath: string | undefined;\n private watcher: FSWatcher | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(store: ConfigStore, options?: { debounceMs?: number }) {\n super();\n this.store = store;\n this.debounceMs = options?.debounceMs ?? 500;\n this.repoPath = store.getRepoPath();\n }\n\n /**\n * Starts watching config files for changes.\n * Watches both global (~/.neo/config.yml) and repo config files.\n */\n start(): void {\n if (this.watcher) {\n return; // Already watching\n }\n\n const paths = this.getConfigPaths();\n\n this.watcher = watch(paths, {\n ignoreInitial: true,\n // Don't error if files don't exist — they may be created later\n ignorePermissionErrors: true,\n });\n\n this.watcher.on(\"change\", () => this.handleChange());\n this.watcher.on(\"add\", () => this.handleChange());\n this.watcher.on(\"unlink\", () => this.handleChange());\n }\n\n /**\n * Stops watching config files.\n */\n stop(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n }\n\n // ─── Private ─────────────────────────────────────────────\n\n /**\n * Returns the list of config file paths to watch.\n */\n private getConfigPaths(): string[] {\n const globalPath = join(homedir(), \".neo\", \"config.yml\");\n const paths = [globalPath];\n\n if (this.repoPath) {\n const repoConfigPath = join(this.repoPath, \".neo\", \"config.yml\");\n paths.push(repoConfigPath);\n }\n\n return paths;\n }\n\n /**\n * Handles file change events with debouncing.\n */\n private handleChange(): void {\n // Clear existing timer to debounce rapid changes\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n }\n\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.reloadConfig();\n }, this.debounceMs);\n\n // Unref timer so it doesn't keep the process alive\n if (typeof this.debounceTimer === \"object\" && \"unref\" in this.debounceTimer) {\n this.debounceTimer.unref();\n }\n }\n\n /**\n * Reloads the config and emits 'change' event.\n */\n private async reloadConfig(): Promise<void> {\n try {\n await this.store.load();\n this.emit(\"change\");\n } catch {\n // Silently ignore reload errors — file may be temporarily invalid\n // ConfigStore.load() already handles missing/invalid files gracefully\n }\n }\n}\n","import type { z } from \"zod\";\nimport type { NeoConfig, RepoOverrideConfig } from \"./schema\";\nimport { neoConfigSchema, repoOverrideConfigSchema } from \"./schema\";\n\n// ─── Warning types ──────────────────────────────────────────\n\nexport type ConfigWarningType = \"unknown_key\" | \"deprecated\" | \"type_coerced\";\n\nexport interface ConfigWarning {\n type: ConfigWarningType;\n path: string;\n message: string;\n}\n\nexport interface ParseResult<T> {\n config: T;\n warnings: ConfigWarning[];\n}\n\n// ─── Deprecated keys registry ───────────────────────────────\n// Add deprecated keys here with their replacement (if any)\n\nconst DEPRECATED_KEYS: Record<string, string | null> = {\n // Example: 'sessions.timeout' is deprecated in favor of 'sessions.initTimeoutMs'\n // 'sessions.timeout': 'sessions.initTimeoutMs',\n};\n\n// ─── Known keys map ─────────────────────────────────────────\n// Static map of known keys for each config section.\n// This avoids accessing Zod internals which causes type errors.\n\ntype SchemaKeyMap = Record<string, Set<string> | undefined>;\n\nconst NEO_CONFIG_KEYS: SchemaKeyMap = {\n \"\": new Set([\n \"repos\",\n \"concurrency\",\n \"budget\",\n \"recovery\",\n \"sessions\",\n \"webhooks\",\n \"supervisor\",\n \"memory\",\n \"mcpServers\",\n \"claudeCodePath\",\n \"idempotency\",\n ]),\n concurrency: new Set([\"maxSessions\", \"maxPerRepo\", \"queueMax\"]),\n budget: new Set([\"dailyCapUsd\", \"alertThresholdPct\"]),\n recovery: new Set([\"maxRetries\", \"backoffBaseMs\"]),\n sessions: new Set([\"initTimeoutMs\", \"maxDurationMs\", \"dir\"]),\n supervisor: new Set([\n \"port\",\n \"secret\",\n \"heartbeatTimeoutMs\",\n \"maxConsecutiveFailures\",\n \"maxEventsPerSec\",\n \"dailyCapUsd\",\n \"consolidationIntervalMs\",\n \"compactionIntervalMs\",\n \"eventTimeoutMs\",\n \"instructions\",\n \"idleSkipMax\",\n \"activeWorkSkipMax\",\n \"autoDecide\",\n ]),\n memory: new Set([\"embeddings\"]),\n idempotency: new Set([\"enabled\", \"key\", \"ttlMs\"]),\n};\n\nconst REPO_OVERRIDE_KEYS: SchemaKeyMap = {\n \"\": new Set([\"concurrency\", \"budget\", \"recovery\", \"sessions\"]),\n concurrency: NEO_CONFIG_KEYS.concurrency,\n budget: NEO_CONFIG_KEYS.budget,\n recovery: NEO_CONFIG_KEYS.recovery,\n sessions: NEO_CONFIG_KEYS.sessions,\n};\n\n// ─── Unknown keys detection ─────────────────────────────────\n\n/**\n * Recursively collects warnings for unknown keys in the input.\n */\nfunction collectUnknownKeyWarnings(\n input: unknown,\n keyMap: SchemaKeyMap,\n path: string,\n warnings: ConfigWarning[],\n): void {\n if (input === null || input === undefined || typeof input !== \"object\") {\n return;\n }\n\n if (Array.isArray(input)) {\n return;\n }\n\n const inputObj = input as Record<string, unknown>;\n const knownKeys = keyMap[path] ?? keyMap[\"\"];\n\n if (!knownKeys) {\n return;\n }\n\n for (const key of Object.keys(inputObj)) {\n const fullPath = path ? `${path}.${key}` : key;\n\n if (!knownKeys.has(key)) {\n warnings.push({\n type: \"unknown_key\",\n path: fullPath,\n message: `Unknown configuration key '${fullPath}'`,\n });\n } else {\n // Recurse into nested objects that have known key mappings\n const nestedKeys = keyMap[fullPath] ?? keyMap[key];\n if (nestedKeys && inputObj[key] && typeof inputObj[key] === \"object\") {\n collectUnknownKeyWarnings(inputObj[key], keyMap, fullPath, warnings);\n }\n }\n }\n}\n\n// ─── Deprecated keys detection ──────────────────────────────\n\n/**\n * Checks for deprecated keys in the input.\n */\nfunction collectDeprecatedWarnings(input: unknown, path: string, warnings: ConfigWarning[]): void {\n if (input === null || input === undefined || typeof input !== \"object\") {\n return;\n }\n\n if (Array.isArray(input)) {\n return;\n }\n\n const inputObj = input as Record<string, unknown>;\n\n for (const key of Object.keys(inputObj)) {\n const fullPath = path ? `${path}.${key}` : key;\n\n if (fullPath in DEPRECATED_KEYS) {\n const replacement = DEPRECATED_KEYS[fullPath];\n const message = replacement\n ? `Configuration key '${fullPath}' is deprecated, use '${replacement}' instead`\n : `Configuration key '${fullPath}' is deprecated and will be removed`;\n warnings.push({\n type: \"deprecated\",\n path: fullPath,\n message,\n });\n }\n\n // Recurse into nested objects\n if (inputObj[key] && typeof inputObj[key] === \"object\") {\n collectDeprecatedWarnings(inputObj[key], fullPath, warnings);\n }\n }\n}\n\n// ─── Type coercion detection ────────────────────────────────\n\n/**\n * Detects type coercions by comparing input types with parsed output.\n */\nfunction collectTypeCoercionWarnings(\n input: unknown,\n parsed: unknown,\n path: string,\n warnings: ConfigWarning[],\n): void {\n if (input === undefined || input === null) {\n return;\n }\n\n // Primitive type coercion detection\n const inputType = typeof input;\n const parsedType = typeof parsed;\n\n // Detect string-to-number coercion (e.g., \"5\" -> 5)\n if (inputType === \"string\" && parsedType === \"number\" && !Number.isNaN(Number(input))) {\n warnings.push({\n type: \"type_coerced\",\n path,\n message: `Value at '${path}' was coerced from string \"${input}\" to number ${parsed}`,\n });\n return;\n }\n\n // Detect string-to-boolean coercion (e.g., \"true\" -> true)\n if (inputType === \"string\" && parsedType === \"boolean\") {\n warnings.push({\n type: \"type_coerced\",\n path,\n message: `Value at '${path}' was coerced from string \"${input}\" to boolean ${parsed}`,\n });\n return;\n }\n\n // Recurse into objects\n if (\n inputType === \"object\" &&\n parsedType === \"object\" &&\n !Array.isArray(input) &&\n !Array.isArray(parsed)\n ) {\n const inputObj = input as Record<string, unknown>;\n const parsedObj = parsed as Record<string, unknown>;\n\n for (const key of Object.keys(inputObj)) {\n const fullPath = path ? `${path}.${key}` : key;\n collectTypeCoercionWarnings(inputObj[key], parsedObj[key], fullPath, warnings);\n }\n }\n\n // Recurse into arrays\n if (Array.isArray(input) && Array.isArray(parsed)) {\n for (let i = 0; i < input.length; i++) {\n collectTypeCoercionWarnings(input[i], parsed[i], `${path}[${i}]`, warnings);\n }\n }\n}\n\n// ─── Public API ─────────────────────────────────────────────\n\n/**\n * Parses NeoConfig with warnings for unknown keys, deprecated options, and type coercions.\n *\n * @param input - Raw parsed YAML/JSON input\n * @returns ParseResult with config and warnings\n * @throws Error if parsing fails (validation errors are still fatal)\n */\nexport function parseConfigWithWarnings(input: unknown): ParseResult<NeoConfig> {\n const warnings: ConfigWarning[] = [];\n\n // Collect warnings before parsing\n collectUnknownKeyWarnings(input, NEO_CONFIG_KEYS, \"\", warnings);\n collectDeprecatedWarnings(input, \"\", warnings);\n\n // Parse with Zod - this will throw on validation errors\n const result = neoConfigSchema.safeParse(input);\n if (!result.success) {\n throw new Error(formatZodErrors(result.error.issues));\n }\n\n // Collect type coercion warnings after parsing\n collectTypeCoercionWarnings(input, result.data, \"\", warnings);\n\n return {\n config: result.data,\n warnings,\n };\n}\n\n/**\n * Parses RepoOverrideConfig with warnings.\n *\n * @param input - Raw parsed YAML/JSON input\n * @returns ParseResult with config and warnings\n * @throws Error if parsing fails\n */\nexport function parseRepoConfigWithWarnings(input: unknown): ParseResult<RepoOverrideConfig> {\n const warnings: ConfigWarning[] = [];\n\n // Collect warnings before parsing\n collectUnknownKeyWarnings(input, REPO_OVERRIDE_KEYS, \"\", warnings);\n collectDeprecatedWarnings(input, \"\", warnings);\n\n // Parse with Zod\n const result = repoOverrideConfigSchema.safeParse(input);\n if (!result.success) {\n throw new Error(formatZodErrors(result.error.issues));\n }\n\n // Collect type coercion warnings after parsing\n collectTypeCoercionWarnings(input, result.data, \"\", warnings);\n\n return {\n config: result.data,\n warnings,\n };\n}\n\n// ─── Helper ─────────────────────────────────────────────────\n\nfunction formatZodErrors(issues: z.ZodIssue[]): string {\n return issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \");\n}\n","import { createReadStream } from \"node:fs\";\nimport { appendFile, stat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport { fileForDate, toDateKey } from \"@/shared/date\";\nimport { ensureDir } from \"@/shared/fs\";\nimport type { CostEntry } from \"@/types\";\n\n/**\n * Error thrown when a journal file exceeds the maximum allowed size.\n */\nexport class JournalFileSizeError extends Error {\n constructor(\n public readonly filePath: string,\n public readonly fileSizeBytes: number,\n public readonly maxSizeBytes: number,\n ) {\n super(\n `Journal file exceeds maximum size: ${filePath} (${(fileSizeBytes / 1024 / 1024).toFixed(2)}MB > ${(maxSizeBytes / 1024 / 1024).toFixed(2)}MB)`,\n );\n this.name = \"JournalFileSizeError\";\n }\n}\n\n/**\n * Append-only JSONL journal for cost tracking.\n * Monthly file rotation: cost-YYYY-MM.jsonl\n */\nexport class CostJournal {\n private readonly dir: string;\n private readonly dirCache = new Set<string>();\n private dayCache: { key: string; total: number } | null = null;\n private readonly maxFileSizeBytes: number;\n\n constructor(options: { dir: string; maxFileSizeBytes?: number }) {\n this.dir = options.dir;\n this.maxFileSizeBytes = options.maxFileSizeBytes ?? 100 * 1024 * 1024; // 100MB default\n }\n\n async append(entry: CostEntry): Promise<void> {\n await ensureDir(this.dir, this.dirCache);\n const file = fileForDate(new Date(entry.timestamp), \"cost\", this.dir);\n await appendFile(file, `${JSON.stringify(entry)}\\n`, \"utf-8\");\n // Invalidate cache — the day total may have changed\n this.dayCache = null;\n }\n\n async getDayTotal(date?: Date): Promise<number> {\n const d = date ?? new Date();\n const dayKey = toDateKey(d);\n\n if (this.dayCache?.key === dayKey) {\n return this.dayCache.total;\n }\n\n const file = fileForDate(d, \"cost\", this.dir);\n let total = 0;\n\n try {\n // Validate file size before reading\n const stats = await stat(file);\n if (stats.size > this.maxFileSizeBytes) {\n throw new JournalFileSizeError(file, stats.size, this.maxFileSizeBytes);\n }\n\n const stream = createReadStream(file, { encoding: \"utf-8\" });\n const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });\n\n for await (const line of rl) {\n if (!line.trim()) continue;\n const entry = JSON.parse(line) as CostEntry;\n if (toDateKey(new Date(entry.timestamp)) === dayKey) {\n total += entry.costUsd;\n }\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n // File doesn't exist yet — total is 0\n }\n\n this.dayCache = { key: dayKey, total };\n return total;\n }\n}\n","import path from \"node:path\";\n\n/**\n * Converts a Date to a YYYY-MM-DD string in UTC.\n *\n * Uses UTC to ensure consistent date keys regardless of local timezone.\n * This is critical for cost tracking and event journaling where entries\n * must be grouped by calendar day consistently across all environments.\n *\n * @param date - The date to convert.\n * @returns A string in YYYY-MM-DD format (e.g., \"2026-03-14\").\n *\n * @example\n * ```ts\n * import { toDateKey } from \"@/shared/date\";\n *\n * toDateKey(new Date(\"2026-03-14T10:00:00Z\")); // => \"2026-03-14\"\n * toDateKey(new Date(\"2026-03-14T23:59:59Z\")); // => \"2026-03-14\"\n * ```\n */\nexport function toDateKey(date: Date): string {\n return date.toISOString().slice(0, 10);\n}\n\n/**\n * Generates a dated file path with monthly rotation.\n *\n * Creates paths in the format: `{dir}/{prefix}-YYYY-MM.jsonl`\n * Uses UTC year/month to ensure consistent file paths across timezones.\n *\n * @param date - The date used to determine the year and month for the file name.\n * @param prefix - The prefix for the file name (e.g., \"cost\", \"events\").\n * @param dir - The directory where the file will be located.\n * @returns The full file path (e.g., \"/data/cost-2026-03.jsonl\").\n *\n * @example\n * ```ts\n * import { fileForDate } from \"@/shared/date\";\n *\n * fileForDate(new Date(\"2026-03-14T10:00:00Z\"), \"cost\", \"/data\");\n * // => \"/data/cost-2026-03.jsonl\"\n *\n * fileForDate(new Date(\"2026-12-31T23:59:59Z\"), \"events\", \"/logs\");\n * // => \"/logs/events-2026-12.jsonl\"\n * ```\n */\nexport function fileForDate(date: Date, prefix: string, dir: string): string {\n const yyyy = date.getUTCFullYear();\n const mm = String(date.getUTCMonth() + 1).padStart(2, \"0\");\n return path.join(dir, `${prefix}-${yyyy}-${mm}.jsonl`);\n}\n","import { mkdir } from \"node:fs/promises\";\n\n/**\n * Ensures a directory exists, creating it recursively if necessary.\n *\n * Uses an optional cache to avoid redundant filesystem calls when the same\n * directory is ensured multiple times. This is useful in hot paths where\n * directory existence is checked frequently.\n *\n * @param dirPath - The absolute or relative path to the directory to ensure.\n * @param cache - Optional Set to track directories that have already been created.\n * When provided, subsequent calls with the same path skip the mkdir call.\n * @returns A promise that resolves when the directory exists.\n *\n * @example\n * ```ts\n * import { ensureDir } from \"@/shared/fs\";\n *\n * // Basic usage - creates directory if it doesn't exist\n * await ensureDir(\"/tmp/my-app/logs\");\n *\n * // With caching - second call skips filesystem\n * const cache = new Set<string>();\n * await ensureDir(\"/tmp/my-app/logs\", cache); // calls mkdir\n * await ensureDir(\"/tmp/my-app/logs\", cache); // returns immediately\n * ```\n */\nexport async function ensureDir(dirPath: string, cache?: Set<string>): Promise<void> {\n if (cache?.has(dirPath)) {\n return;\n }\n\n await mkdir(dirPath, { recursive: true });\n\n cache?.add(dirPath);\n}\n","import { EventEmitter } from \"node:events\";\nimport type { NeoEvent } from \"@/types\";\n\n/**\n * Safe EventEmitter wrapper (ADR-022).\n *\n * - Catches listener errors to prevent cascading crashes\n * - Emits on both the specific event type and the wildcard \"*\" channel\n * - Swallows errors from the error handler itself to guarantee stability\n */\nexport class NeoEventEmitter {\n private readonly emitter = new EventEmitter();\n\n emit(event: NeoEvent): void {\n this.safeEmit(event.type, event);\n this.safeEmit(\"*\", event);\n }\n\n on(eventType: string, listener: (event: NeoEvent) => void): this {\n this.emitter.on(eventType, listener);\n return this;\n }\n\n off(eventType: string, listener: (event: NeoEvent) => void): this {\n this.emitter.off(eventType, listener);\n return this;\n }\n\n once(eventType: string, listener: (event: NeoEvent) => void): this {\n this.emitter.once(eventType, listener);\n return this;\n }\n\n removeAllListeners(eventType?: string): this {\n this.emitter.removeAllListeners(eventType);\n return this;\n }\n\n private safeEmit(eventType: string, event: NeoEvent): void {\n try {\n this.emitter.emit(eventType, event);\n } catch (error) {\n if (eventType !== \"error\") {\n try {\n this.emitter.emit(\"error\", error);\n } catch (nestedErr) {\n // Swallow — prevent crash even if error handler throws\n // This is a last-resort safety net to prevent infinite error loops\n console.error(\n \"[emitter] Error handler threw:\",\n nestedErr instanceof Error ? nestedErr.message : String(nestedErr),\n );\n }\n }\n }\n }\n}\n","import { appendFile, stat } from \"node:fs/promises\";\nimport { fileForDate } from \"@/shared/date\";\nimport { ensureDir } from \"@/shared/fs\";\nimport type { NeoEvent } from \"@/types\";\n\n/**\n * Error thrown when a journal file exceeds the maximum allowed size.\n * Re-exported from cost/journal for consistency.\n */\nexport class JournalFileSizeError extends Error {\n constructor(\n public readonly filePath: string,\n public readonly fileSizeBytes: number,\n public readonly maxSizeBytes: number,\n ) {\n super(\n `Journal file exceeds maximum size: ${filePath} (${(fileSizeBytes / 1024 / 1024).toFixed(2)}MB > ${(maxSizeBytes / 1024 / 1024).toFixed(2)}MB)`,\n );\n this.name = \"JournalFileSizeError\";\n }\n}\n\n/**\n * Append-only JSONL journal for events.\n * Monthly file rotation: events-YYYY-MM.jsonl\n * Write-only for v0.1 — read API comes in v0.2.\n */\nexport class EventJournal {\n private readonly dir: string;\n private readonly dirCache = new Set<string>();\n private readonly maxFileSizeBytes: number;\n\n constructor(options: { dir: string; maxFileSizeBytes?: number }) {\n this.dir = options.dir;\n this.maxFileSizeBytes = options.maxFileSizeBytes ?? 500 * 1024 * 1024; // 500MB default\n }\n\n async append(event: NeoEvent): Promise<void> {\n await ensureDir(this.dir, this.dirCache);\n const file = fileForDate(new Date(event.timestamp), \"events\", this.dir);\n\n // Validate file size before appending to prevent unbounded growth\n try {\n const stats = await stat(file);\n if (stats.size > this.maxFileSizeBytes) {\n throw new JournalFileSizeError(file, stats.size, this.maxFileSizeBytes);\n }\n } catch (error) {\n // File doesn't exist yet — safe to append\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n\n await appendFile(file, `${JSON.stringify(event)}\\n`, \"utf-8\");\n }\n}\n","import { createHmac, randomUUID } from \"node:crypto\";\nimport type { NeoConfig } from \"@/config\";\nimport type { NeoEvent } from \"@/types\";\n\ntype WebhookConfig = NeoConfig[\"webhooks\"][number];\n\ninterface WebhookPayload {\n id: string;\n version: 1;\n event: string;\n payload: Record<string, unknown>;\n source: \"neo\";\n deliveredAt: string;\n}\n\n/** Event types that get retry on failure (terminal events the supervisor must see). */\nconst RETRY_EVENT_TYPES = new Set([\"session:complete\", \"session:fail\", \"budget:alert\"]);\n\nconst RETRY_MAX_ATTEMPTS = 3;\nconst RETRY_BASE_DELAY_MS = 500;\n\n/**\n * Webhook dispatcher for NeoEvents.\n *\n * - Matches events against per-webhook filters (exact or wildcard like \"session:*\")\n * - Excludes gate:waiting events (contain non-serializable callbacks)\n * - Signs payloads with HMAC-SHA256 when a secret is configured\n * - Terminal events (session:complete, session:fail, budget:alert) are retried\n * with exponential backoff on failure\n * - Non-terminal events remain fire-and-forget\n */\nexport class WebhookDispatcher {\n private readonly webhooks: WebhookConfig[];\n private readonly pending: Set<Promise<void>> = new Set();\n\n constructor(webhooks: WebhookConfig[]) {\n this.webhooks = webhooks;\n }\n\n dispatch(event: NeoEvent): void {\n // gate:waiting contains non-serializable callbacks (approve/reject)\n if (event.type === \"gate:waiting\") return;\n\n for (const webhook of this.webhooks) {\n if (!matchesFilter(event.type, webhook.events)) continue;\n\n const payload: WebhookPayload = {\n id: randomUUID(),\n version: 1,\n event: event.type,\n payload: toSerializable(event),\n source: \"neo\",\n deliveredAt: new Date().toISOString(),\n };\n\n const body = JSON.stringify(payload);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (webhook.secret) {\n headers[\"X-Neo-Signature\"] = sign(body, webhook.secret);\n }\n\n if (RETRY_EVENT_TYPES.has(event.type)) {\n // Terminal events: retry with exponential backoff, track for flush\n const p = sendWithRetry(webhook.url, headers, body, webhook.timeoutMs)\n .catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Log terminal webhook delivery failures\n console.debug(\n `[neo] Webhook delivery failed for ${event.type} to ${webhook.url}:`,\n err,\n );\n })\n .finally(() => this.pending.delete(p));\n this.pending.add(p);\n } else {\n // Non-terminal: fire-and-forget\n fetch(webhook.url, {\n method: \"POST\",\n headers,\n body,\n signal: AbortSignal.timeout(webhook.timeoutMs),\n }).catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Log non-terminal webhook delivery failures\n console.debug(`[neo] Webhook delivery failed for ${event.type} to ${webhook.url}:`, err);\n });\n }\n }\n }\n\n /** Wait for all pending terminal webhook deliveries to complete. */\n async flush(): Promise<void> {\n if (this.pending.size === 0) return;\n await Promise.allSettled([...this.pending]);\n }\n}\n\n/**\n * Send a webhook POST with exponential backoff retry.\n * Retries up to RETRY_MAX_ATTEMPTS times with delays of 500ms, 1s, 2s.\n */\nasync function sendWithRetry(\n url: string,\n headers: Record<string, string>,\n body: string,\n timeoutMs: number,\n): Promise<void> {\n for (let attempt = 1; attempt <= RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body,\n signal: AbortSignal.timeout(timeoutMs),\n });\n if (res.ok) return;\n // Non-2xx: treat as failure, retry\n } catch (err) {\n // Network error or timeout: retry\n console.debug(\n `[webhook] Network error on attempt ${attempt}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n if (attempt < RETRY_MAX_ATTEMPTS) {\n const delay = RETRY_BASE_DELAY_MS * 2 ** (attempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n}\n\n/**\n * Check if an event type matches a filter list.\n * Supports exact matches and wildcard prefixes (e.g. \"session:*\").\n * No filter (undefined) means all events match.\n */\nexport function matchesFilter(eventType: string, filters?: string[]): boolean {\n if (!filters || filters.length === 0) return true;\n return filters.some((f) => {\n if (f.endsWith(\":*\")) return eventType.startsWith(f.slice(0, -1));\n return f === eventType;\n });\n}\n\nfunction sign(body: string, secret: string): string {\n return createHmac(\"sha256\", secret).update(body).digest(\"hex\");\n}\n\nfunction toSerializable(event: NeoEvent): Record<string, unknown> {\n const obj: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(event)) {\n if (typeof value !== \"function\") {\n obj[key] = value;\n }\n }\n return obj;\n}\n","import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rm } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT = 60_000;\n\n/**\n * Validates that a git ref name (branch, tag, remote) is safe to use.\n * Prevents command injection by allowing only alphanumeric chars, dashes, slashes, underscores, plus, and dot.\n * Rejects '..' to prevent directory traversal attacks.\n * Rejects git option-like strings starting with '-' to prevent option injection.\n *\n * @throws Error if the ref name is invalid\n */\nexport function validateGitRef(refName: string, paramName: string): void {\n if (!refName || typeof refName !== \"string\") {\n throw new Error(`${paramName} must be a non-empty string`);\n }\n\n // Reject directory traversal\n if (refName.includes(\"..\")) {\n throw new Error(`${paramName} contains invalid pattern '..' (directory traversal)`);\n }\n\n // Reject git option injection (anything starting with -)\n if (refName.startsWith(\"-\")) {\n throw new Error(`${paramName} cannot start with '-' (option injection)`);\n }\n\n // Allow only safe characters: alphanumeric, dash, underscore, slash, plus, dot\n // This supports semver tags like v1.2.3+build.123\n const validRefPattern = /^[a-zA-Z0-9/_+.-]+$/;\n if (!validRefPattern.test(refName)) {\n throw new Error(\n `${paramName} contains invalid characters. Only alphanumeric, dash, underscore, slash, plus, and dot are allowed. Got: ${refName}`,\n );\n }\n}\n\nexport interface SessionCloneInfo {\n path: string;\n branch: string;\n repoPath: string;\n}\n\n/**\n * Create an isolated git clone for an agent session.\n * Uses `git clone --local` to hardlink objects (fast, no network).\n * Then checks out the target branch (existing or new).\n */\nexport async function createSessionClone(options: {\n repoPath: string;\n branch: string;\n baseBranch: string;\n sessionDir: string;\n}): Promise<SessionCloneInfo> {\n // SECURITY: Validate all git ref parameters BEFORE any git operations\n // This prevents command injection via branch names like '--upload-pack=payload'\n validateGitRef(options.branch, \"branch\");\n validateGitRef(options.baseBranch, \"baseBranch\");\n\n const repoPath = resolve(options.repoPath);\n const sessionDir = resolve(options.sessionDir);\n\n await mkdir(dirname(sessionDir), { recursive: true });\n\n // Resolve the real upstream remote URL so the clone is completely\n // independent from the user's local repo. This prevents any git\n // operations in the clone from leaking into the user's working tree.\n const remoteUrl = await execFileAsync(\"git\", [\"config\", \"--get\", \"remote.origin.url\"], {\n cwd: repoPath,\n timeout: GIT_TIMEOUT,\n })\n .then(({ stdout }) => stdout.trim())\n .catch((err) => {\n // No remote configured — will fall back to local clone\n console.debug(\n `[neo] No remote.origin.url for ${repoPath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return \"\";\n });\n\n // Clone from the real remote (GitHub) instead of the local path.\n // This ensures zero coupling: no hardlinks, no local-path origin,\n // no alternates. Falls back to local clone if no remote is configured.\n const cloneSource = remoteUrl || repoPath;\n await execFileAsync(\"git\", [\"clone\", \"--branch\", options.baseBranch, cloneSource, sessionDir], {\n timeout: GIT_TIMEOUT,\n });\n\n // If branch === baseBranch, we're already on it after clone — nothing to do\n if (options.branch !== options.baseBranch) {\n // Check if the target branch already exists on the remote (e.g. fixer on existing PR)\n const branchExists = await execFileAsync(\n \"git\",\n [\"ls-remote\", \"--heads\", \"origin\", options.branch],\n { cwd: sessionDir, timeout: GIT_TIMEOUT },\n )\n .then(({ stdout }) => stdout.trim().length > 0)\n .catch((err) => {\n // Branch doesn't exist remotely or network error — will create new branch\n console.debug(\n `[neo] ls-remote failed for branch ${options.branch}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return false;\n });\n\n if (branchExists) {\n // Fetch and checkout the existing branch\n await execFileAsync(\"git\", [\"fetch\", \"origin\", options.branch], {\n cwd: sessionDir,\n timeout: GIT_TIMEOUT,\n });\n await execFileAsync(\"git\", [\"checkout\", \"-b\", options.branch, `origin/${options.branch}`], {\n cwd: sessionDir,\n timeout: GIT_TIMEOUT,\n });\n } else {\n // Create a new branch from baseBranch\n await execFileAsync(\"git\", [\"checkout\", \"-b\", options.branch], {\n cwd: sessionDir,\n timeout: GIT_TIMEOUT,\n });\n }\n }\n\n return { path: sessionDir, branch: options.branch, repoPath };\n}\n\n/**\n * Remove a session clone directory.\n * Idempotent — does not throw if the directory is already gone.\n */\nexport async function removeSessionClone(sessionPath: string): Promise<void> {\n const absPath = resolve(sessionPath);\n\n if (!existsSync(absPath)) {\n return;\n }\n\n await rm(absPath, { recursive: true, force: true });\n}\n\n/**\n * List all session clones under a base directory.\n */\nexport async function listSessionClones(sessionsBaseDir: string): Promise<SessionCloneInfo[]> {\n const absBase = resolve(sessionsBaseDir);\n\n if (!existsSync(absBase)) {\n return [];\n }\n\n const entries = await readdir(absBase, { withFileTypes: true });\n const clones: SessionCloneInfo[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const clonePath = resolve(absBase, entry.name);\n\n try {\n const { stdout: branchOut } = await execFileAsync(\n \"git\",\n [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"],\n {\n cwd: clonePath,\n timeout: GIT_TIMEOUT,\n },\n );\n let repoPath = clonePath;\n try {\n const { stdout: originUrl } = await execFileAsync(\n \"git\",\n [\"config\", \"--get\", \"remote.origin.url\"],\n { cwd: clonePath, timeout: GIT_TIMEOUT },\n );\n const url = originUrl.trim();\n if (url) repoPath = resolve(clonePath, url);\n } catch (err) {\n // No origin or not a clone — keep clonePath as fallback\n console.debug(\n `[neo] Failed to get origin URL for ${clonePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n clones.push({\n path: clonePath,\n branch: branchOut.trim(),\n repoPath,\n });\n } catch (err) {\n // Not a git repo — skip\n console.debug(\n `[neo] Skipping ${clonePath}, not a valid git repo: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n return clones;\n}\n","import { execFile } from \"node:child_process\";\nimport { resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport type { RepoConfig } from \"@/config\";\nimport { validateGitRef } from \"@/isolation/clone\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT = 60_000;\n\n/**\n * Run a git command with execFile (no shell — prevents injection).\n */\nasync function git(repoPath: string, args: string[]): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", args, {\n cwd: resolve(repoPath),\n timeout: GIT_TIMEOUT,\n });\n return stdout.trim();\n}\n\nexport async function createBranch(\n repoPath: string,\n branch: string,\n baseBranch: string,\n): Promise<void> {\n // SECURITY: Validate all git ref parameters to prevent command injection\n validateGitRef(branch, \"branch\");\n validateGitRef(baseBranch, \"baseBranch\");\n\n await git(repoPath, [\"branch\", branch, baseBranch]);\n}\n\nexport async function pushBranch(repoPath: string, branch: string, remote: string): Promise<void> {\n // SECURITY: Validate all git ref parameters to prevent command injection\n validateGitRef(branch, \"branch\");\n validateGitRef(remote, \"remote\");\n\n await git(repoPath, [\"push\", remote, branch]);\n}\n\nexport async function fetchRemote(repoPath: string, remote: string): Promise<void> {\n // SECURITY: Validate all git ref parameters to prevent command injection\n validateGitRef(remote, \"remote\");\n\n await git(repoPath, [\"fetch\", remote]);\n}\n\nexport async function deleteBranch(repoPath: string, branch: string): Promise<void> {\n // SECURITY: Validate all git ref parameters to prevent command injection\n validateGitRef(branch, \"branch\");\n\n await git(repoPath, [\"branch\", \"-D\", branch]);\n}\n\nexport async function getCurrentBranch(repoPath: string): Promise<string> {\n return git(repoPath, [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n}\n\n/**\n * Resolve the branch name for a run.\n * If an explicit branch is provided, use it as-is.\n * Otherwise, generate a deterministic name from the repo's branchPrefix and runId.\n */\nexport function getBranchName(config: RepoConfig, runId: string, branch?: string): string {\n if (branch) return branch;\n const prefix = config.branchPrefix ?? \"feat\";\n const sanitized = runId.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n return `${prefix}/run-${sanitized}`;\n}\n\n/**\n * Check if a session clone has uncommitted changes (staged or unstaged).\n */\nexport async function hasUncommittedChanges(sessionPath: string): Promise<boolean> {\n const status = await git(sessionPath, [\"status\", \"--porcelain\"]);\n return status.length > 0;\n}\n\n/**\n * Auto-commit all changes in a session clone. Used as a safety net after agent\n * sessions to prevent losing work when the clone is cleaned up.\n */\nexport async function autoCommitChanges(sessionPath: string, runId: string): Promise<boolean> {\n const hasChanges = await hasUncommittedChanges(sessionPath);\n if (!hasChanges) return false;\n\n await git(sessionPath, [\"add\", \"-A\"]);\n await git(sessionPath, [\n \"commit\",\n \"-m\",\n `chore: auto-commit uncommitted changes from run ${runId}`,\n ]);\n\n return true;\n}\n\n/**\n * Push a branch from a session clone to a remote. Silently succeeds if\n * the branch has no new commits to push.\n */\nexport async function pushSessionBranch(\n sessionPath: string,\n branch: string,\n remote: string,\n): Promise<void> {\n // SECURITY: Validate all git ref parameters to prevent command injection\n validateGitRef(branch, \"branch\");\n validateGitRef(remote, \"remote\");\n\n await git(sessionPath, [\"push\", \"-u\", remote, branch]);\n}\n","import { resolve } from \"node:path\";\nimport type { ResolvedAgent } from \"@/types\";\n\n/**\n * SDK-compatible sandbox configuration.\n * Controls which tools an agent can use and which paths it can access.\n */\nexport interface SandboxConfig {\n /** Tools the agent is allowed to use */\n allowedTools: string[];\n /** Directories the agent can read from */\n readablePaths: string[];\n /** Directories the agent can write to (empty for readonly agents) */\n writablePaths: string[];\n /** Whether the agent has write access */\n writable: boolean;\n}\n\n/** Tools that modify the filesystem */\nconst WRITE_TOOLS = new Set([\"Write\", \"Edit\", \"NotebookEdit\"]);\n\n/**\n * Build an SDK-compatible sandbox configuration for an agent.\n *\n * - Writable agents: all their tools are allowed, write paths include the session clone\n * - Readonly agents: write tools are filtered out, no writable paths\n */\nexport function buildSandboxConfig(agent: ResolvedAgent, sessionPath?: string): SandboxConfig {\n const isWritable = agent.sandbox === \"writable\";\n const absSession = sessionPath ? resolve(sessionPath) : undefined;\n\n const allowedTools = isWritable\n ? agent.definition.tools\n : agent.definition.tools.filter((t) => !WRITE_TOOLS.has(t));\n\n const readablePaths = absSession ? [absSession] : [];\n const writablePaths = isWritable && absSession ? [absSession] : [];\n\n return {\n allowedTools,\n readablePaths,\n writablePaths,\n writable: isWritable,\n };\n}\n","import { appendFile, mkdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Middleware } from \"@/types\";\n\nconst DEFAULT_FLUSH_INTERVAL_MS = 500;\nconst DEFAULT_FLUSH_SIZE = 20;\n\n/**\n * Audit log middleware.\n *\n * Buffers JSONL entries in memory and flushes to disk either when\n * the buffer reaches `flushSize` entries or every `flushIntervalMs`.\n * File per session. Uses `{ decision: \"async\" }` so it never blocks the chain.\n *\n * Call `flush()` to force-write remaining entries (e.g. on shutdown).\n * Call `cleanup()` to stop the internal timer (e.g. on shutdown or before GC).\n */\nexport interface AuditLogMiddleware extends Middleware {\n flush: () => Promise<void>;\n cleanup: () => void;\n}\n\nexport function auditLog(options: {\n dir: string;\n includeInput?: boolean;\n includeOutput?: boolean;\n flushIntervalMs?: number;\n flushSize?: number;\n}): AuditLogMiddleware {\n const {\n dir,\n includeInput = true,\n includeOutput = false,\n flushIntervalMs = DEFAULT_FLUSH_INTERVAL_MS,\n flushSize = DEFAULT_FLUSH_SIZE,\n } = options;\n\n let dirCreated = false;\n // sessionId → buffered lines\n const buffers = new Map<string, string[]>();\n let flushTimer: ReturnType<typeof setInterval> | undefined;\n\n async function ensureDir(): Promise<void> {\n if (!dirCreated) {\n await mkdir(dir, { recursive: true });\n dirCreated = true;\n }\n }\n\n async function flushAll(): Promise<void> {\n if (buffers.size === 0) return;\n await ensureDir();\n\n const writes: Promise<void>[] = [];\n for (const [sessionId, lines] of buffers) {\n const filePath = path.join(dir, `${sessionId}.jsonl`);\n writes.push(appendFile(filePath, lines.join(\"\"), \"utf-8\"));\n }\n buffers.clear();\n await Promise.all(writes);\n }\n\n async function flushSession(sessionId: string): Promise<void> {\n const lines = buffers.get(sessionId);\n if (!lines || lines.length === 0) return;\n await ensureDir();\n\n const filePath = path.join(dir, `${sessionId}.jsonl`);\n await appendFile(filePath, lines.join(\"\"), \"utf-8\");\n buffers.delete(sessionId);\n }\n\n function stopTimer(): void {\n if (flushTimer !== undefined) {\n clearInterval(flushTimer);\n flushTimer = undefined;\n }\n }\n\n return {\n name: \"audit-log\",\n on: \"PostToolUse\",\n async flush() {\n stopTimer();\n await flushAll();\n },\n cleanup() {\n stopTimer();\n },\n async handler(event, context) {\n const entry: Record<string, unknown> = {\n timestamp: new Date().toISOString(),\n sessionId: event.sessionId,\n agent: context.agent,\n toolName: event.toolName,\n };\n\n if (includeInput && event.input !== undefined) {\n entry.input = event.input;\n }\n\n if (includeOutput && event.output !== undefined) {\n entry.output = event.output;\n }\n\n const sessionId = event.sessionId;\n let lines = buffers.get(sessionId);\n if (!lines) {\n lines = [];\n buffers.set(sessionId, lines);\n }\n lines.push(`${JSON.stringify(entry)}\\n`);\n\n // Flush when buffer is full\n if (lines.length >= flushSize) {\n await flushSession(sessionId);\n }\n\n // Start periodic flush timer if not already running\n if (flushTimer === undefined && flushIntervalMs > 0) {\n flushTimer = setInterval(() => {\n void flushAll();\n }, flushIntervalMs);\n // Unref so it doesn't keep the process alive\n if (typeof flushTimer === \"object\" && \"unref\" in flushTimer) {\n flushTimer.unref();\n }\n }\n\n return { decision: \"async\", asyncTimeout: 5_000 };\n },\n };\n}\n","import type { Middleware } from \"@/types\";\n\n/**\n * Budget guard middleware.\n *\n * Checks daily cost against budget cap on every tool call.\n * If over budget, blocks with reason \"Daily budget exceeded\".\n * Uses the middleware context's `get(\"costToday\")` and `get(\"budgetCapUsd\")`.\n */\nexport function budgetGuard(): Middleware {\n return {\n name: \"budget-guard\",\n on: \"PreToolUse\",\n async handler(_event, context) {\n const costToday = context.get(\"costToday\");\n const budgetCapUsd = context.get(\"budgetCapUsd\");\n\n if (costToday !== undefined && budgetCapUsd !== undefined && costToday >= budgetCapUsd) {\n return {\n decision: \"block\",\n reason: \"Daily budget exceeded\",\n };\n }\n\n return { decision: \"pass\" };\n },\n };\n}\n","import type {\n HookCallback,\n HookCallbackMatcher,\n HookInput,\n HookJSONOutput,\n HookEvent as SDKHookEvent,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport type {\n HookEvent,\n Middleware,\n MiddlewareContext,\n MiddlewareEvent,\n MiddlewareResult,\n} from \"@/types\";\n\nexport interface MiddlewareChain {\n execute(event: MiddlewareEvent, context: MiddlewareContext): Promise<MiddlewareResult>;\n}\n\nfunction matchesTool(match: string | string[] | undefined, toolName: string | undefined): boolean {\n if (match === undefined) return true;\n if (toolName === undefined) return false;\n if (Array.isArray(match)) return match.includes(toolName);\n return match === toolName;\n}\n\nexport function buildMiddlewareChain(middleware: Middleware[]): MiddlewareChain {\n return {\n async execute(event: MiddlewareEvent, context: MiddlewareContext): Promise<MiddlewareResult> {\n let lastAsync: MiddlewareResult | undefined;\n\n for (const mw of middleware) {\n // Hook event matching\n if (mw.on !== event.hookEvent) continue;\n\n // Tool name matching\n if (!matchesTool(mw.match, event.toolName)) continue;\n\n const result = await mw.handler(event, context);\n\n switch (result.decision) {\n case \"block\":\n return result;\n case \"async\":\n lastAsync = result;\n break;\n case \"pass\":\n break;\n }\n }\n\n return lastAsync ?? { decision: \"pass\" };\n },\n };\n}\n\n/**\n * SDK hooks type — maps hook event names to callback matchers.\n */\nexport type SDKHooks = Partial<Record<SDKHookEvent, HookCallbackMatcher[]>>;\n\n/**\n * Convert a middleware chain to Agent SDK hooks format.\n *\n * Creates one HookCallbackMatcher per supported event (PreToolUse, PostToolUse, Notification).\n * The matcher delegates to the chain's execute method, translating SDK input to our\n * MiddlewareEvent format.\n */\nexport function buildSDKHooks(\n chain: MiddlewareChain,\n context: MiddlewareContext,\n middleware: Middleware[] = [],\n): SDKHooks {\n function makeCallback(hookEvent: HookEvent): HookCallback {\n return async (input: HookInput): Promise<HookJSONOutput> => {\n const event: MiddlewareEvent = {\n hookEvent,\n sessionId: input.session_id,\n toolName: \"tool_name\" in input ? (input.tool_name as string) : undefined,\n input: \"tool_input\" in input ? (input.tool_input as Record<string, unknown>) : undefined,\n output: \"tool_response\" in input ? String(input.tool_response) : undefined,\n message: \"message\" in input ? (input.message as string) : undefined,\n };\n\n const result = await chain.execute(event, context);\n\n switch (result.decision) {\n case \"block\":\n return { decision: \"block\", reason: result.reason };\n case \"async\":\n return { async: true, asyncTimeout: result.asyncTimeout };\n case \"pass\":\n return {};\n }\n };\n }\n\n // Only register hooks for events that have at least one middleware listener\n const usedEvents = new Set(middleware.map((mw) => mw.on));\n const allEvents: HookEvent[] = [\"PreToolUse\", \"PostToolUse\", \"Notification\"];\n\n const hooks: SDKHooks = {};\n for (const hookEvent of allEvents) {\n // When no middleware list is provided, register all events (backward-compatible)\n if (middleware.length === 0 || usedEvents.has(hookEvent)) {\n hooks[hookEvent] = [{ hooks: [makeCallback(hookEvent)] }];\n }\n }\n\n return hooks;\n}\n","import type { Middleware } from \"@/types\";\n\n/**\n * Loop detection middleware.\n *\n * Tracks Bash commands per session. If the same command appears\n * `threshold` times, blocks it and tells the agent to escalate.\n *\n * Call `cleanup(sessionId)` when a session ends to prevent memory leaks.\n */\nexport interface LoopDetectionMiddleware extends Middleware {\n cleanup: (sessionId: string) => void;\n}\n\nexport function loopDetection(options: {\n threshold: number;\n scope?: \"session\";\n}): LoopDetectionMiddleware {\n const { threshold } = options;\n const commandHistory = new Map<string, Map<string, number>>();\n\n return {\n name: \"loop-detection\",\n on: \"PreToolUse\",\n match: \"Bash\",\n cleanup(sessionId: string) {\n commandHistory.delete(sessionId);\n },\n async handler(event) {\n const sessionId = event.sessionId;\n const command =\n event.input && typeof event.input === \"object\" && \"command\" in event.input\n ? String(event.input.command)\n : \"\";\n\n if (!command) return { decision: \"pass\" };\n\n if (!commandHistory.has(sessionId)) {\n commandHistory.set(sessionId, new Map());\n }\n\n const sessionHistory = commandHistory.get(sessionId) ?? new Map<string, number>();\n const count = (sessionHistory.get(command) ?? 0) + 1;\n sessionHistory.set(command, count);\n\n if (count >= threshold) {\n return {\n decision: \"block\",\n reason: `Loop detected: you have run this exact command ${String(count)} times. STOP and escalate — do not retry the same approach.`,\n };\n }\n\n return { decision: \"pass\" };\n },\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Semaphore } from \"@/concurrency/semaphore\";\nimport type { McpServerConfig, NeoConfig, RepoConfig } from \"@/config\";\nimport { CostJournal } from \"@/cost/journal\";\nimport { NeoEventEmitter } from \"@/events\";\nimport { EventJournal } from \"@/events/journal\";\nimport { WebhookDispatcher } from \"@/events/webhook\";\nimport { createSessionClone, removeSessionClone } from \"@/isolation/clone\";\nimport { pushSessionBranch } from \"@/isolation/git\";\nimport { auditLog } from \"@/middleware/audit-log\";\nimport { budgetGuard } from \"@/middleware/budget-guard\";\nimport { loopDetection } from \"@/middleware/loop-detection\";\nimport { RunStore } from \"@/orchestrator/run-store\";\nimport { getJournalsDir, getSupervisorsDir } from \"@/paths\";\nimport { SessionExecutor } from \"@/runner/session-executor\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport { formatMemoriesForPrompt, MemoryStore } from \"@/supervisor/memory/index.js\";\nimport type {\n ActiveSession,\n CostEntry,\n DispatchInput,\n Middleware,\n NeoEvent,\n OrchestratorStatus,\n PersistedRun,\n ResolvedAgent,\n StepResult,\n TaskResult,\n} from \"@/types\";\n\n// ─── Constants ─────────────────────────────────────────\n\nconst MAX_PROMPT_SIZE = 100 * 1024; // 100 KB\nconst MAX_METADATA_DEPTH = 5;\nconst SHUTDOWN_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\nconst textEncoder = new TextEncoder();\n\n// ─── Options ───────────────────────────────────────────\n\nexport interface OrchestratorOptions {\n middleware?: Middleware[] | undefined;\n journalDir?: string | undefined;\n /** Skip orphan recovery on start — workers should set this to true to avoid false orphan detection on concurrent launches. */\n skipOrphanRecovery?: boolean | undefined;\n}\n\n// ─── Internal dispatch context ─────────────────────────\n\ninterface DispatchContext {\n input: DispatchInput;\n runId: string;\n sessionId: string;\n startedAt: number;\n agent: ResolvedAgent;\n repoConfig: RepoConfig;\n activeSession: ActiveSession;\n}\n\n// ─── Idempotency ───────────────────────────────────────\n\ninterface IdempotencyEntry {\n result: TaskResult;\n expiresAt: number;\n}\n\n// ─── Orchestrator ──────────────────────────────────────\n\nexport class Orchestrator extends NeoEventEmitter {\n private readonly config: NeoConfig;\n private readonly semaphore: Semaphore;\n private readonly userMiddleware: Middleware[];\n private readonly registeredAgents = new Map<string, ResolvedAgent>();\n private readonly _activeSessions = new Map<string, ActiveSession>();\n private readonly idempotencyCache = new Map<string, IdempotencyEntry>();\n private readonly abortControllers = new Map<string, AbortController>();\n private readonly repoIndex = new Map<string, RepoConfig>();\n private readonly runStore = new RunStore();\n private readonly journalDir: string;\n private costJournal: CostJournal | null = null;\n private eventJournal: EventJournal | null = null;\n private webhookDispatcher: WebhookDispatcher | null = null;\n private memoryStore: MemoryStore | null = null;\n private _paused = false;\n private _costToday = 0;\n private _startedAt = 0;\n private _drainResolve: (() => void) | null = null;\n\n private readonly skipOrphanRecovery: boolean;\n\n constructor(config: NeoConfig, options: OrchestratorOptions = {}) {\n super();\n this.config = config;\n this.userMiddleware = options.middleware ?? [];\n this.journalDir = options.journalDir ?? getJournalsDir();\n this.skipOrphanRecovery = options.skipOrphanRecovery ?? false;\n for (const repo of config.repos) {\n const resolvedPath = path.resolve(repo.path);\n const normalizedRepo = { ...repo, path: resolvedPath };\n this.repoIndex.set(resolvedPath, normalizedRepo);\n }\n this.semaphore = new Semaphore(\n {\n maxSessions: config.concurrency.maxSessions,\n maxPerRepo: config.concurrency.maxPerRepo,\n queueMax: config.concurrency.queueMax,\n },\n {\n onEnqueue: (sessionId, repo, position) => {\n this.emit({\n type: \"queue:enqueue\",\n sessionId,\n repo,\n position,\n timestamp: new Date().toISOString(),\n });\n },\n onDequeue: (sessionId, repo, waitedMs) => {\n this.emit({\n type: \"queue:dequeue\",\n sessionId,\n repo,\n waitedMs,\n timestamp: new Date().toISOString(),\n });\n },\n },\n );\n }\n\n // ─── Registration ──────────────────────────────────────\n\n registerAgent(agent: ResolvedAgent): void {\n this.registeredAgents.set(agent.name, agent);\n }\n\n // ─── Dispatch ──────────────────────────────────────────\n\n async dispatch(input: DispatchInput): Promise<TaskResult> {\n const idempotencyKey = this.preDispatchChecks(input);\n const ctx = this.buildDispatchContext(input);\n\n // Acquire semaphore (blocks if at capacity)\n const abortController = new AbortController();\n this.abortControllers.set(ctx.sessionId, abortController);\n await this.semaphore.acquire(\n input.repo,\n ctx.sessionId,\n input.priority ?? \"medium\",\n abortController.signal,\n );\n ctx.activeSession.status = \"running\";\n\n const stepResult = await this.executeStep(ctx);\n return this.finalizeDispatch(ctx, stepResult, idempotencyKey);\n }\n\n // ─── Control ───────────────────────────────────────────\n\n pause(): void {\n this._paused = true;\n }\n\n resume(): void {\n this._paused = false;\n }\n\n async kill(sessionId: string): Promise<void> {\n const controller = this.abortControllers.get(sessionId);\n if (controller) {\n controller.abort(new Error(\"Session killed\"));\n }\n\n this._activeSessions.delete(sessionId);\n this.abortControllers.delete(sessionId);\n this.semaphore.release(sessionId);\n }\n\n async drain(): Promise<void> {\n this._paused = true;\n if (this._activeSessions.size === 0) return;\n return new Promise<void>((resolve) => {\n this._drainResolve = resolve;\n });\n }\n\n // ─── Getters ───────────────────────────────────────────\n\n get status(): OrchestratorStatus {\n return {\n paused: this._paused,\n activeSessions: [...this._activeSessions.values()],\n activeRunCount: this.activeRunCount,\n queueDepth: this.semaphore.queueDepth(),\n costToday: this._costToday,\n budgetCapUsd: this.config.budget.dailyCapUsd,\n budgetRemainingPct: this.computeBudgetRemainingPct(),\n uptime: this._startedAt > 0 ? Date.now() - this._startedAt : 0,\n };\n }\n\n get activeSessions(): ActiveSession[] {\n return [...this._activeSessions.values()];\n }\n\n get activeRunCount(): number {\n let count = 0;\n for (const session of this._activeSessions.values()) {\n if (session.status === \"running\") {\n count++;\n }\n }\n return count;\n }\n\n // ─── Lifecycle ─────────────────────────────────────────\n\n async start(): Promise<void> {\n this._startedAt = Date.now();\n\n // Initialize journals\n this.costJournal = new CostJournal({ dir: this.journalDir });\n this.eventJournal = new EventJournal({ dir: this.journalDir });\n\n // Initialize webhook dispatcher with configured webhooks + auto-discovered supervisor webhooks\n const supervisorWebhooks = await this.discoverSupervisorWebhooks();\n\n const allWebhooks = [...this.config.webhooks, ...supervisorWebhooks];\n if (allWebhooks.length > 0) {\n this.webhookDispatcher = new WebhookDispatcher(allWebhooks);\n }\n\n // Log supervisor webhook discovery for debugging connectivity\n if (supervisorWebhooks.length > 0) {\n // biome-ignore lint/suspicious/noConsole: Intentional logging for webhook discovery\n console.log(\n `[neo] Discovered ${supervisorWebhooks.length} supervisor webhook(s): ${supervisorWebhooks.map((w) => w.url).join(\", \")}`,\n );\n }\n\n // Restore today's cost from journal\n this._costToday = await this.costJournal.getDayTotal();\n\n if (!this.skipOrphanRecovery) {\n await this.recoverOrphanedRuns();\n }\n\n await mkdir(this.config.sessions.dir, { recursive: true });\n }\n\n async shutdown(): Promise<void> {\n this._paused = true;\n\n if (this._activeSessions.size > 0) {\n await Promise.race([\n this.drain(),\n new Promise<void>((resolve) => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),\n ]);\n }\n\n for (const mw of this.userMiddleware) {\n if (\"flush\" in mw && typeof mw.flush === \"function\") {\n await (mw as { flush: () => Promise<void> }).flush();\n }\n if (\"cleanup\" in mw && typeof mw.cleanup === \"function\") {\n for (const session of this._activeSessions.values()) {\n (mw as { cleanup: (id: string) => void }).cleanup(session.sessionId);\n }\n }\n }\n\n this.emit({\n type: \"orchestrator:shutdown\",\n timestamp: new Date().toISOString(),\n });\n\n // Flush pending webhook deliveries — ensures terminal events\n // (session:complete/fail) reach the supervisor before process exits\n if (this.webhookDispatcher) {\n await this.webhookDispatcher.flush();\n }\n }\n\n // ─── Emit override (journal events) ───────────────────\n\n override emit(event: NeoEvent): void {\n super.emit(event);\n // Fire-and-forget event journal append\n if (this.eventJournal) {\n this.eventJournal.append(event).catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Log journal write failures for debugging\n console.debug(\"[neo] Event journal append failed:\", err);\n });\n }\n // Fire-and-forget webhook dispatch\n if (this.webhookDispatcher) {\n this.webhookDispatcher.dispatch(event);\n }\n }\n\n // ─── Static middleware factories ───────────────────────\n\n static middleware = {\n loopDetection: (options: { threshold: number; scope?: \"session\" }) => loopDetection(options),\n auditLog: (options: {\n dir: string;\n includeInput?: boolean;\n includeOutput?: boolean;\n flushIntervalMs?: number;\n flushSize?: number;\n }) => auditLog(options),\n budgetGuard: () => budgetGuard(),\n };\n\n // ─── Private: Dispatch phases ──────────────────────────\n\n private preDispatchChecks(input: DispatchInput): string | null {\n this.validateInput(input);\n\n const idempotencyKey = this.computeIdempotencyKey(input);\n if (idempotencyKey) {\n this.evictExpiredIdempotencyEntries();\n const cached = this.idempotencyCache.get(idempotencyKey);\n if (cached && cached.expiresAt > Date.now()) {\n throw new Error(\n `Duplicate dispatch rejected: runId '${input.runId ?? \"auto-generated\"}' already exists. Each dispatch must use a unique runId.`,\n );\n }\n }\n\n if (this._paused) {\n throw new Error(\n \"Dispatch rejected: orchestrator is paused. Call orchestrator.resume() before dispatching.\",\n );\n }\n\n return idempotencyKey;\n }\n\n private buildDispatchContext(input: DispatchInput): DispatchContext {\n const runId = input.runId ?? randomUUID();\n const sessionId = randomUUID();\n const agent = this.registeredAgents.get(input.agent);\n if (!agent) {\n const available = [...this.registeredAgents.keys()].join(\", \") || \"none\";\n throw new Error(\n `Agent \"${input.agent}\" not found. Available agents: ${available}. Register the agent first.`,\n );\n }\n const repoConfig = this.resolveRepo(input.repo);\n\n const activeSession: ActiveSession = {\n sessionId,\n runId,\n step: \"execute\",\n agent: agent.name,\n repo: input.repo,\n status: \"queued\",\n startedAt: new Date().toISOString(),\n };\n this._activeSessions.set(sessionId, activeSession);\n\n return {\n input,\n runId,\n sessionId,\n startedAt: Date.now(),\n agent,\n repoConfig,\n activeSession,\n };\n }\n\n private async executeStep(ctx: DispatchContext): Promise<StepResult> {\n const { input, runId, sessionId, startedAt, agent, repoConfig, activeSession } = ctx;\n let sessionPath: string | undefined;\n\n // Persist initial running state so `neo runs` shows this run immediately\n await this.persistRun({\n version: 1,\n runId,\n agent: agent.name,\n repo: input.repo,\n prompt: input.prompt,\n pid: process.pid,\n status: \"running\",\n steps: {},\n createdAt: activeSession.startedAt,\n updatedAt: new Date().toISOString(),\n metadata: input.metadata,\n });\n\n try {\n // Create isolated clone for ALL agents.\n // Uses the explicit branch if provided, otherwise falls back to the base branch.\n const branchName = (input.branch as string) || repoConfig.defaultBranch;\n const sessionDir = path.join(this.config.sessions.dir, runId);\n const info = await createSessionClone({\n repoPath: input.repo,\n branch: branchName,\n baseBranch: repoConfig.defaultBranch,\n sessionDir,\n });\n sessionPath = info.path;\n activeSession.sessionPath = sessionPath;\n\n const stepResult = await this.runAgentSession(ctx, sessionPath);\n this.emitCostEvents(sessionId, stepResult.costUsd, ctx);\n this.emitSessionComplete(ctx, stepResult);\n return stepResult;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.emitSessionFail(ctx, errorMsg);\n\n const failResult: StepResult = {\n status: \"failure\",\n sessionId,\n costUsd: 0,\n durationMs: Date.now() - startedAt,\n agent: agent.name,\n startedAt: activeSession.startedAt,\n completedAt: new Date().toISOString(),\n error: errorMsg,\n attempt: 1,\n };\n\n // Write episode to memory store\n try {\n const store = this.getMemoryStore();\n await store.write({\n type: \"episode\",\n scope: input.repo,\n content: `Run ${runId.slice(0, 8)} (${agent.name}): failed${failResult.error ? ` — ${failResult.error.slice(0, 150)}` : \"\"}`,\n source: agent.name,\n outcome: \"failure\",\n runId,\n });\n } catch (err) {\n // Best-effort — don't fail the run if memory write fails\n console.debug(\n `[orchestrator] Failed to write failure episode to memory: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n return failResult;\n } finally {\n // Auto-commit, push, and cleanup session clone\n if (sessionPath) {\n await this.finalizeSession(sessionPath, ctx);\n }\n\n // Cleanup middleware state for this session to prevent memory leaks\n for (const mw of this.userMiddleware) {\n if (\"cleanup\" in mw && typeof mw.cleanup === \"function\") {\n (mw as { cleanup: (id: string) => void }).cleanup(sessionId);\n }\n }\n\n this.semaphore.release(sessionId);\n this._activeSessions.delete(sessionId);\n this.abortControllers.delete(sessionId);\n\n if (this._activeSessions.size === 0 && this._drainResolve) {\n this._drainResolve();\n this._drainResolve = null;\n }\n }\n }\n\n /**\n * Push the branch (writable only), then remove the session clone.\n * Runs in `finally` so it executes on both success and failure.\n */\n private async finalizeSession(sessionPath: string, ctx: DispatchContext): Promise<void> {\n // Only push for writable agents — readonly agents have no changes to push\n if (ctx.agent.sandbox === \"writable\") {\n const branch = ctx.input.branch as string;\n const remote = ctx.repoConfig.pushRemote ?? \"origin\";\n try {\n await pushSessionBranch(sessionPath, branch, remote).catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Debug logging for push failures\n console.debug(\"[neo] Push failed:\", err);\n });\n } catch (err) {\n // biome-ignore lint/suspicious/noConsole: Debug logging for finalization errors\n console.debug(\"[neo] Finalization error:\", err);\n }\n }\n\n try {\n await removeSessionClone(sessionPath);\n } catch (err) {\n // biome-ignore lint/suspicious/noConsole: Debug logging for session cleanup errors\n console.debug(\"[neo] Session cleanup failed:\", err);\n }\n }\n\n private async runAgentSession(\n ctx: DispatchContext,\n sessionPath: string | undefined,\n ): Promise<StepResult> {\n const { input, runId, sessionId, agent, repoConfig, activeSession } = ctx;\n\n this.emit({\n type: \"session:start\",\n sessionId,\n runId,\n step: \"execute\",\n agent: agent.name,\n repo: input.repo,\n metadata: input.metadata,\n timestamp: new Date().toISOString(),\n });\n\n // Create SessionExecutor with config and context value getter\n const executor = new SessionExecutor(\n {\n initTimeoutMs: this.config.sessions.initTimeoutMs,\n maxDurationMs: this.config.sessions.maxDurationMs,\n maxRetries: this.config.recovery.maxRetries,\n backoffBaseMs: this.config.recovery.backoffBaseMs,\n },\n (key: string) => {\n if (key === \"costToday\") return this._costToday;\n if (key === \"budgetCapUsd\") return this.config.budget.dailyCapUsd;\n return undefined;\n },\n );\n\n // Build execution input\n const strategy = input.gitStrategy ?? repoConfig.gitStrategy ?? \"branch\";\n const mcpServers = this.resolveMcpServers(agent);\n const memoryContext = this.loadMemoryContext(input.repo);\n\n const result = await executor.execute(\n {\n runId,\n sessionId,\n agent,\n repoConfig,\n repoPath: input.repo,\n prompt: input.prompt,\n branch: input.branch,\n gitStrategy: strategy,\n sessionPath,\n metadata: input.metadata,\n startedAt: activeSession.startedAt,\n },\n {\n middleware: this.userMiddleware,\n mcpServers,\n memoryContext,\n onAttempt: (attempt, strategy) => {\n if (attempt > 1) {\n this.emit({\n type: \"session:fail\",\n sessionId,\n runId,\n error: `Retrying with strategy: ${strategy}`,\n attempt: attempt - 1,\n maxRetries: this.config.recovery.maxRetries,\n willRetry: true,\n metadata: input.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n },\n },\n );\n\n // Write episode to memory store\n try {\n const store = this.getMemoryStore();\n const isSuccess = result.status === \"success\";\n await store.write({\n type: \"episode\",\n scope: input.repo,\n content: `Run ${runId.slice(0, 8)} (${agent.name}): ${isSuccess ? \"completed\" : \"failed\"}${result.error ? ` — ${result.error.slice(0, 150)}` : \"\"}`,\n source: agent.name,\n outcome: isSuccess ? \"success\" : \"failure\",\n runId,\n });\n } catch (err) {\n // Best-effort — don't fail the run if memory write fails\n console.debug(\n `[orchestrator] Failed to write completion episode to memory: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n return result;\n }\n\n private async finalizeDispatch(\n ctx: DispatchContext,\n stepResult: StepResult,\n idempotencyKey: string | null,\n ): Promise<TaskResult> {\n const { input, runId, agent, activeSession } = ctx;\n\n const taskResult: TaskResult = {\n runId,\n agent: agent.name,\n repo: input.repo,\n status: stepResult.status === \"success\" ? \"success\" : \"failure\",\n steps: { execute: stepResult },\n branch:\n stepResult.status === \"success\" && activeSession.sessionPath ? input.branch : undefined,\n costUsd: stepResult.costUsd,\n durationMs: Date.now() - ctx.startedAt,\n timestamp: new Date().toISOString(),\n metadata: input.metadata,\n };\n\n if (stepResult.prUrl) {\n taskResult.prUrl = stepResult.prUrl;\n }\n if (stepResult.prNumber !== undefined) {\n taskResult.prNumber = stepResult.prNumber;\n }\n\n await this.persistRun({\n version: 1,\n runId,\n agent: agent.name,\n repo: input.repo,\n prompt: input.prompt,\n pid: process.pid,\n branch: taskResult.branch,\n status: taskResult.status === \"success\" ? \"completed\" : \"failed\",\n steps: taskResult.steps,\n createdAt: activeSession.startedAt,\n updatedAt: new Date().toISOString(),\n metadata: input.metadata,\n });\n\n if (idempotencyKey) {\n const ttl = this.config.idempotency?.ttlMs ?? 3_600_000;\n this.idempotencyCache.set(idempotencyKey, {\n result: taskResult,\n expiresAt: Date.now() + ttl,\n });\n }\n\n return taskResult;\n }\n\n // ─── Private: Memory injection ──────────────────────────\n\n private getMemoryStore(): MemoryStore {\n if (!this.memoryStore) {\n const supervisorDir = path.join(getSupervisorsDir(), \"supervisor\");\n this.memoryStore = new MemoryStore(path.join(supervisorDir, \"memory.sqlite\"));\n }\n return this.memoryStore;\n }\n\n private loadMemoryContext(repoPath: string): string | undefined {\n try {\n const store = this.getMemoryStore();\n const memories = store.query({\n scope: repoPath,\n types: [\"fact\", \"procedure\", \"feedback\"],\n limit: 25,\n sortBy: \"relevance\",\n });\n if (memories.length === 0) return undefined;\n store.markAccessed(memories.map((m) => m.id));\n return formatMemoriesForPrompt(memories);\n } catch (err) {\n // Memory store unavailable — continue without memories\n console.debug(\n `[orchestrator] Failed to load memories: ${err instanceof Error ? err.message : String(err)}`,\n );\n return undefined;\n }\n }\n\n // ─── Private: Event helpers ────────────────────────────\n\n private emitCostEvents(sessionId: string, sessionCost: number, ctx: DispatchContext): void {\n this._costToday += sessionCost;\n\n // Persist cost entry to journal (fire-and-forget)\n if (this.costJournal) {\n const costEntry: CostEntry = {\n timestamp: new Date().toISOString(),\n runId: ctx.runId,\n step: \"execute\",\n sessionId,\n agent: ctx.agent.name,\n costUsd: sessionCost,\n models: {},\n durationMs: Date.now() - ctx.startedAt,\n repo: ctx.input.repo,\n };\n this.costJournal.append(costEntry).catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Log journal write failures for debugging\n console.debug(\"[neo] Cost journal append failed:\", err);\n });\n }\n\n this.emit({\n type: \"cost:update\",\n sessionId,\n sessionCost,\n todayTotal: this._costToday,\n budgetRemainingPct: this.computeBudgetRemainingPct(),\n timestamp: new Date().toISOString(),\n });\n\n const utilizationPct = (this._costToday / this.config.budget.dailyCapUsd) * 100;\n if (utilizationPct >= this.config.budget.alertThresholdPct) {\n this.emit({\n type: \"budget:alert\",\n todayTotal: this._costToday,\n capUsd: this.config.budget.dailyCapUsd,\n utilizationPct,\n timestamp: new Date().toISOString(),\n });\n }\n }\n\n private emitSessionComplete(ctx: DispatchContext, stepResult: StepResult): void {\n this.emit({\n type: \"session:complete\",\n sessionId: ctx.sessionId,\n runId: ctx.runId,\n status: \"success\",\n costUsd: stepResult.costUsd,\n durationMs: stepResult.durationMs,\n output: stepResult.output,\n metadata: ctx.input.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n\n private emitSessionFail(ctx: DispatchContext, errorMsg: string): void {\n this.emit({\n type: \"session:fail\",\n sessionId: ctx.sessionId,\n runId: ctx.runId,\n error: errorMsg,\n attempt: 1,\n maxRetries: this.config.recovery.maxRetries,\n willRetry: false,\n metadata: ctx.input.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n\n // ─── Private: Input validation ─────────────────────────\n\n private validateInput(input: DispatchInput): void {\n if (!input.prompt || input.prompt.trim().length === 0) {\n throw new Error(\"Validation error: prompt must be a non-empty string\");\n }\n if (textEncoder.encode(input.prompt).length > MAX_PROMPT_SIZE) {\n throw new Error(\n `Validation error: prompt exceeds maximum size of ${String(MAX_PROMPT_SIZE)} bytes`,\n );\n }\n\n if (!existsSync(input.repo)) {\n throw new Error(`Validation error: repo path does not exist: ${input.repo}`);\n }\n\n if (!this.registeredAgents.has(input.agent)) {\n throw new Error(`Validation error: agent \"${input.agent}\" not found in registry`);\n }\n\n if (input.metadata !== undefined) {\n if (!isPlainObject(input.metadata)) {\n throw new Error(\"Validation error: metadata must be a plain object\");\n }\n if (objectDepth(input.metadata) > MAX_METADATA_DEPTH) {\n throw new Error(\n `Validation error: metadata exceeds maximum nesting depth of ${String(MAX_METADATA_DEPTH)}`,\n );\n }\n }\n\n const resumeOptions = [input.step, input.from, input.retry].filter(Boolean);\n if (resumeOptions.length > 1) {\n throw new Error(\"Validation error: step, from, and retry are mutually exclusive\");\n }\n }\n\n // ─── Private: Helpers ──────────────────────────────────\n\n private evictExpiredIdempotencyEntries(): void {\n const now = Date.now();\n for (const [key, entry] of this.idempotencyCache) {\n if (entry.expiresAt <= now) {\n this.idempotencyCache.delete(key);\n }\n }\n }\n\n private computeIdempotencyKey(input: DispatchInput): string | null {\n const idempotency = this.config.idempotency;\n if (!idempotency?.enabled) return null;\n\n const key = idempotency.key ?? \"metadata\";\n if (key === \"prompt\") {\n return `${input.agent}:${input.repo}:${input.prompt}`;\n }\n return `${input.agent}:${input.repo}:${JSON.stringify(input.metadata ?? {})}`;\n }\n\n private resolveRepo(repoPath: string): RepoConfig {\n const repo = this.repoIndex.get(path.resolve(repoPath));\n if (repo) return repo;\n return {\n path: repoPath,\n defaultBranch: \"main\",\n branchPrefix: \"feat\",\n pushRemote: \"origin\",\n gitStrategy: \"branch\",\n };\n }\n\n private computeBudgetRemainingPct(): number {\n const cap = this.config.budget.dailyCapUsd;\n if (cap <= 0) return 0;\n return Math.max(0, ((cap - this._costToday) / cap) * 100);\n }\n\n // ─── Private: MCP server resolution ────────────────────\n\n private resolveMcpServers(agent: ResolvedAgent): Record<string, McpServerConfig> | undefined {\n const configServers = this.config.mcpServers;\n if (!configServers) return undefined;\n\n // Collect unique server names from agent definition\n const names = agent.definition.mcpServers;\n if (!names || names.length === 0) return undefined;\n\n const resolved: Record<string, McpServerConfig> = {};\n for (const name of names) {\n const serverConfig = configServers[name];\n if (serverConfig) {\n resolved[name] = serverConfig;\n }\n }\n\n return Object.keys(resolved).length > 0 ? resolved : undefined;\n }\n\n // ─── Private: Supervisor discovery ─────────────────────\n\n /** Discover running supervisor daemons and return webhook configs for their endpoints. */\n private async discoverSupervisorWebhooks(): Promise<NeoConfig[\"webhooks\"]> {\n const { readdir } = await import(\"node:fs/promises\");\n const supervisorsDir = getSupervisorsDir();\n if (!existsSync(supervisorsDir)) return [];\n\n const webhooks: NeoConfig[\"webhooks\"] = [];\n\n try {\n const entries = await readdir(supervisorsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n try {\n const statePath = path.join(supervisorsDir, entry.name, \"state.json\");\n const raw = await readFile(statePath, \"utf-8\");\n const state = JSON.parse(raw) as { status?: string; port?: number; pid?: number };\n\n if (state.status !== \"running\" || !state.port) continue;\n if (state.pid && !isProcessAlive(state.pid)) continue;\n\n webhooks.push({\n url: `http://localhost:${String(state.port)}/webhook`,\n events: [\"session:complete\", \"session:fail\", \"budget:alert\"],\n secret: this.config.supervisor.secret,\n timeoutMs: 5000,\n });\n } catch (err) {\n // State file missing or corrupt — skip\n console.debug(\n `[orchestrator] Failed to load supervisor webhook config: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n } catch (err) {\n // Supervisors dir unreadable — skip\n console.debug(\n `[orchestrator] Failed to read supervisors directory: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n return webhooks;\n }\n\n // ─── Private: Run persistence ──────────────────────────\n\n private async persistRun(run: PersistedRun): Promise<void> {\n await this.runStore.persistRun(run);\n }\n\n private async recoverOrphanedRuns(): Promise<void> {\n const orphanedRuns = await this.runStore.recoverOrphanedRuns();\n\n // Emit session:fail for each orphaned run so the supervisor learns about them\n for (const run of orphanedRuns) {\n this.emit({\n type: \"session:fail\",\n sessionId: run.runId,\n runId: run.runId,\n error: \"Orphaned run: process died without completing\",\n attempt: 1,\n maxRetries: this.config.recovery.maxRetries,\n willRetry: false,\n metadata: run.metadata,\n timestamp: new Date().toISOString(),\n });\n }\n }\n}\n\n// ─── Utility functions ─────────────────────────────────\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction objectDepth(obj: unknown, current = 0): number {\n if (!isPlainObject(obj)) return current;\n let max = current + 1;\n for (const value of Object.values(obj)) {\n const depth = objectDepth(value, current + 1);\n if (depth > max) max = depth;\n }\n return max;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getRepoRunsDir, getRunsDir, toRepoSlug } from \"@/paths\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport type { PersistedRun } from \"@/types\";\n\nexport interface RunStoreOptions {\n runsDir?: string | undefined;\n}\n\n/** Grace period before a run without PID can be considered orphaned (ms). */\nconst ORPHAN_GRACE_PERIOD_MS = 30_000;\n\n/**\n * Handles persistence and recovery of workflow runs.\n *\n * Runs are stored as JSON files in: ~/.neo/runs/<repo-slug>/<runId>.json\n * This enables cross-process resume and status queries via `neo runs`.\n */\nexport class RunStore {\n private readonly runsDir: string;\n private readonly createdDirs = new Set<string>();\n\n constructor(options: RunStoreOptions = {}) {\n this.runsDir = options.runsDir ?? getRunsDir();\n }\n\n /**\n * Persist a run to disk. Creates the repo subdirectory if needed.\n * Fails silently — run persistence is non-critical.\n */\n async persistRun(run: PersistedRun): Promise<void> {\n try {\n const slug = toRepoSlug({ path: run.repo });\n const repoDir = getRepoRunsDir(slug);\n if (!this.createdDirs.has(repoDir)) {\n await mkdir(repoDir, { recursive: true });\n this.createdDirs.add(repoDir);\n }\n const filePath = path.join(repoDir, `${run.runId}.json`);\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Non-critical — don't fail the dispatch if persistence fails\n }\n }\n\n /**\n * Find all runs that were left in \"running\" state but whose process died.\n * Returns them so the caller can emit failure events and update status.\n */\n async recoverOrphanedRuns(): Promise<PersistedRun[]> {\n if (!existsSync(this.runsDir)) return [];\n\n const orphaned: PersistedRun[] = [];\n\n try {\n const jsonFiles = await this.collectRunFiles();\n for (const filePath of jsonFiles) {\n const run = await this.recoverRunIfOrphaned(filePath);\n if (run) orphaned.push(run);\n }\n } catch {\n // Non-critical\n }\n\n return orphaned;\n }\n\n /**\n * Collect all .json run files from the runs directory tree.\n * Searches both top-level and repo subdirectories.\n */\n async collectRunFiles(): Promise<string[]> {\n const entries = await readdir(this.runsDir, { withFileTypes: true });\n const jsonFiles: string[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const subDir = path.join(this.runsDir, entry.name);\n const subFiles = await readdir(subDir);\n for (const f of subFiles) {\n if (f.endsWith(\".json\")) jsonFiles.push(path.join(subDir, f));\n }\n } else if (entry.name.endsWith(\".json\")) {\n jsonFiles.push(path.join(this.runsDir, entry.name));\n }\n }\n\n return jsonFiles;\n }\n\n /**\n * Check if a run file represents an orphaned run.\n * If so, update its status to \"failed\" and return it.\n */\n private async recoverRunIfOrphaned(filePath: string): Promise<PersistedRun | null> {\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n\n if (run.status !== \"running\") return null;\n\n // Never mark our own process's runs as orphaned\n if (run.pid && run.pid === process.pid) return null;\n\n // If the run has a PID and the process is still alive, skip it\n if (run.pid && isProcessAlive(run.pid)) return null;\n\n // Don't mark recently created runs as orphaned — the worker process\n // may not have written its PID yet (race condition on concurrent launches)\n const ageMs = Date.now() - new Date(run.createdAt).getTime();\n if (ageMs < ORPHAN_GRACE_PERIOD_MS) return null;\n\n run.status = \"failed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n\n return run;\n }\n}\n","/**\n * Checks whether a process with the given PID is currently running.\n *\n * Uses the POSIX signal 0 trick: `process.kill(pid, 0)` doesn't actually\n * send a signal but checks whether the process exists and the current\n * process has permission to signal it. If the process doesn't exist,\n * an ESRCH error is thrown.\n *\n * @param pid - The process ID to check. Must be a positive integer.\n * @returns `true` if the process is alive and accessible, `false` otherwise.\n *\n * @example\n * ```ts\n * import { isProcessAlive } from \"@/shared/process\";\n *\n * // Check if current process is alive (always true)\n * isProcessAlive(process.pid); // => true\n *\n * // Check if a non-existent process is alive\n * isProcessAlive(999999); // => false\n * ```\n */\nexport function isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) {\n return false;\n }\n\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n // EPERM means the process exists but we lack permission to signal it\n if (error instanceof Error && \"code\" in error && error.code === \"EPERM\") {\n return true;\n }\n // ESRCH means the process does not exist\n return false;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { GitStrategy } from \"@/config\";\nimport type { ResolvedAgent } from \"@/types\";\n\n// ─── Constants ─────────────────────────────────────────\n\nconst INSTRUCTIONS_PATH = \".neo/INSTRUCTIONS.md\";\n\n// ─── Repo instructions loader ──────────────────────────\n\nexport async function loadRepoInstructions(repoPath: string): Promise<string | undefined> {\n const filePath = path.join(repoPath, INSTRUCTIONS_PATH);\n try {\n return await readFile(filePath, \"utf-8\");\n } catch {\n return undefined;\n }\n}\n\n// ─── Git strategy prompt builder ───────────────────────\n\nexport function buildGitStrategyInstructions(\n strategy: GitStrategy,\n agent: ResolvedAgent,\n branch: string,\n baseBranch: string,\n remote: string,\n metadata?: Record<string, unknown>,\n): string | null {\n const prNumber = metadata?.prNumber as number | undefined;\n\n // Readonly agents: only inject PR comment instruction if a PR exists\n if (agent.sandbox !== \"writable\") {\n if (prNumber) {\n return `## Pull Request\\n\\nPR #${String(prNumber)} is open for this task. After your review, leave your findings as a comment: \\`gh pr comment ${String(prNumber)} --body \"...\"\\`.`;\n }\n return null;\n }\n\n // Writable agents: inject git workflow context\n if (strategy === \"pr\") {\n if (prNumber) {\n return `## Git workflow\\n\\nYou are on branch \\`${branch}\\`.\\nAn open PR exists: #${String(prNumber)}.\\nAfter committing, push your changes to the branch. The PR will be updated automatically.\\nLeave a review comment on the PR summarizing what you did: \\`gh pr comment ${String(prNumber)} --body \"...\"\\`.`;\n }\n return `## Git workflow\\n\\nYou are on branch \\`${branch}\\` (base: \\`${baseBranch}\\`).\\nAfter committing:\\n1. Push: \\`git push -u ${remote} ${branch}\\`\\n2. Create a PR against \\`${baseBranch}\\` — choose a title and description that reflect the work you completed. End the PR body with: \\`🤖 Generated with [neo](https://neotx.dev)\\`\\n3. Output the PR URL on a dedicated line: \\`PR_URL: <url>\\``;\n }\n\n // strategy === \"branch\"\n return `## Git workflow\\n\\nYou are on branch \\`${branch}\\` (base: \\`${baseBranch}\\`).\\nCommit your changes. The branch will be pushed automatically.`;\n}\n\n// ─── Reporting instructions for agents ──────────────────\n\nexport function buildReportingInstructions(_runId: string): string {\n return `## Reporting & Memory\n\nYou have two tools to communicate what you learn and do: \\`neo log\\` (real-time visibility) and \\`neo memory\\` (persistent knowledge for future agents). Use both deliberately throughout your work.\n\n### Progress reporting — \\`neo log\\`\n\nChain \\`neo log\\` with the command that triggered the event — never call it standalone.\n\n<log-types>\n| Type | When to use | Example |\n|------|------------|---------|\n| \\`milestone\\` | A meaningful goal is achieved (tests pass, build succeeds, feature complete) | \\`neo log milestone \"auth middleware passing all tests\"\\` |\n| \\`action\\` | You performed a significant action (push, PR, deploy) | \\`neo log action \"pushed 3 commits to feat/auth\"\\` |\n| \\`decision\\` | You made a non-obvious choice — record WHY | \\`neo log decision \"chose JWT over sessions — stateless, simpler for MVP\"\\` |\n| \\`blocker\\` | Something is preventing progress | \\`neo log blocker \"CI fails: missing DATABASE_URL in test env\"\\` |\n| \\`discovery\\` | You found something surprising or important about the codebase | \\`neo log discovery \"API rate limiter is disabled in dev — tests hit real endpoints\"\\` |\n| \\`progress\\` | General progress update | \\`neo log progress \"3/5 endpoints migrated\"\\` |\n</log-types>\n\n<log-rules>\n- **Chain with commands**: \\`pnpm test && neo log milestone \"tests passing\" || neo log blocker \"tests failing\"\\`\n- **Log decisions with reasoning**: the \"why\" is more valuable than the \"what\"\n- **Log blockers immediately**: do not continue silently — surface problems so the supervisor can act\n- **Log at natural boundaries**: after completing a subtask, before switching context, when hitting an obstacle\n</log-rules>\n\n### Memory — \\`neo memory\\`\n\nMemory is persistent knowledge injected into future agent prompts. Write a memory when you learn something that would change HOW the next agent approaches work on this repo.\n\n<memory-types>\n| Type | When to write | Example |\n|------|--------------|---------|\n| \\`fact\\` | Stable truth that affects workflow decisions | Build quirks, CI config, auth patterns, deployment constraints |\n| \\`procedure\\` | Non-obvious multi-step workflow learned from failure | \"Run X before Y otherwise Z breaks\" |\n</memory-types>\n\n<memory-decision-tree>\nBefore writing a memory, apply this test:\n1. Can \\`cat package.json\\`, \\`ls\\`, or reading the README answer this? → Do NOT memorize.\n2. Would knowing this change how you approach the task? → Write a \\`fact\\`.\n3. Did you fail before discovering this workflow? → Write a \\`procedure\\`.\n4. Is this just a detail about what you did (file counts, line numbers, component names)? → Do NOT memorize.\n</memory-decision-tree>\n\n<memory-examples type=\"good\">\n# Affects workflow — non-obvious build/CI constraints\nneo memory write --type fact --scope $NEO_REPOSITORY \"CI requires pnpm build before push — no auto-rebuild in pipeline\"\nneo memory write --type fact --scope $NEO_REPOSITORY \"Biome enforces complexity max 20 — extract helpers for large functions\"\n\n# Learned from failure — save the next agent from the same mistake\nneo memory write --type procedure --scope $NEO_REPOSITORY \"Run pnpm db:generate after any schema.prisma change — TypeScript types won't update otherwise\"\nneo memory write --type procedure --scope $NEO_REPOSITORY \"E2E tests need STRIPE_TEST_KEY in .env.test — tests hang silently without it\"\n</memory-examples>\n\n<memory-examples type=\"bad\">\n# NEVER write these — trivial or derivable\n# \"packages/core has 71 files\" → derivable from ls\n# \"Uses React 19\" → visible in package.json\n# \"Main entry is src/index.ts\" → visible in package.json\n# \"Tests use vitest\" → visible in config files\n</memory-examples>\n\n<when-to-write>\nWrite memories at these key moments:\n- **After resolving a non-obvious issue**: the fix revealed a constraint future agents should know\n- **After discovering a build/CI/deploy quirk**: the next agent will hit the same wall without this\n- **Before finishing your task**: review what you learned — anything that would save the next agent 10+ minutes?\n- **After a failed attempt**: if you tried something that seemed right but failed, document why\n</when-to-write>`;\n}\n\n// ─── Full prompt assembler ─────────────────────────────\n\nexport function buildFullPrompt(\n agentPrompt: string | undefined,\n repoInstructions: string | undefined,\n gitInstructions: string | null,\n taskPrompt: string,\n memoryContext?: string | undefined,\n cwdInstructions?: string | undefined,\n reportingInstructions?: string | undefined,\n): string {\n const sections: string[] = [];\n\n if (agentPrompt) sections.push(agentPrompt);\n if (cwdInstructions) sections.push(cwdInstructions);\n if (memoryContext) sections.push(memoryContext);\n if (repoInstructions) sections.push(`## Repository instructions\\n\\n${repoInstructions}`);\n if (gitInstructions) sections.push(gitInstructions);\n if (reportingInstructions) sections.push(reportingInstructions);\n sections.push(`## Task\\n\\n${taskPrompt}`);\n\n return sections.join(\"\\n\\n---\\n\\n\");\n}\n","import type { ZodType } from \"zod\";\n\nexport interface ParsedOutput {\n rawOutput: string;\n output?: unknown;\n parseError?: string;\n prUrl?: string;\n prNumber?: number;\n}\n\n/**\n * Extract JSON from agent output that may be wrapped in markdown code blocks.\n * Tries multiple strategies: raw JSON parse, then markdown code block extraction.\n */\nfunction extractJson(raw: string): unknown | undefined {\n // Strategy 1: Try parsing the entire string as JSON\n try {\n return JSON.parse(raw);\n } catch {\n // Not raw JSON, continue\n }\n\n // Strategy 2: Extract from markdown code blocks (```json ... ``` or ``` ... ```)\n const codeBlockRegex = /```(?:json)?\\s*\\n?([\\s\\S]*?)```/;\n const match = raw.match(codeBlockRegex);\n if (match?.[1]) {\n try {\n return JSON.parse(match[1].trim());\n } catch {\n // Invalid JSON inside code block\n }\n }\n\n return undefined;\n}\n\n// ─── PR URL extraction ──────────────────────────────────\n\nconst PR_URL_REGEX = /^PR_URL:\\s*(https?:\\/\\/\\S+)/m;\n\nexport function extractPrUrl(raw: string): { prUrl: string; prNumber?: number } | undefined {\n const match = raw.match(PR_URL_REGEX);\n if (!match?.[1]) return undefined;\n\n const prUrl = match[1];\n const numberMatch = prUrl.match(/\\/pull\\/(\\d+)/);\n\n if (numberMatch?.[1]) {\n return { prUrl, prNumber: Number.parseInt(numberMatch[1], 10) };\n }\n return { prUrl };\n}\n\n/**\n * Parse agent output, optionally validating against a Zod schema.\n * Also extracts structured markers like PR_URL from the output.\n *\n * - If no schema: returns rawOutput only\n * - If schema provided: extracts JSON from output, validates with schema\n * - On failure: returns rawOutput + parseError (caller decides whether to retry)\n */\nexport function parseOutput(raw: string, schema?: ZodType): ParsedOutput {\n const prInfo = extractPrUrl(raw);\n const base: ParsedOutput = { rawOutput: raw };\n if (prInfo) {\n base.prUrl = prInfo.prUrl;\n if (prInfo.prNumber !== undefined) {\n base.prNumber = prInfo.prNumber;\n }\n }\n\n if (!schema) {\n return base;\n }\n\n const extracted = extractJson(raw);\n if (extracted === undefined) {\n base.parseError = \"Failed to extract JSON from output\";\n return base;\n }\n\n const result = schema.safeParse(extracted);\n if (!result.success) {\n base.parseError = `Schema validation failed: ${result.error.message}`;\n return base;\n }\n\n base.output = result.data;\n return base;\n}\n","// ─── SDK Stream Message Types ────────────────────────────\n// Unified type definitions for Claude Agent SDK stream messages.\n// Both session.ts and heartbeat.ts import from this module.\n\n/**\n * Base SDK stream message shape.\n * All messages from the SDK stream have at least a type field.\n */\nexport interface SDKStreamMessage {\n type: string;\n subtype?: string;\n}\n\n/**\n * Init message emitted when a session starts.\n * Contains the session ID for tracking.\n */\nexport interface SDKInitMessage extends SDKStreamMessage {\n type: \"system\";\n subtype: \"init\";\n session_id: string;\n}\n\n/**\n * Result message emitted when a session completes.\n * Contains the final output, cost, and turn count.\n */\nexport interface SDKResultMessage extends SDKStreamMessage {\n type: \"result\";\n subtype: \"success\" | string;\n session_id: string;\n result: string;\n total_cost_usd: number;\n num_turns: number;\n}\n\n/**\n * Content block in an assistant message.\n */\nexport interface SDKContentBlock {\n type: string;\n thinking?: string;\n text?: string;\n}\n\n/**\n * Assistant message with content blocks.\n */\nexport interface SDKAssistantMessage extends SDKStreamMessage {\n type: \"assistant\";\n message?: {\n content?: SDKContentBlock[];\n };\n}\n\n/**\n * Tool use message from the assistant.\n */\nexport interface SDKToolUseMessage extends SDKStreamMessage {\n type: \"assistant\";\n subtype: \"tool_use\";\n tool: string;\n input?: unknown;\n}\n\n/**\n * Tool result message.\n */\nexport interface SDKToolResultMessage extends SDKStreamMessage {\n type: \"assistant\";\n subtype: \"tool_result\";\n result?: string;\n}\n\n// ─── Type Guards ─────────────────────────────────────────\n\n/**\n * Check if a message is an init message (session started).\n */\nexport function isInitMessage(msg: SDKStreamMessage): msg is SDKInitMessage {\n return msg.type === \"system\" && msg.subtype === \"init\";\n}\n\n/**\n * Check if a message is a result message (session completed).\n */\nexport function isResultMessage(msg: SDKStreamMessage): msg is SDKResultMessage {\n return msg.type === \"result\";\n}\n\n/**\n * Check if a message is an assistant message with content.\n */\nexport function isAssistantMessage(msg: SDKStreamMessage): msg is SDKAssistantMessage {\n return msg.type === \"assistant\" && !msg.subtype;\n}\n\n/**\n * Check if a message is a tool use message.\n */\nexport function isToolUseMessage(msg: SDKStreamMessage): msg is SDKToolUseMessage {\n return msg.type === \"assistant\" && msg.subtype === \"tool_use\";\n}\n\n/**\n * Check if a message is a tool result message.\n */\nexport function isToolResultMessage(msg: SDKStreamMessage): msg is SDKToolResultMessage {\n return msg.type === \"assistant\" && msg.subtype === \"tool_result\";\n}\n","import type { McpServerConfig } from \"@/config\";\nimport type { SandboxConfig } from \"@/isolation/sandbox\";\nimport { isInitMessage, isResultMessage, type SDKStreamMessage } from \"@/sdk-types\";\nimport type { ResolvedAgent } from \"@/types\";\n\n// ─── Types ──────────────────────────────────────────────\n\nexport interface SessionOptions {\n agent: ResolvedAgent;\n prompt: string;\n repoPath?: string;\n sessionPath?: string;\n sandboxConfig: SandboxConfig;\n hooks?: Record<string, unknown>;\n mcpServers?: Record<string, McpServerConfig>;\n env?: Record<string, string>;\n initTimeoutMs: number;\n maxDurationMs: number;\n resumeSessionId?: string | undefined;\n onEvent?: ((event: SessionEvent) => void) | undefined;\n}\n\nexport interface SessionResult {\n sessionId: string;\n output: string;\n costUsd: number;\n durationMs: number;\n turnCount: number;\n}\n\nexport type SessionEvent =\n | { type: \"session:start\"; sessionId: string }\n | { type: \"session:complete\"; sessionId: string; result: SessionResult }\n | { type: \"session:fail\"; sessionId: string; error: string };\n\n// ─── Helpers ────────────────────────────────────────────\n\nfunction checkAborted(signal: AbortSignal): void {\n if (signal.aborted) {\n const reason = signal.reason;\n throw reason instanceof Error ? reason : new Error(String(reason));\n }\n}\n\nfunction toSessionError(error: unknown, isTimeout: boolean, sessionId: string): SessionError {\n if (error instanceof SessionError) return error;\n const message = error instanceof Error ? error.message : String(error);\n return new SessionError(message, isTimeout ? \"timeout\" : \"unknown\", sessionId);\n}\n\n// ─── Query Options Builder ──────────────────────────────\n\nfunction buildQueryOptions(options: SessionOptions): Record<string, unknown> {\n const { sessionPath, sandboxConfig } = options;\n\n const queryOptions: Record<string, unknown> = {\n // Always pass cwd: session clone for writable agents, repo root for readonly.\n // Without this, readonly agents default to process.cwd() and may write to main tree.\n cwd: sessionPath ?? options.repoPath,\n // maxTurns: agent.maxTurns,\n allowedTools: sandboxConfig.allowedTools,\n // Workers run detached without a TTY — bypass interactive permission prompts.\n // Required pair: permissionMode alone is not enough, SDK also needs the flag.\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n // Load project-level CLAUDE.md so agents inherit project rules and conventions.\n settingSources: [\"user\", \"project\", \"local\"],\n // Don't persist agent sessions — they are ephemeral clones.\n persistSession: false,\n };\n\n if (options.resumeSessionId) {\n queryOptions.resume = options.resumeSessionId;\n }\n\n if (options.mcpServers && Object.keys(options.mcpServers).length > 0) {\n queryOptions.mcpServers = options.mcpServers;\n }\n\n if (options.env && Object.keys(options.env).length > 0) {\n // Merge with process.env so PATH, HOME, etc. are preserved.\n // Custom vars override process.env if there's a conflict.\n queryOptions.env = { ...process.env, ...options.env };\n }\n\n return queryOptions;\n}\n\n// ─── Session Runner ─────────────────────────────────────\n\nexport async function runSession(options: SessionOptions): Promise<SessionResult> {\n const { prompt, initTimeoutMs, maxDurationMs, onEvent } = options;\n\n const startTime = Date.now();\n let sessionId = \"\";\n\n const abortController = new AbortController();\n const initTimer = setTimeout(() => {\n abortController.abort(new Error(\"Session init timeout exceeded\"));\n }, initTimeoutMs);\n const maxDurationTimer = setTimeout(() => {\n abortController.abort(new Error(\"Session max duration exceeded\"));\n }, maxDurationMs);\n\n try {\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\");\n const queryOptions = buildQueryOptions(options);\n\n let output = \"\";\n let costUsd = 0;\n let turnCount = 0;\n\n // The prompt is already assembled by the orchestrator (agent prompt +\n // repo instructions + git strategy context + task). Session just passes it through.\n const stream = sdk.query({ prompt, options: queryOptions as never });\n\n for await (const message of stream) {\n checkAborted(abortController.signal);\n\n const msg = message as SDKStreamMessage;\n\n if (isInitMessage(msg)) {\n sessionId = msg.session_id;\n clearTimeout(initTimer);\n onEvent?.({ type: \"session:start\", sessionId });\n }\n\n if (isResultMessage(msg)) {\n output = msg.result ?? \"\";\n costUsd = msg.total_cost_usd ?? 0;\n turnCount = msg.num_turns ?? 0;\n sessionId = msg.session_id ?? sessionId;\n\n if (msg.subtype !== \"success\") {\n throw new SessionError(\n `Session ended with error: ${msg.subtype}`,\n msg.subtype,\n sessionId,\n );\n }\n }\n }\n\n const sessionResult: SessionResult = {\n sessionId,\n output,\n costUsd,\n durationMs: Date.now() - startTime,\n turnCount,\n };\n\n onEvent?.({ type: \"session:complete\", sessionId, result: sessionResult });\n return sessionResult;\n } catch (error) {\n const errorSessionId = sessionId || \"unknown\";\n const sessionError = toSessionError(error, abortController.signal.aborted, errorSessionId);\n\n onEvent?.({ type: \"session:fail\", sessionId: errorSessionId, error: sessionError.message });\n throw sessionError;\n } finally {\n clearTimeout(initTimer);\n clearTimeout(maxDurationTimer);\n }\n}\n\n// ─── Error class ────────────────────────────────────────\n\nexport class SessionError extends Error {\n constructor(\n message: string,\n public readonly errorType: string,\n public readonly sessionId: string,\n ) {\n super(message);\n this.name = \"SessionError\";\n }\n}\n","import {\n runSession,\n SessionError,\n type SessionOptions,\n type SessionResult,\n} from \"@/runner/session\";\n\n// ─── Types ──────────────────────────────────────────────\n\nexport interface RecoveryOptions extends SessionOptions {\n maxRetries: number;\n backoffBaseMs: number;\n nonRetryable?: string[];\n onAttempt?: (attempt: number, strategy: string) => void;\n}\n\n// ─── Default non-retryable errors ───────────────────────\n\nconst DEFAULT_NON_RETRYABLE = [\"error_max_turns\", \"budget_exceeded\"];\n\n// ─── Recovery strategy names ────────────────────────────\n\nfunction getStrategy(attempt: number): string {\n switch (attempt) {\n case 1:\n return \"normal\";\n case 2:\n return \"resume\";\n default:\n return \"fresh\";\n }\n}\n\n// ─── Sleep utility ──────────────────────────────────────\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ─── Error handling ─────────────────────────────────────\n\nfunction isNonRetryable(error: unknown, nonRetryable: string[]): boolean {\n return error instanceof SessionError && nonRetryable.includes(error.errorType);\n}\n\nfunction updateSessionId(error: unknown, current: string | undefined): string | undefined {\n if (error instanceof SessionError && error.sessionId !== \"unknown\") {\n return error.sessionId;\n }\n return current;\n}\n\nfunction buildFinalError(error: unknown, maxRetries: number): Error {\n if (error instanceof Error) {\n return new Error(`Recovery failed after ${maxRetries} attempts. Last error: ${error.message}`, {\n cause: error,\n });\n }\n return new Error(`Recovery failed after ${maxRetries} attempts`);\n}\n\n/**\n * Run a session with 3-level recovery escalation (ADR-020).\n *\n * Level 1 (attempt 1): Normal execution — new session\n * Level 2 (attempt 2): Resume session — pass resumeSessionId from level 1\n * Level 3 (attempt 3): Fresh session — abandon previous, start clean\n *\n * Non-retryable errors skip to immediate failure.\n * Backoff: backoffBaseMs * attempt between levels.\n */\nexport async function runWithRecovery(options: RecoveryOptions): Promise<SessionResult> {\n const {\n maxRetries,\n backoffBaseMs,\n nonRetryable = DEFAULT_NON_RETRYABLE,\n onAttempt,\n ...rest\n } = options;\n\n let lastSessionId: string | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const strategy = getStrategy(attempt);\n onAttempt?.(attempt, strategy);\n\n try {\n const result = await runSession({\n ...rest,\n resumeSessionId: strategy === \"resume\" ? lastSessionId : undefined,\n });\n return result;\n } catch (error) {\n lastSessionId = updateSessionId(error, lastSessionId);\n\n if (isNonRetryable(error, nonRetryable)) throw error;\n if (attempt === maxRetries) throw buildFinalError(error, maxRetries);\n\n // Next attempt will be \"fresh\" — clear session to start clean\n if (getStrategy(attempt + 1) === \"fresh\") {\n lastSessionId = undefined;\n }\n\n await sleep(backoffBaseMs * attempt);\n }\n }\n\n throw new Error(\"Recovery failed: unreachable\");\n}\n","import type { GitStrategy, McpServerConfig, RepoConfig } from \"@/config\";\nimport { buildSandboxConfig } from \"@/isolation/sandbox\";\nimport { buildMiddlewareChain, buildSDKHooks } from \"@/middleware/chain\";\nimport {\n buildFullPrompt,\n buildGitStrategyInstructions,\n buildReportingInstructions,\n loadRepoInstructions,\n} from \"@/orchestrator/prompt-builder\";\nimport { type ParsedOutput, parseOutput } from \"@/runner/output-parser\";\nimport { runWithRecovery } from \"@/runner/recovery\";\nimport type { Middleware, MiddlewareContext, ResolvedAgent, StepResult } from \"@/types\";\n\n// ─── Types ─────────────────────────────────────────────\n\nexport interface SessionExecutionInput {\n runId: string;\n sessionId: string;\n agent: ResolvedAgent;\n repoConfig: RepoConfig;\n repoPath: string;\n prompt: string;\n branch?: string | undefined;\n gitStrategy: GitStrategy;\n sessionPath?: string | undefined;\n metadata?: Record<string, unknown> | undefined;\n startedAt: string;\n}\n\nexport interface SessionExecutionConfig {\n initTimeoutMs: number;\n maxDurationMs: number;\n maxRetries: number;\n backoffBaseMs: number;\n}\n\nexport interface SessionExecutionDeps {\n middleware: Middleware[];\n mcpServers?: Record<string, McpServerConfig> | undefined;\n memoryContext?: string | undefined;\n onAttempt?: (attempt: number, strategy: string) => void;\n}\n\nexport interface SessionExecutionResult extends StepResult {\n parsed: ParsedOutput;\n}\n\n// ─── Middleware context builder ────────────────────────\n\nfunction buildMiddlewareContext(\n runId: string,\n step: string,\n agent: string,\n repo: string,\n getContextValue: (key: string) => unknown,\n): MiddlewareContext {\n const store = new Map<string, unknown>();\n return {\n runId,\n step,\n agent,\n repo,\n get: ((key: string) => {\n const value = getContextValue(key);\n if (value !== undefined) return value;\n return store.get(key);\n }) as MiddlewareContext[\"get\"],\n set: ((key: string, value: unknown) => {\n store.set(key, value);\n }) as MiddlewareContext[\"set\"],\n };\n}\n\n// ─── SessionExecutor ───────────────────────────────────\n\n/**\n * Encapsulates session execution logic: prompt building, SDK calls, and response processing.\n * Extracted from Orchestrator for better testability and separation of concerns.\n */\nexport class SessionExecutor {\n constructor(\n private readonly config: SessionExecutionConfig,\n private readonly getContextValue: (key: string) => unknown,\n ) {}\n\n /**\n * Execute an agent session with the given input and dependencies.\n * Handles prompt building, SDK invocation via recovery wrapper, and output parsing.\n */\n async execute(\n input: SessionExecutionInput,\n deps: SessionExecutionDeps,\n ): Promise<SessionExecutionResult> {\n const {\n runId,\n agent,\n repoConfig,\n repoPath,\n prompt: taskPrompt,\n branch,\n gitStrategy,\n sessionPath,\n metadata,\n startedAt,\n } = input;\n\n const { middleware, mcpServers, memoryContext, onAttempt } = deps;\n\n // Validate writable agents have a branch\n if (agent.sandbox === \"writable\" && !branch) {\n throw new Error(\n \"Validation error: --branch is required for writable agents. Provide an explicit branch name (e.g. --branch feat/PROJ-42-description).\",\n );\n }\n\n const branchName = agent.sandbox === \"writable\" ? (branch as string) : \"\";\n\n // Build sandbox config for agent\n const sandboxConfig = buildSandboxConfig(agent, sessionPath);\n\n // Build middleware chain and SDK hooks\n const chain = buildMiddlewareChain(middleware);\n const middlewareContext = buildMiddlewareContext(\n runId,\n \"execute\",\n agent.name,\n repoPath,\n this.getContextValue,\n );\n const hooks = buildSDKHooks(chain, middlewareContext, middleware);\n\n // Build the full prompt\n const repoInstructions = await loadRepoInstructions(repoPath);\n const gitInstructions = buildGitStrategyInstructions(\n gitStrategy,\n agent,\n branchName,\n repoConfig.defaultBranch,\n repoConfig.pushRemote ?? \"origin\",\n metadata,\n );\n\n const cwdInstructions = sessionPath\n ? `## Working directory\\n\\nYou are working in an isolated clone at: \\`${sessionPath}\\`\\nALWAYS run commands from this directory. NEVER cd to or operate on any other repository.`\n : undefined;\n\n const reportingInstructions = buildReportingInstructions(runId);\n\n const fullPrompt = buildFullPrompt(\n agent.definition.prompt,\n repoInstructions,\n gitInstructions,\n taskPrompt,\n memoryContext,\n cwdInstructions,\n reportingInstructions,\n );\n\n // Execute session with recovery\n const agentEnv: Record<string, string> = {\n NEO_RUN_ID: runId,\n NEO_AGENT_NAME: agent.name,\n NEO_REPOSITORY: repoPath,\n };\n\n const sessionResult = await runWithRecovery({\n agent,\n prompt: fullPrompt,\n repoPath,\n sandboxConfig,\n hooks,\n env: agentEnv,\n initTimeoutMs: this.config.initTimeoutMs,\n maxDurationMs: this.config.maxDurationMs,\n maxRetries: this.config.maxRetries,\n backoffBaseMs: this.config.backoffBaseMs,\n ...(sessionPath ? { sessionPath } : {}),\n ...(mcpServers ? { mcpServers } : {}),\n ...(onAttempt ? { onAttempt } : {}),\n });\n\n // Parse output\n const parsed = parseOutput(sessionResult.output);\n\n // Build result\n const result: SessionExecutionResult = {\n status: \"success\",\n sessionId: sessionResult.sessionId,\n output: parsed.output ?? parsed.rawOutput,\n rawOutput: sessionResult.output,\n costUsd: sessionResult.costUsd,\n durationMs: sessionResult.durationMs,\n agent: agent.name,\n startedAt,\n completedAt: new Date().toISOString(),\n attempt: 1,\n parsed,\n };\n\n if (parsed.prUrl) {\n result.prUrl = parsed.prUrl;\n }\n if (parsed.prNumber !== undefined) {\n result.prNumber = parsed.prNumber;\n }\n\n return result;\n }\n}\n\n// ─── Standalone prompt builders (re-exported for backward compatibility) ───\n\nexport {\n buildFullPrompt,\n buildGitStrategyInstructions,\n buildReportingInstructions,\n loadRepoInstructions,\n};\n","// ─── Embedder interface ──────────────────────────────────\n\nexport interface Embedder {\n embed(texts: string[]): Promise<number[][]>;\n readonly dimensions: number;\n}\n\n// ─── Local embedder (Transformers.js) ────────────────────\n\nlet extractorPromise: Promise<unknown> | null = null;\n\nfunction getExtractor(): Promise<unknown> {\n if (!extractorPromise) {\n extractorPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n return pipeline(\"feature-extraction\", \"Xenova/all-MiniLM-L6-v2\", {\n dtype: \"fp32\",\n });\n })();\n }\n return extractorPromise;\n}\n\nexport class LocalEmbedder implements Embedder {\n readonly dimensions = 384;\n\n async embed(texts: string[]): Promise<number[][]> {\n const extractor = (await getExtractor()) as (\n texts: string[],\n opts: { pooling: string; normalize: boolean },\n ) => Promise<{ tolist(): number[][] }>;\n const output = await extractor(texts, { pooling: \"mean\", normalize: true });\n return output.tolist();\n }\n}\n\n// ─── Cosine similarity ──────────────────────────────────\n\nexport function cosineSimilarity(a: number[], b: number[]): number {\n let dot = 0;\n let normA = 0;\n let normB = 0;\n for (let i = 0; i < a.length; i++) {\n dot += (a[i] ?? 0) * (b[i] ?? 0);\n normA += (a[i] ?? 0) * (a[i] ?? 0);\n normB += (b[i] ?? 0) * (b[i] ?? 0);\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB);\n return denom === 0 ? 0 : dot / denom;\n}\n","import { z } from \"zod\";\n\n// ─── Memory types ────────────────────────────────────────\n\nexport const memoryTypeSchema = z.enum([\n \"fact\",\n \"procedure\",\n \"episode\",\n \"focus\",\n \"feedback\",\n \"task\",\n]);\n\nexport type MemoryType = z.infer<typeof memoryTypeSchema>;\n\n// ─── Memory entry (persisted in SQLite) ──────────────────\n\nexport const memoryEntrySchema = z.object({\n id: z.string(),\n type: memoryTypeSchema,\n scope: z.string(), // \"global\" | repo path\n content: z.string(),\n source: z.string(), // \"developer\" | \"reviewer\" | \"supervisor\" | \"user\"\n tags: z.array(z.string()).default([]),\n\n // Lifecycle\n createdAt: z.string(),\n lastAccessedAt: z.string(),\n accessCount: z.number().default(0),\n\n // Optional per-type fields\n expiresAt: z.string().optional(), // focus TTL\n outcome: z.string().optional(), // episode: success/failure/blocked\n runId: z.string().optional(),\n category: z.string().optional(), // feedback: reviewer issue category\n severity: z.string().optional(),\n supersedes: z.string().optional(), // contradiction resolution\n});\n\nexport type MemoryEntry = z.infer<typeof memoryEntrySchema>;\n\n// ─── Write input (id and timestamps are auto-generated) ──\n\nexport const memoryWriteInputSchema = z.object({\n type: memoryTypeSchema,\n scope: z.string().default(\"global\"),\n content: z.string(),\n source: z.string().default(\"user\"),\n tags: z.array(z.string()).default([]),\n expiresAt: z.string().optional(),\n outcome: z.string().optional(),\n runId: z.string().optional(),\n category: z.string().optional(),\n severity: z.string().optional(),\n supersedes: z.string().optional(),\n});\n\nexport type MemoryWriteInput = z.input<typeof memoryWriteInputSchema>;\n\n// ─── Query options ───────────────────────────────────────\n\nexport interface MemoryQuery {\n scope?: string;\n types?: MemoryType[];\n since?: string; // ISO timestamp\n limit?: number;\n sortBy?: \"relevance\" | \"createdAt\" | \"accessCount\";\n tags?: string[];\n}\n\n// ─── Stats ───────────────────────────────────────────────\n\nexport interface MemoryStats {\n total: number;\n byType: Record<string, number>;\n byScope: Record<string, number>;\n}\n","import type { MemoryEntry } from \"./entry.js\";\n\nconst TYPE_LABELS: Record<string, string> = {\n fact: \"Fact\",\n procedure: \"How-to\",\n episode: \"Past run\",\n focus: \"Current focus\",\n feedback: \"Recurring issue\",\n};\n\nconst TYPE_ICONS: Record<string, string> = {\n fact: \"·\",\n procedure: \"→\",\n episode: \"◇\",\n focus: \"★\",\n feedback: \"⚠\",\n};\n\n/**\n * Format a list of memories for injection into an agent or supervisor prompt.\n * Groups by type, renders as concise markdown.\n */\nexport function formatMemoriesForPrompt(memories: MemoryEntry[]): string {\n if (memories.length === 0) return \"\";\n\n const grouped = new Map<string, MemoryEntry[]>();\n for (const m of memories) {\n const group = grouped.get(m.type) ?? [];\n group.push(m);\n grouped.set(m.type, group);\n }\n\n const sections: string[] = [];\n\n for (const [type, entries] of grouped) {\n const label = TYPE_LABELS[type] ?? type;\n const icon = TYPE_ICONS[type] ?? \"·\";\n const lines = entries.map((e) => {\n const confidence = e.accessCount >= 3 ? \"\" : \" (unconfirmed)\";\n return `${icon} ${e.content}${confidence}`;\n });\n sections.push(`### ${label}s\\n${lines.join(\"\\n\")}`);\n }\n\n return `## Known context for this repository\\n\\n${sections.join(\"\\n\\n\")}`;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport type { Embedder } from \"./embedder.js\";\nimport type { MemoryEntry, MemoryQuery, MemoryStats, MemoryWriteInput } from \"./entry.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\n// ─── MemoryStore ─────────────────────────────────────────\n\nexport class MemoryStore {\n private db: import(\"better-sqlite3\").Database;\n private embedder: Embedder | null;\n private hasVec: boolean;\n\n constructor(dbPath: string, embedder?: Embedder | null) {\n const dir = path.dirname(dbPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // better-sqlite3 is synchronous — import at module level would break ESM lazy loading\n const Database = esmRequire(\"better-sqlite3\");\n this.db = new Database(dbPath);\n this.db.pragma(\"journal_mode = WAL\");\n this.db.pragma(\"foreign_keys = ON\");\n\n this.embedder = embedder ?? null;\n this.hasVec = false;\n\n this.initSchema();\n }\n\n // ─── Schema initialization ───────────────────────────\n\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('fact','procedure','episode','focus','feedback','task')),\n scope TEXT NOT NULL,\n content TEXT NOT NULL,\n source TEXT NOT NULL,\n tags TEXT DEFAULT '[]',\n created_at TEXT NOT NULL,\n last_accessed_at TEXT NOT NULL,\n access_count INTEGER DEFAULT 0,\n expires_at TEXT,\n outcome TEXT,\n run_id TEXT,\n category TEXT,\n severity TEXT,\n supersedes TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_mem_type_scope ON memories(type, scope);\n CREATE INDEX IF NOT EXISTS idx_mem_created ON memories(created_at);\n `);\n\n // Migrate CHECK constraint if table predates 'task' type\n this.migrateCheckConstraint();\n\n // FTS5 for full-text search\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(\n content,\n content='memories',\n content_rowid='rowid',\n tokenize='porter'\n );\n `);\n\n // Triggers to keep FTS in sync\n this.db.exec(`\n CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN\n INSERT INTO memories_fts(rowid, content) VALUES (new.rowid, new.content);\n END;\n CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content) VALUES('delete', old.rowid, old.content);\n END;\n CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN\n INSERT INTO memories_fts(memories_fts, rowid, content) VALUES('delete', old.rowid, old.content);\n INSERT INTO memories_fts(rowid, content) VALUES (new.rowid, new.content);\n END;\n `);\n\n // sqlite-vec for vector search (optional — may not be installed)\n if (this.embedder) {\n try {\n const sqliteVec = esmRequire(\"sqlite-vec\");\n sqliteVec.load(this.db);\n this.db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS memories_vec USING vec0(\n memory_id TEXT,\n embedding float[${this.embedder.dimensions}]\n );\n `);\n this.hasVec = true;\n } catch {\n // sqlite-vec not available — fall back to FTS\n this.hasVec = false;\n }\n }\n }\n\n /**\n * Migrate existing tables whose CHECK constraint predates the 'task' type.\n * SQLite doesn't allow ALTER CHECK, so we recreate the table if needed.\n */\n private migrateCheckConstraint(): void {\n const tableInfo = this.db\n .prepare(\"SELECT sql FROM sqlite_master WHERE type='table' AND name='memories'\")\n .get() as { sql: string } | undefined;\n if (!tableInfo || tableInfo.sql.includes(\"'task'\")) return;\n\n this.db.exec(`\n ALTER TABLE memories RENAME TO memories_old;\n\n CREATE TABLE memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('fact','procedure','episode','focus','feedback','task')),\n scope TEXT NOT NULL,\n content TEXT NOT NULL,\n source TEXT NOT NULL,\n tags TEXT DEFAULT '[]',\n created_at TEXT NOT NULL,\n last_accessed_at TEXT NOT NULL,\n access_count INTEGER DEFAULT 0,\n expires_at TEXT,\n outcome TEXT,\n run_id TEXT,\n category TEXT,\n severity TEXT,\n supersedes TEXT\n );\n\n INSERT INTO memories SELECT * FROM memories_old;\n DROP TABLE memories_old;\n `);\n }\n\n // ─── Write ───────────────────────────────────────────\n\n async write(input: MemoryWriteInput): Promise<string> {\n const id = `mem_${randomUUID().slice(0, 12)}`;\n const now = new Date().toISOString();\n\n this.db\n .prepare(\n `INSERT INTO memories (id, type, scope, content, source, tags, created_at, last_accessed_at, access_count, expires_at, outcome, run_id, category, severity, supersedes)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n input.type,\n input.scope ?? \"global\",\n input.content,\n input.source ?? \"user\",\n JSON.stringify(input.tags ?? []),\n now,\n now,\n input.expiresAt ?? null,\n input.outcome ?? null,\n input.runId ?? null,\n input.category ?? null,\n input.severity ?? null,\n input.supersedes ?? null,\n );\n\n // Embed and store vector\n if (this.embedder && this.hasVec) {\n try {\n const [vector] = await this.embedder.embed([input.content]);\n const rowid = this.db.prepare(\"SELECT rowid FROM memories WHERE id = ?\").get(id) as\n | { rowid: number }\n | undefined;\n if (rowid && vector) {\n this.db\n .prepare(\"INSERT INTO memories_vec (rowid, memory_id, embedding) VALUES (?, ?, ?)\")\n .run(rowid.rowid, id, new Float32Array(vector));\n }\n } catch {\n // Embedding failed — entry still saved without vector\n }\n }\n\n return id;\n }\n\n // ─── Update ──────────────────────────────────────────\n\n update(id: string, content: string): void {\n this.db.prepare(\"UPDATE memories SET content = ? WHERE id = ?\").run(content, id);\n\n // Re-embedding happens lazily on next search if needed\n // For now, remove stale vector\n if (this.hasVec) {\n const row = this.db.prepare(\"SELECT rowid FROM memories WHERE id = ?\").get(id) as\n | { rowid: number }\n | undefined;\n if (row) {\n this.db.prepare(\"DELETE FROM memories_vec WHERE rowid = ?\").run(row.rowid);\n }\n }\n }\n\n // ─── Update fields ───────────────────────────────────\n\n updateFields(id: string, fields: { content?: string; outcome?: string; runId?: string }): void {\n const sets: string[] = [];\n const params: unknown[] = [];\n if (fields.content !== undefined) {\n sets.push(\"content = ?\");\n params.push(fields.content);\n }\n if (fields.outcome !== undefined) {\n sets.push(\"outcome = ?\");\n params.push(fields.outcome);\n }\n if (fields.runId !== undefined) {\n sets.push(\"run_id = ?\");\n params.push(fields.runId);\n }\n if (sets.length === 0) return;\n params.push(id);\n this.db.prepare(`UPDATE memories SET ${sets.join(\", \")} WHERE id = ?`).run(...params);\n }\n\n // ─── Forget ──────────────────────────────────────────\n\n forget(id: string): void {\n const row = this.db.prepare(\"SELECT rowid FROM memories WHERE id = ?\").get(id) as\n | { rowid: number }\n | undefined;\n if (row && this.hasVec) {\n this.db.prepare(\"DELETE FROM memories_vec WHERE rowid = ?\").run(row.rowid);\n }\n this.db.prepare(\"DELETE FROM memories WHERE id = ?\").run(id);\n }\n\n // ─── Query (synchronous — structured filters) ───────\n\n query(opts: MemoryQuery = {}): MemoryEntry[] {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (opts.scope) {\n conditions.push(\"(scope = ? OR scope = 'global')\");\n params.push(opts.scope);\n }\n\n if (opts.types && opts.types.length > 0) {\n const placeholders = opts.types.map(() => \"?\").join(\",\");\n conditions.push(`type IN (${placeholders})`);\n params.push(...opts.types);\n }\n\n if (opts.since) {\n conditions.push(\"created_at > ?\");\n params.push(opts.since);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n\n let orderBy: string;\n switch (opts.sortBy) {\n case \"accessCount\":\n orderBy = \"ORDER BY access_count DESC\";\n break;\n case \"createdAt\":\n orderBy = \"ORDER BY created_at DESC\";\n break;\n default:\n orderBy =\n \"ORDER BY (access_count * MAX(0, 1.0 - (julianday('now') - julianday(last_accessed_at)) / 60.0)) DESC\";\n break;\n }\n\n const limit = opts.limit ? `LIMIT ${opts.limit}` : \"LIMIT 50\";\n\n const rows = this.db\n .prepare(`SELECT * FROM memories ${where} ${orderBy} ${limit}`)\n .all(...params) as RawMemoryRow[];\n\n return rows.map(rowToEntry);\n }\n\n // ─── Search (async — semantic or FTS) ────────────────\n\n async search(text: string, opts: MemoryQuery = {}): Promise<MemoryEntry[]> {\n // Try vector search first\n if (this.embedder && this.hasVec) {\n try {\n const [queryVec] = await this.embedder.embed([text]);\n const limit = opts.limit ?? 20;\n\n // Build scope/type filter for post-filtering\n const candidates = this.db\n .prepare(\n `SELECT m.*, v.distance\n FROM memories_vec v\n JOIN memories m ON m.rowid = v.rowid\n WHERE v.embedding MATCH ?\n ORDER BY v.distance\n LIMIT ?`,\n )\n .all(new Float32Array(queryVec as number[]), limit * 3) as (RawMemoryRow & {\n distance: number;\n })[];\n\n // Post-filter by scope and type\n const filtered = candidates.filter((row) => {\n if (opts.scope && row.scope !== opts.scope && row.scope !== \"global\") return false;\n if (\n opts.types &&\n opts.types.length > 0 &&\n !opts.types.includes(row.type as MemoryEntry[\"type\"])\n )\n return false;\n return true;\n });\n\n return filtered.slice(0, limit).map((row) => rowToEntry(row));\n } catch {\n // Fall through to FTS\n }\n }\n\n // Fallback: FTS5 full-text search\n const limit = opts.limit ?? 20;\n const ftsQuery = text\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w}\"`)\n .join(\" OR \");\n\n if (!ftsQuery) return this.query(opts);\n\n try {\n const rows = this.db\n .prepare(\n `SELECT m.*, rank\n FROM memories_fts fts\n JOIN memories m ON m.rowid = fts.rowid\n WHERE memories_fts MATCH ?\n ORDER BY rank\n LIMIT ?`,\n )\n .all(ftsQuery, limit) as RawMemoryRow[];\n\n const filtered = rows.filter((row) => {\n if (opts.scope && row.scope !== opts.scope && row.scope !== \"global\") return false;\n if (\n opts.types &&\n opts.types.length > 0 &&\n !opts.types.includes(row.type as MemoryEntry[\"type\"])\n )\n return false;\n return true;\n });\n\n return filtered.map(rowToEntry);\n } catch {\n // FTS query syntax error — fall back to LIKE\n return this.query(opts);\n }\n }\n\n // ─── Lifecycle ───────────────────────────────────────\n\n markAccessed(ids: string[]): void {\n if (ids.length === 0) return;\n const now = new Date().toISOString();\n const stmt = this.db.prepare(\n \"UPDATE memories SET access_count = access_count + 1, last_accessed_at = ? WHERE id = ?\",\n );\n const transaction = this.db.transaction(() => {\n for (const id of ids) {\n stmt.run(now, id);\n }\n });\n transaction();\n }\n\n decay(maxAgeDays = 30, minAccessCount = 3): number {\n // Delete stale low-access memories\n const staleResult = this.db\n .prepare(\n `DELETE FROM memories\n WHERE access_count < ?\n AND julianday('now') - julianday(last_accessed_at) > ?\n AND type NOT IN ('focus', 'task')`,\n )\n .run(minAccessCount, maxAgeDays);\n\n // Delete completed tasks older than 7 days\n const taskResult = this.db\n .prepare(\n `DELETE FROM memories\n WHERE type = 'task'\n AND outcome = 'done'\n AND julianday('now') - julianday(last_accessed_at) > 7`,\n )\n .run();\n\n return staleResult.changes + taskResult.changes;\n }\n\n expireEphemeral(): number {\n const result = this.db\n .prepare(\n `DELETE FROM memories\n WHERE type = 'focus'\n AND expires_at IS NOT NULL\n AND expires_at < ?`,\n )\n .run(new Date().toISOString());\n return result.changes;\n }\n\n // ─── Stats ───────────────────────────────────────────\n\n stats(): MemoryStats {\n const total = (\n this.db.prepare(\"SELECT COUNT(*) as count FROM memories\").get() as { count: number }\n ).count;\n\n const byTypeRows = this.db\n .prepare(\"SELECT type, COUNT(*) as count FROM memories GROUP BY type\")\n .all() as { type: string; count: number }[];\n const byType: Record<string, number> = {};\n for (const row of byTypeRows) {\n byType[row.type] = row.count;\n }\n\n const byScopeRows = this.db\n .prepare(\"SELECT scope, COUNT(*) as count FROM memories GROUP BY scope\")\n .all() as { scope: string; count: number }[];\n const byScope: Record<string, number> = {};\n for (const row of byScopeRows) {\n byScope[row.scope] = row.count;\n }\n\n return { total, byType, byScope };\n }\n\n // ─── Cleanup ─────────────────────────────────────────\n\n close(): void {\n this.db.close();\n }\n}\n\n// ─── Internal helpers ────────────────────────────────────\n\ninterface RawMemoryRow {\n id: string;\n type: string;\n scope: string;\n content: string;\n source: string;\n tags: string;\n created_at: string;\n last_accessed_at: string;\n access_count: number;\n expires_at: string | null;\n outcome: string | null;\n run_id: string | null;\n category: string | null;\n severity: string | null;\n supersedes: string | null;\n}\n\nfunction rowToEntry(row: RawMemoryRow): MemoryEntry {\n let tags: string[] = [];\n try {\n tags = JSON.parse(row.tags);\n } catch {\n tags = [];\n }\n\n return {\n id: row.id,\n type: row.type as MemoryEntry[\"type\"],\n scope: row.scope,\n content: row.content,\n source: row.source,\n tags,\n createdAt: row.created_at,\n lastAccessedAt: row.last_accessed_at,\n accessCount: row.access_count,\n expiresAt: row.expires_at ?? undefined,\n outcome: row.outcome ?? undefined,\n runId: row.run_id ?? undefined,\n category: row.category ?? undefined,\n severity: row.severity ?? undefined,\n supersedes: row.supersedes ?? undefined,\n };\n}\n","import { z } from \"zod\";\n\nexport type { Decision, DecisionOption } from \"./decisions.js\";\n// ─── Decision schemas (re-exported for centralized access) ────\nexport {\n decisionOptionSchema,\n decisionSchema,\n} from \"./decisions.js\";\n\n// ─── Wake reason (why daemon woke from idle) ─────────────\n\nexport const wakeReasonSchema = z.enum([\"events\", \"timer\", \"active_runs\", \"forced\"]);\n\nexport type WakeReason = z.infer<typeof wakeReasonSchema>;\n\n// ─── Base supervisor fields (shared between daemon state and API status) ──\n\n/**\n * Common fields shared between supervisorDaemonStateSchema and supervisorStatusSchema.\n * Extracted to avoid duplication and ensure consistency.\n */\nconst supervisorBaseFieldsSchema = z.object({\n pid: z.number(),\n sessionId: z.string(),\n startedAt: z.string(),\n heartbeatCount: z.number(),\n totalCostUsd: z.number(),\n todayCostUsd: z.number(),\n});\n\n// ─── Daemon state (persisted in state.json) ──────────────\n\nexport const supervisorDaemonStateSchema = supervisorBaseFieldsSchema.extend({\n port: z.number(),\n cwd: z.string(),\n lastHeartbeat: z.string().optional(),\n heartbeatCount: z.number().default(0),\n totalCostUsd: z.number().default(0),\n todayCostUsd: z.number().default(0),\n costResetDate: z.string().optional(),\n idleSkipCount: z.number().default(0),\n activeWorkSkipCount: z.number().default(0),\n status: z.enum([\"running\", \"draining\", \"stopped\"]).default(\"running\"),\n lastConsolidationHeartbeat: z.number().default(0),\n lastCompactionHeartbeat: z.number().default(0),\n lastConsolidationTimestamp: z.string().optional(),\n wakeReason: wakeReasonSchema.optional(),\n});\n\nexport type SupervisorDaemonState = z.infer<typeof supervisorDaemonStateSchema>;\n\n// ─── Incoming webhook event ──────────────────────────────\n\nexport const webhookIncomingEventSchema = z.object({\n id: z.string().optional(),\n source: z.string().optional(),\n event: z.string().optional(),\n payload: z.record(z.string(), z.unknown()).optional(),\n receivedAt: z.string(),\n processedAt: z.string().optional(),\n});\n\nexport type WebhookIncomingEvent = z.infer<typeof webhookIncomingEventSchema>;\n\n// ─── TUI / external inbox message ───────────────────────\n\nexport const inboxMessageSchema = z.object({\n id: z.string(),\n from: z.enum([\"tui\", \"api\", \"external\", \"agent\"]),\n text: z.string(),\n timestamp: z.string(),\n processedAt: z.string().optional(),\n});\n\nexport type InboxMessage = z.infer<typeof inboxMessageSchema>;\n\n// ─── Activity log entry ─────────────────────────────────\n\nexport const activityEntrySchema = z.object({\n id: z.string(),\n type: z.enum([\n \"heartbeat\",\n \"decision\",\n \"action\",\n \"error\",\n \"warning\",\n \"event\",\n \"message\",\n \"thinking\",\n \"plan\",\n \"dispatch\",\n \"tool_use\",\n ]),\n summary: z.string(),\n detail: z.unknown().optional(),\n timestamp: z.string(),\n});\n\nexport type ActivityEntry = z.infer<typeof activityEntrySchema>;\n\n// ─── Log buffer entry (written by neo log, read by heartbeat) ──\n\nexport const logBufferEntrySchema = z.object({\n id: z.string(),\n type: z.enum([\"progress\", \"action\", \"decision\", \"blocker\", \"milestone\", \"discovery\"]),\n message: z.string(),\n agent: z.string().optional(),\n runId: z.string().optional(),\n repo: z.string().optional(),\n target: z.enum([\"memory\", \"knowledge\", \"digest\"]),\n timestamp: z.string(),\n consolidatedAt: z.string().optional(),\n});\n\nexport type LogBufferEntry = z.infer<typeof logBufferEntrySchema>;\n\n// ─── Internal event kinds (timer-based, not external) ────\n\nexport const internalEventKindSchema = z.enum([\"consolidation_timer\", \"active_run_check\"]);\n\nexport type InternalEventKind = z.infer<typeof internalEventKindSchema>;\n\n// ─── Supervisor status (API response) ──────────────────\n\nexport const supervisorStatusSchema = supervisorBaseFieldsSchema.extend({\n status: z.enum([\"running\", \"idle\", \"stopping\"]),\n lastHeartbeat: z.string(),\n activeRunCount: z.number(),\n recentActivitySummary: z.array(z.string()),\n});\n\nexport type SupervisorStatus = z.infer<typeof supervisorStatusSchema>;\n\n// ─── Activity query options (API query params) ─────────\n\n/**\n * Filterable activity types for API queries.\n * This is a subset of activityEntrySchema.type — only types that make sense\n * for external filtering are included. Internal types like \"heartbeat\" and\n * \"thinking\" are excluded as they're implementation details.\n */\nexport const activityTypeFilterSchema = z.enum([\n \"decision\",\n \"action\",\n \"error\",\n \"event\",\n \"message\",\n \"plan\",\n \"dispatch\",\n]);\n\nexport type ActivityTypeFilter = z.infer<typeof activityTypeFilterSchema>;\n\nexport const activityQueryOptionsSchema = z.object({\n limit: z.number().int().min(1).max(500).default(50).optional(),\n offset: z.number().int().min(0).default(0).optional(),\n type: activityTypeFilterSchema.optional(),\n since: z.string().datetime().optional(),\n until: z.string().datetime().optional(),\n});\n\nexport type ActivityQueryOptions = z.infer<typeof activityQueryOptionsSchema>;\n\n// ─── Queued event (union of all event sources) ──────────\n\nexport type QueuedEvent =\n | { kind: \"webhook\"; data: WebhookIncomingEvent }\n | { kind: \"message\"; data: InboxMessage }\n | { kind: \"run_complete\"; runId: string; timestamp: string }\n | { kind: \"internal\"; eventKind: InternalEventKind; timestamp: string };\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { ensureDir } from \"@/shared/fs\";\n\n// ─── Schemas ─────────────────────────────────────────────\n\nexport const decisionOptionSchema = z.object({\n key: z.string(),\n label: z.string(),\n description: z.string().optional(),\n});\n\nexport const decisionSchema = z.object({\n id: z.string(),\n question: z.string(),\n context: z.string().optional(),\n options: z.array(decisionOptionSchema).optional(),\n type: z.string().default(\"generic\"),\n source: z.string(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.coerce.string(),\n expiresAt: z.coerce.string().optional(),\n defaultAnswer: z.string().optional(),\n answeredAt: z.coerce.string().optional(),\n answer: z.string().optional(),\n expiredAt: z.coerce.string().optional(),\n});\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type DecisionOption = z.infer<typeof decisionOptionSchema>;\nexport type Decision = z.infer<typeof decisionSchema>;\n\nexport type DecisionInput = Omit<\n Decision,\n \"id\" | \"createdAt\" | \"answeredAt\" | \"answer\" | \"expiredAt\"\n>;\n\n// ─── Store ───────────────────────────────────────────────\n\n/**\n * JSONL-backed store for decisions.\n * Append-only with in-place updates for answers and expiration.\n * Uses an in-memory mutex to serialize write operations.\n */\nexport class DecisionStore {\n private readonly filePath: string;\n private readonly dir: string;\n private readonly dirCache = new Set<string>();\n /** Promise-based mutex to serialize write operations */\n private writeLock: Promise<void> = Promise.resolve();\n\n constructor(filePath: string) {\n this.filePath = filePath;\n this.dir = path.dirname(filePath);\n }\n\n /**\n * Acquire the write lock and execute a callback.\n * Serializes all write operations to prevent race conditions.\n */\n private async withWriteLock<T>(fn: () => Promise<T>): Promise<T> {\n // Chain onto the existing lock\n const release = this.writeLock;\n let releaseLock: () => void = () => {};\n this.writeLock = new Promise((r) => {\n releaseLock = r;\n });\n\n try {\n // Wait for previous operation to complete\n await release;\n return await fn();\n } finally {\n // Release the lock for the next operation\n releaseLock();\n }\n }\n\n /**\n * Create a new decision and persist it.\n * @returns The generated decision ID\n */\n async create(input: DecisionInput): Promise<string> {\n await ensureDir(this.dir, this.dirCache);\n\n const id = `dec_${randomUUID().replace(/-/g, \"\").slice(0, 20)}`;\n const decision: Decision = {\n ...input,\n id,\n createdAt: new Date().toISOString(),\n };\n\n await appendFile(this.filePath, `${JSON.stringify(decision)}\\n`, \"utf-8\");\n return id;\n }\n\n /**\n * Answer a decision by ID.\n * Reads all entries, updates the matching one, and rewrites the file.\n * Uses a mutex to serialize concurrent calls and prevent race conditions.\n */\n async answer(id: string, answer: string): Promise<void> {\n await this.withWriteLock(async () => {\n const decisions = await this.readAll();\n const decision = decisions.find((d) => d.id === id);\n\n if (!decision) {\n throw new Error(`Decision not found: ${id}`);\n }\n\n if (decision.answer !== undefined) {\n throw new Error(`Decision already answered: ${id}`);\n }\n\n decision.answer = answer;\n decision.answeredAt = new Date().toISOString();\n\n await this.writeAll(decisions);\n });\n }\n\n /**\n * Get all pending decisions (unanswered, not expired, not timed out).\n */\n async pending(): Promise<Decision[]> {\n const decisions = await this.readAll();\n const now = new Date().toISOString();\n\n return decisions.filter((d) => {\n if (d.answer !== undefined) return false;\n if (d.expiredAt !== undefined) return false;\n if (d.expiresAt && d.expiresAt < now) return false;\n return true;\n });\n }\n\n /**\n * Get answered decisions, optionally filtered by timestamp.\n * @param since - ISO timestamp to filter decisions answered after this time\n */\n async answered(since?: string): Promise<Decision[]> {\n const decisions = await this.readAll();\n\n return decisions.filter((d) => {\n if (d.answer === undefined) return false;\n if (since && d.answeredAt && d.answeredAt < since) return false;\n return true;\n });\n }\n\n /**\n * Get a specific decision by ID.\n */\n async get(id: string): Promise<Decision | null> {\n const decisions = await this.readAll();\n return decisions.find((d) => d.id === id) ?? null;\n }\n\n /**\n * Auto-answer expired decisions with their defaultAnswer.\n * Decisions without defaultAnswer are marked as expired (expiredAt).\n * Uses a mutex to serialize concurrent calls and prevent race conditions.\n * @returns The decisions that were auto-answered or marked expired\n */\n async expire(): Promise<Decision[]> {\n return this.withWriteLock(async () => {\n const decisions = await this.readAll();\n const now = new Date().toISOString();\n const expired: Decision[] = [];\n\n for (const decision of decisions) {\n if (\n decision.answer === undefined &&\n decision.expiredAt === undefined &&\n decision.expiresAt &&\n decision.expiresAt < now\n ) {\n if (decision.defaultAnswer !== undefined) {\n decision.answer = decision.defaultAnswer;\n decision.answeredAt = now;\n } else {\n decision.expiredAt = now;\n }\n expired.push(decision);\n }\n }\n\n if (expired.length > 0) {\n await this.writeAll(decisions);\n }\n\n return expired;\n });\n }\n\n // ─── Private helpers ─────────────────────────────────────\n\n private async readAll(): Promise<Decision[]> {\n let content: string;\n try {\n content = await readFile(this.filePath, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n\n const decisions: Decision[] = [];\n for (const line of content.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const parsed = decisionSchema.parse(JSON.parse(line));\n decisions.push(parsed);\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Intentional warning for parse failures\n console.warn(\n `[DecisionStore] Skipping malformed JSONL line: ${error instanceof Error ? error.message : \"unknown error\"}`,\n );\n }\n }\n\n return decisions;\n }\n\n private async writeAll(decisions: Decision[]): Promise<void> {\n await ensureDir(this.dir, this.dirCache);\n const content = `${decisions.map((d) => JSON.stringify(d)).join(\"\\n\")}\\n`;\n await writeFile(this.filePath, content, \"utf-8\");\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, readFile, rename, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ActivityEntry } from \"./schemas.js\";\n\nconst ACTIVITY_FILE = \"activity.jsonl\";\nconst MAX_SIZE_BYTES = 10 * 1024 * 1024; // 10MB rotation threshold\n\nexport class ActivityLog {\n readonly filePath: string;\n private readonly dir: string;\n\n constructor(dir: string) {\n this.dir = dir;\n this.filePath = path.join(dir, ACTIVITY_FILE);\n }\n\n /**\n * Append a structured entry to the activity log.\n * Rotates the file if it exceeds MAX_SIZE_BYTES.\n */\n async append(entry: ActivityEntry): Promise<void> {\n await this.checkRotation();\n const line = `${JSON.stringify(entry)}\\n`;\n await appendFile(this.filePath, line, \"utf-8\");\n }\n\n /**\n * Create and append a new entry with auto-generated id and timestamp.\n */\n async log(type: ActivityEntry[\"type\"], summary: string, detail?: unknown): Promise<void> {\n await this.append({\n id: randomUUID(),\n type,\n summary,\n detail,\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * Read the last N entries from the activity log.\n */\n async tail(n: number): Promise<ActivityEntry[]> {\n let content: string;\n try {\n content = await readFile(this.filePath, \"utf-8\");\n } catch (err) {\n // Activity log file not found — no entries yet\n console.debug(\n `[ActivityLog] Failed to read activity log: ${err instanceof Error ? err.message : String(err)}`,\n );\n return [];\n }\n\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const lastLines = lines.slice(-n);\n\n const entries: ActivityEntry[] = [];\n for (const line of lastLines) {\n try {\n entries.push(JSON.parse(line) as ActivityEntry);\n } catch (err) {\n // Skip malformed JSONL line\n console.debug(\n `[ActivityLog] Skipping malformed line: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n return entries;\n }\n\n private async checkRotation(): Promise<void> {\n try {\n const stats = await stat(this.filePath);\n if (stats.size > MAX_SIZE_BYTES) {\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const rotatedPath = path.join(this.dir, `activity-${timestamp}.jsonl`);\n await rename(this.filePath, rotatedPath);\n }\n } catch {\n // File doesn't exist yet — no rotation needed\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type { GlobalConfig } from \"@/config\";\nimport { getSupervisorDecisionsPath, getSupervisorDir } from \"@/paths\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport { ActivityLog } from \"./activity-log.js\";\nimport { DecisionStore } from \"./decisions.js\";\nimport { EventQueue } from \"./event-queue.js\";\nimport { HeartbeatLoop } from \"./heartbeat.js\";\nimport type { SupervisorDaemonState, WebhookIncomingEvent } from \"./schemas.js\";\nimport { WebhookServer } from \"./webhook-server.js\";\n\nexport interface SupervisorDaemonOptions {\n name: string;\n config: GlobalConfig;\n /** Path to bundled default SUPERVISOR.md (e.g. from @neotx/agents) */\n defaultInstructionsPath?: string | undefined;\n}\n\n/**\n * Orchestrates all supervisor components: webhook server, event queue,\n * heartbeat loop, memory, and activity logging.\n */\nexport class SupervisorDaemon {\n private readonly name: string;\n private readonly config: GlobalConfig;\n private readonly dir: string;\n private readonly defaultInstructionsPath: string | undefined;\n private webhookServer: WebhookServer | null = null;\n private eventQueue: EventQueue | null = null;\n private heartbeatLoop: HeartbeatLoop | null = null;\n private activityLog: ActivityLog | null = null;\n private decisionStore: DecisionStore | null = null;\n private sessionId = \"\";\n\n constructor(options: SupervisorDaemonOptions) {\n this.name = options.name;\n this.config = options.config;\n this.dir = getSupervisorDir(options.name);\n this.defaultInstructionsPath = options.defaultInstructionsPath;\n }\n\n async start(): Promise<void> {\n // Create supervisor directory\n await mkdir(this.dir, { recursive: true });\n\n // Check lockfile for duplicate daemons\n const lockPath = path.join(this.dir, \"daemon.lock\");\n if (existsSync(lockPath)) {\n const lockPid = await this.readLockPid(lockPath);\n if (lockPid && isProcessAlive(lockPid)) {\n throw new Error(\n `Supervisor \"${this.name}\" already running (PID ${lockPid}). Use --kill first.`,\n );\n }\n // Stale lock — clean up\n await rm(lockPath, { force: true });\n }\n\n // Write lockfile atomically\n const tempLock = `${lockPath}.${process.pid}`;\n await writeFile(tempLock, String(process.pid), \"utf-8\");\n const { rename } = await import(\"node:fs/promises\");\n await rename(tempLock, lockPath);\n\n // Recover session ID from previous state or generate new one\n const existingState = await this.readState();\n if (existingState?.sessionId && existingState.status !== \"stopped\") {\n this.sessionId = existingState.sessionId;\n } else {\n this.sessionId = randomUUID();\n }\n\n // Initialize activity log\n this.activityLog = new ActivityLog(this.dir);\n\n // Initialize decision store\n this.decisionStore = new DecisionStore(getSupervisorDecisionsPath(this.name));\n\n // Initialize event queue\n this.eventQueue = new EventQueue({\n maxEventsPerSec: this.config.supervisor.maxEventsPerSec,\n });\n\n // Replay unprocessed events from disk\n const inboxPath = path.join(this.dir, \"inbox.jsonl\");\n const eventsPath = path.join(this.dir, \"events.jsonl\");\n await this.eventQueue.replayUnprocessed(inboxPath, eventsPath);\n\n // Start file watching\n await this.eventQueue.startWatching(inboxPath, eventsPath);\n\n // Start webhook server\n this.webhookServer = new WebhookServer({\n port: this.config.supervisor.port,\n secret: this.config.supervisor.secret,\n eventsPath,\n onEvent: (event) => {\n this.eventQueue?.push({ kind: \"webhook\", data: event });\n\n // Handle decision:answer webhook events\n this.handleDecisionAnswer(event).catch((err) => {\n this.activityLog?.log(\n \"error\",\n `Failed to handle decision:answer: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n\n // Convert session:complete/session:fail webhooks into run_complete events\n // so the heartbeat gets a structured signal that a run finished\n if (\n (event.event === \"session:complete\" || event.event === \"session:fail\") &&\n event.payload\n ) {\n const runId = typeof event.payload.runId === \"string\" ? event.payload.runId : undefined;\n if (runId) {\n this.eventQueue?.push({\n kind: \"run_complete\",\n runId,\n timestamp: event.receivedAt,\n });\n }\n }\n },\n getHealth: () => this.getHealthInfo(),\n });\n await this.webhookServer.start();\n\n // Write initial state\n await this.writeState({\n pid: process.pid,\n sessionId: this.sessionId,\n port: this.config.supervisor.port,\n cwd: homedir(),\n startedAt: new Date().toISOString(),\n lastHeartbeat: existingState?.lastHeartbeat,\n heartbeatCount: existingState?.heartbeatCount ?? 0,\n totalCostUsd: existingState?.totalCostUsd ?? 0,\n todayCostUsd: existingState?.todayCostUsd ?? 0,\n costResetDate: existingState?.costResetDate,\n idleSkipCount: existingState?.idleSkipCount ?? 0,\n activeWorkSkipCount: existingState?.activeWorkSkipCount ?? 0,\n status: \"running\",\n lastConsolidationHeartbeat: existingState?.lastConsolidationHeartbeat ?? 0,\n lastCompactionHeartbeat: existingState?.lastCompactionHeartbeat ?? 0,\n lastConsolidationTimestamp: existingState?.lastConsolidationTimestamp,\n });\n\n // Install signal handlers\n const shutdown = () => {\n // biome-ignore lint/suspicious/noConsole: Intentional daemon logging for signal handler errors\n this.stop().catch(console.error);\n };\n process.on(\"SIGTERM\", shutdown);\n process.on(\"SIGINT\", shutdown);\n\n await this.activityLog.log(\n \"event\",\n `Supervisor \"${this.name}\" started on port ${this.config.supervisor.port}`,\n );\n\n // Start heartbeat loop (blocks until stopped)\n const statePath = path.join(this.dir, \"state.json\");\n this.heartbeatLoop = new HeartbeatLoop({\n config: this.config,\n supervisorDir: this.dir,\n statePath,\n sessionId: this.sessionId,\n eventQueue: this.eventQueue,\n activityLog: this.activityLog,\n eventsPath,\n defaultInstructionsPath: this.defaultInstructionsPath,\n });\n\n await this.heartbeatLoop.start();\n }\n\n async stop(): Promise<void> {\n this.heartbeatLoop?.stop();\n this.eventQueue?.stopWatching();\n\n if (this.webhookServer) {\n await this.webhookServer.stop();\n }\n\n // Update state\n const state = await this.readState();\n if (state) {\n state.status = \"stopped\";\n await this.writeState(state);\n }\n\n // Remove lockfile\n const lockPath = path.join(this.dir, \"daemon.lock\");\n await rm(lockPath, { force: true });\n\n if (this.activityLog) {\n await this.activityLog.log(\"event\", `Supervisor \"${this.name}\" stopped`);\n }\n }\n\n private getHealthInfo(): Record<string, unknown> {\n return {\n status: \"ok\",\n name: this.name,\n pid: process.pid,\n uptime: process.uptime(),\n sessionId: this.sessionId,\n port: this.config.supervisor.port,\n };\n }\n\n private async readState(): Promise<SupervisorDaemonState | null> {\n const statePath = path.join(this.dir, \"state.json\");\n try {\n const raw = await readFile(statePath, \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch (err) {\n // State file not found or corrupted — treat as no previous state\n console.debug(\n `[SupervisorDaemon] Failed to read state: ${err instanceof Error ? err.message : String(err)}`,\n );\n return null;\n }\n }\n\n private async writeState(state: SupervisorDaemonState): Promise<void> {\n const statePath = path.join(this.dir, \"state.json\");\n await writeFile(statePath, JSON.stringify(state, null, 2), \"utf-8\");\n }\n\n private async readLockPid(lockPath: string): Promise<number | null> {\n try {\n const raw = await readFile(lockPath, \"utf-8\");\n const pid = Number.parseInt(raw.trim(), 10);\n return Number.isNaN(pid) ? null : pid;\n } catch (err) {\n // Lock file not found or unreadable — no lock exists\n console.debug(\n `[SupervisorDaemon] Failed to read lock PID from ${lockPath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return null;\n }\n }\n\n /**\n * Handle decision:answer webhook events.\n * Extracts decisionId and answer from the payload and records the answer.\n */\n private async handleDecisionAnswer(event: WebhookIncomingEvent): Promise<void> {\n if (event.event !== \"decision:answer\") return;\n if (!this.decisionStore || !event.payload) return;\n\n const decisionId =\n typeof event.payload.decisionId === \"string\" ? event.payload.decisionId : undefined;\n const answer = typeof event.payload.answer === \"string\" ? event.payload.answer : undefined;\n\n if (!decisionId || !answer) {\n await this.activityLog?.log(\n \"error\",\n `decision:answer webhook missing required fields (decisionId: ${decisionId}, answer: ${answer})`,\n );\n return;\n }\n\n try {\n await this.decisionStore.answer(decisionId, answer);\n await this.activityLog?.log(\n \"decision\",\n `Decision ${decisionId} answered via webhook: \"${answer}\"`,\n );\n } catch (err) {\n await this.activityLog?.log(\n \"error\",\n `Failed to answer decision ${decisionId}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","import { type FSWatcher, watch } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport type { InboxMessage, QueuedEvent, WebhookIncomingEvent } from \"./schemas.js\";\n\ninterface EventQueueOptions {\n maxEventsPerSec: number;\n}\n\nexport interface GroupedMessage {\n text: string;\n from: string;\n count: number;\n}\n\nexport interface GroupedEvents {\n messages: GroupedMessage[];\n webhooks: QueuedEvent[];\n runCompletions: QueuedEvent[];\n}\n\nexport interface DrainAndGroupResult {\n grouped: GroupedEvents;\n rawEvents: QueuedEvent[];\n}\n\n/**\n * In-memory event queue with deduplication, rate limiting, and file watching.\n *\n * Accumulates events from 3 sources:\n * - Webhooks (pushed directly by WebhookServer)\n * - Inbox messages (watched from inbox.jsonl)\n * - Run completions (watched from runs directory)\n *\n * The daemon drains this queue at each heartbeat.\n */\nexport class EventQueue {\n private readonly queue: QueuedEvent[] = [];\n private readonly seenIds = new Set<string>();\n private readonly maxSeenIds = 1000;\n private readonly maxEventsPerSec: number;\n private eventCountThisSecond = 0;\n private currentSecond = 0;\n private watchers: FSWatcher[] = [];\n private fileOffsets = new Map<string, number>();\n\n /** Resolve function to wake up the heartbeat loop when an event arrives */\n private wakeUp: (() => void) | null = null;\n\n constructor(options: EventQueueOptions) {\n this.maxEventsPerSec = options.maxEventsPerSec;\n }\n\n /**\n * Push an event into the queue. Applies dedup and rate limiting.\n */\n push(event: QueuedEvent): boolean {\n // Deduplication by event ID\n const id = this.getEventId(event);\n if (id && this.seenIds.has(id)) return false;\n\n // Rate limiting\n const now = Math.floor(Date.now() / 1000);\n if (now !== this.currentSecond) {\n this.currentSecond = now;\n this.eventCountThisSecond = 0;\n }\n if (this.eventCountThisSecond >= this.maxEventsPerSec) return false;\n this.eventCountThisSecond++;\n\n // Track seen IDs (LRU-style: evict oldest when full)\n if (id) {\n this.seenIds.add(id);\n if (this.seenIds.size > this.maxSeenIds) {\n const first = this.seenIds.values().next().value;\n if (first) this.seenIds.delete(first);\n }\n }\n\n this.queue.push(event);\n this.wakeUp?.();\n return true;\n }\n\n /**\n * Drain all queued events and return them. Clears the queue.\n */\n drain(): QueuedEvent[] {\n const events = [...this.queue];\n this.queue.length = 0;\n return events;\n }\n\n /**\n * Drain and group events: deduplicates messages by content,\n * keeps webhooks and run completions separate.\n * Returns both grouped events AND original raw events for later marking as processed.\n */\n drainAndGroup(): DrainAndGroupResult {\n const rawEvents = this.drain();\n\n const messageMap = new Map<string, GroupedMessage>();\n const webhooks: QueuedEvent[] = [];\n const runCompletions: QueuedEvent[] = [];\n\n for (const event of rawEvents) {\n if (event.kind === \"message\") {\n const key = event.data.text.trim().toLowerCase();\n const existing = messageMap.get(key);\n if (existing) {\n existing.count++;\n } else {\n messageMap.set(key, { text: event.data.text, from: event.data.from, count: 1 });\n }\n } else if (event.kind === \"webhook\") {\n webhooks.push(event);\n } else {\n runCompletions.push(event);\n }\n }\n\n return {\n grouped: {\n messages: [...messageMap.values()],\n webhooks,\n runCompletions,\n },\n rawEvents,\n };\n }\n\n size(): number {\n return this.queue.length;\n }\n\n /**\n * Start watching inbox.jsonl and events.jsonl for new entries.\n * New lines are parsed and pushed into the queue.\n */\n async startWatching(inboxPath: string, eventsPath: string): Promise<void> {\n // Ensure files exist before watching — fs.watch() throws on missing files\n for (const p of [inboxPath, eventsPath]) {\n try {\n await writeFile(p, \"\", { flag: \"a\" });\n } catch {\n // Non-critical: file creation may fail due to permissions or missing parent directory.\n // watchJsonlFile will handle this gracefully by skipping the watch.\n }\n }\n this.watchJsonlFile(inboxPath, \"message\");\n this.watchJsonlFile(eventsPath, \"webhook\");\n }\n\n stopWatching(): void {\n for (const w of this.watchers) w.close();\n this.watchers = [];\n this.fileOffsets.clear();\n }\n\n /**\n * Replay unprocessed events from disk on startup.\n */\n async replayUnprocessed(inboxPath: string, eventsPath: string): Promise<void> {\n await this.replayFile(inboxPath, \"message\");\n await this.replayFile(eventsPath, \"webhook\");\n }\n\n /**\n * Returns a promise that resolves when a new event arrives or timeout is reached.\n */\n waitForEvent(timeoutMs: number): Promise<void> {\n if (this.queue.length > 0) return Promise.resolve();\n return new Promise<void>((resolve) => {\n const timer = setTimeout(() => {\n this.wakeUp = null;\n resolve();\n }, timeoutMs);\n\n this.wakeUp = () => {\n clearTimeout(timer);\n this.wakeUp = null;\n resolve();\n };\n });\n }\n\n /**\n * Interrupt any pending waitForEvent — used during shutdown.\n */\n interrupt(): void {\n this.wakeUp?.();\n }\n\n private getEventId(event: QueuedEvent): string | undefined {\n if (event.kind === \"webhook\") return event.data.id;\n if (event.kind === \"message\") return event.data.id;\n if (event.kind === \"run_complete\") return `run:${event.runId}`;\n return undefined;\n }\n\n private watchJsonlFile(filePath: string, kind: \"message\" | \"webhook\"): void {\n try {\n const watcher = watch(filePath, () => {\n // Non-critical: file may have been deleted or become unreadable between watch trigger and read\n this.readNewLines(filePath, kind).catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Log file watch read failures for debugging\n console.debug(`[neo] Failed to read new lines from ${filePath}:`, err);\n });\n });\n this.watchers.push(watcher);\n } catch {\n // Non-critical: file may not exist yet — watcher will be set up when file is created\n }\n }\n\n private async readNewLines(filePath: string, kind: \"message\" | \"webhook\"): Promise<void> {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (_err) {\n // Non-critical: file may not exist or be temporarily unavailable during rotation\n // Silently return — the watcher will retry on next change event\n return;\n }\n\n const offset = this.fileOffsets.get(filePath) ?? 0;\n if (content.length <= offset) return;\n\n const newContent = content.slice(offset);\n this.fileOffsets.set(filePath, content.length);\n\n const lines = newContent.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (parsed.processedAt) continue; // Already processed\n\n if (kind === \"webhook\") {\n this.push({ kind: \"webhook\", data: parsed as unknown as WebhookIncomingEvent });\n } else {\n this.push({ kind: \"message\", data: parsed as unknown as InboxMessage });\n }\n } catch (_err) {\n // Non-critical: skip malformed JSON lines (may be partial writes or corrupted entries)\n }\n }\n }\n\n private async replayFile(filePath: string, kind: \"message\" | \"webhook\"): Promise<void> {\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (_err) {\n // Non-critical on replay: file may not exist yet on first startup\n // Events will be captured when file is created and watcher triggers\n return;\n }\n\n // Set offset so watcher doesn't re-read\n this.fileOffsets.set(filePath, content.length);\n\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const unprocessed: string[] = [];\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (parsed.processedAt) continue;\n\n if (kind === \"webhook\") {\n this.push({ kind: \"webhook\", data: parsed as unknown as WebhookIncomingEvent });\n } else {\n this.push({ kind: \"message\", data: parsed as unknown as InboxMessage });\n }\n unprocessed.push(line);\n } catch (_err) {\n // Non-critical: skip malformed JSON lines during replay (may be partial writes)\n }\n }\n }\n\n /**\n * Mark events as processed by rewriting the source files.\n */\n async markProcessed(inboxPath: string, eventsPath: string, events: QueuedEvent[]): Promise<void> {\n const now = new Date().toISOString();\n\n for (const event of events) {\n if (event.kind === \"webhook\") {\n await this.markInFile(eventsPath, event.data.receivedAt, now);\n } else if (event.kind === \"message\") {\n await this.markInFile(inboxPath, event.data.timestamp, now);\n }\n }\n }\n\n private async markInFile(\n filePath: string,\n matchTimestamp: string,\n processedAt: string,\n ): Promise<void> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n let changed = false;\n\n const updated = lines.map((line) => {\n if (!line.trim()) return line;\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (\n (parsed.receivedAt === matchTimestamp || parsed.timestamp === matchTimestamp) &&\n !parsed.processedAt\n ) {\n parsed.processedAt = processedAt;\n changed = true;\n return JSON.stringify(parsed);\n }\n } catch (_err) {\n // Non-critical: keep malformed lines as-is (manual edits or corruption)\n }\n return line;\n });\n\n if (changed) {\n await writeFile(filePath, updated.join(\"\\n\"), \"utf-8\");\n this.fileOffsets.set(filePath, updated.join(\"\\n\").length);\n }\n } catch {\n // Non-critical: marking as processed may fail but events are already handled.\n // Worst case: duplicate processing on restart (idempotent operations).\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport { ConfigStore, ConfigWatcher, type GlobalConfig } from \"@/config\";\nimport { getDataDir, getRunsDir } from \"@/paths\";\nimport {\n isAssistantMessage,\n isInitMessage,\n isResultMessage,\n isToolResultMessage,\n isToolUseMessage,\n type SDKStreamMessage,\n} from \"@/sdk-types\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport type { PersistedRun } from \"@/types\";\nimport type { ActivityLog } from \"./activity-log.js\";\nimport { type Decision, DecisionStore } from \"./decisions.js\";\nimport type { EventQueue, GroupedEvents } from \"./event-queue.js\";\nimport { type IdleContext, IdleDetector } from \"./idle-detector.js\";\nimport { compactLogBuffer, markConsolidated, readUnconsolidated } from \"./log-buffer.js\";\nimport type { MemoryEntry } from \"./memory/entry.js\";\nimport { MemoryStore } from \"./memory/store.js\";\nimport {\n buildCompactionPrompt,\n buildConsolidationPrompt,\n buildIdlePrompt,\n buildStandardPrompt,\n isIdleHeartbeat,\n} from \"./prompt-builder.js\";\nimport type {\n ActivityEntry,\n LogBufferEntry,\n QueuedEvent,\n SupervisorDaemonState,\n} from \"./schemas.js\";\nimport {\n type HeartbeatEvent,\n heartbeatEventSchema,\n type RunCompletedEvent,\n type RunDispatchedEvent,\n runCompletedEventSchema,\n runDispatchedEventSchema,\n type SupervisorStartedEvent,\n type SupervisorStoppedEvent,\n type SupervisorWebhookEvent,\n supervisorStartedEventSchema,\n supervisorStoppedEventSchema,\n} from \"./webhookEvents.js\";\n\n/** Consolidation runs every N heartbeats */\nconst DEFAULT_CONSOLIDATION_INTERVAL = 5;\n\n// ─── Consolidation logic ────────────────────────────────\n\n/**\n * Determine whether this heartbeat should be a consolidation cycle.\n * Consolidation runs every `consolidationInterval` heartbeats,\n * or earlier if there are pending unconsolidated entries (after at least 2 heartbeats).\n */\nexport function shouldConsolidate(\n heartbeatCount: number,\n lastConsolidationHeartbeat: number,\n consolidationInterval: number,\n hasPendingEntries: boolean,\n): boolean {\n const since = heartbeatCount - lastConsolidationHeartbeat;\n if (since >= consolidationInterval) return true;\n if (hasPendingEntries && since >= 2) return true;\n return false;\n}\n\n/**\n * Determine whether this heartbeat should run compaction.\n * Compaction is a deep cleanup pass that runs every ~50 heartbeats.\n */\nexport function shouldCompact(\n heartbeatCount: number,\n lastCompactionHeartbeat: number,\n compactionInterval = 50,\n): boolean {\n const since = heartbeatCount - lastCompactionHeartbeat;\n return since >= compactionInterval;\n}\n\n/** Grace period before a run without PID can be considered stale (ms). */\nexport const STALE_GRACE_PERIOD_MS = 30_000;\n\n/**\n * Determine if a persisted run is actually active (not stale).\n *\n * For \"running\" status, validates:\n * - If PID exists and process is alive → active\n * - If PID exists but process is dead → stale (ghost run)\n * - If no PID and within grace period → active (still starting up)\n * - If no PID and past grace period → stale (ghost run)\n *\n * For \"paused\" status: always considered active (waiting for user action).\n */\nexport function isRunActive(\n run: PersistedRun,\n isAlive: (pid: number) => boolean = isProcessAlive,\n now: number = Date.now(),\n): boolean {\n // Skip non-active statuses\n if (run.status !== \"running\" && run.status !== \"paused\") {\n return false;\n }\n\n // Paused runs are always considered active (waiting for user action)\n if (run.status === \"paused\") {\n return true;\n }\n\n // For running status, validate the run is actually alive\n // If PID exists and process is alive, it's active\n if (run.pid && isAlive(run.pid)) {\n return true;\n }\n\n // If PID exists but process is dead, it's a stale ghost run\n if (run.pid) {\n return false;\n }\n\n // No PID: check grace period (run may still be starting up)\n const ageMs = now - new Date(run.createdAt).getTime();\n\n return ageMs < STALE_GRACE_PERIOD_MS;\n}\n\n// ─── Helper types for runHeartbeat refactoring ───────────\n\ninterface BudgetCheckResult {\n todayCost: number;\n exceeded: boolean;\n}\n\ninterface ProcessDecisionsResult {\n pendingDecisions: Decision[];\n answeredDecisions: Decision[];\n hasExpiredDecisions: boolean;\n /** Always reflects reality — used for idle-check even in non-autoDecide mode */\n hasPendingDecisions: boolean;\n}\n\ninterface EventContext {\n grouped: GroupedEvents;\n rawEvents: QueuedEvent[];\n totalEventCount: number;\n activeRuns: string[];\n memories: MemoryEntry[];\n recentActions: ActivityEntry[];\n mcpServerNames: string[];\n}\n\ninterface PostSdkProcessingInput {\n rawEvents: QueuedEvent[];\n isConsolidation: boolean;\n unconsolidated: LogBufferEntry[];\n}\n\ninterface CompletionEventsInput {\n heartbeatCount: number;\n activeRuns: string[];\n todayCost: number;\n costUsd: number;\n rawEvents: QueuedEvent[];\n}\n\ninterface SkipLogicInput {\n state: SupervisorDaemonState | null;\n totalEventCount: number;\n activeRuns: string[];\n hasPendingConsolidation: boolean;\n hasExpiredDecisions: boolean;\n}\n\ninterface SkipLogicResult {\n shouldSkip: boolean;\n resetCounters: boolean;\n}\n\ninterface HeartbeatModeResult {\n isConsolidation: boolean;\n isCompaction: boolean;\n unconsolidated: LogBufferEntry[];\n heartbeatCount: number;\n lastConsolidationTs: string | undefined;\n}\n\ninterface StateUpdateResult {\n stateUpdate: Partial<SupervisorDaemonState>;\n}\n\n// ─── HeartbeatLoop ───────────────────────────────────────\n\n/** Callback for emitting webhook events */\nexport type WebhookEventEmitter = (event: SupervisorWebhookEvent) => void | Promise<void>;\n\nexport interface HeartbeatLoopOptions {\n config: GlobalConfig;\n supervisorDir: string;\n statePath: string;\n sessionId: string;\n eventQueue: EventQueue;\n activityLog: ActivityLog;\n /** Path to the inbox/events directory for markProcessed() calls */\n eventsPath: string;\n /** Path to bundled default SUPERVISOR.md (e.g. from @neotx/agents) */\n defaultInstructionsPath?: string | undefined;\n memoryDbPath?: string | undefined;\n /** Optional callback to emit webhook events at lifecycle points */\n onWebhookEvent?: WebhookEventEmitter | undefined;\n /** Repository path for config watching (enables hot-reload) */\n repoPath?: string | undefined;\n /** Debounce time in ms for config file changes (default: 500) */\n configWatcherDebounceMs?: number | undefined;\n}\n\n/**\n * The core autonomous loop. At each iteration:\n * 1. Drain events from the queue\n * 2. Read log buffer entries\n * 3. Determine standard vs consolidation mode\n * 4. Build the appropriate prompt\n * 5. Call sdk.query() for Claude to reason and act\n * 6. Mark entries consolidated and compact log buffer (consolidation only)\n * 7. Log activity\n * 8. Wait for the next event or idle timeout\n */\nexport class HeartbeatLoop {\n private stopping = false;\n private consecutiveFailures = 0;\n private activeAbort: AbortController | null = null;\n private config: GlobalConfig;\n private readonly supervisorDir: string;\n private readonly statePath: string;\n private sessionId: string;\n private readonly eventQueue: EventQueue;\n private readonly activityLog: ActivityLog;\n private readonly _eventsPath: string;\n\n private customInstructions: string | undefined;\n private readonly defaultInstructionsPath: string | undefined;\n private memoryStore: MemoryStore | null = null;\n private readonly memoryDbPath: string | undefined;\n private readonly onWebhookEvent: WebhookEventEmitter | undefined;\n private decisionStore: DecisionStore | null = null;\n\n /** ConfigWatcher for hot-reload support */\n private configWatcher: ConfigWatcher | null = null;\n private configStore: ConfigStore | null = null;\n private readonly repoPath: string | undefined;\n private readonly configWatcherDebounceMs: number | undefined;\n\n constructor(options: HeartbeatLoopOptions) {\n this.config = options.config;\n this.supervisorDir = options.supervisorDir;\n this.statePath = options.statePath;\n this.sessionId = options.sessionId;\n this.eventQueue = options.eventQueue;\n this.activityLog = options.activityLog;\n this._eventsPath = options.eventsPath;\n this.defaultInstructionsPath = options.defaultInstructionsPath;\n this.memoryDbPath = options.memoryDbPath;\n this.onWebhookEvent = options.onWebhookEvent;\n this.repoPath = options.repoPath;\n this.configWatcherDebounceMs = options.configWatcherDebounceMs;\n }\n\n /** Path to the inbox/events directory for markProcessed() calls */\n get eventsPath(): string {\n return this._eventsPath;\n }\n\n private getMemoryStore(): MemoryStore | null {\n if (!this.memoryStore && this.memoryDbPath) {\n try {\n this.memoryStore = new MemoryStore(this.memoryDbPath);\n } catch {\n // Memory store unavailable — continue without it\n }\n }\n return this.memoryStore;\n }\n\n private getDecisionStore(): DecisionStore {\n if (!this.decisionStore) {\n this.decisionStore = new DecisionStore(path.join(this.supervisorDir, \"decisions.jsonl\"));\n }\n return this.decisionStore;\n }\n\n async start(): Promise<void> {\n this.customInstructions = await this.loadInstructions();\n\n // Initialize and start config watcher for hot-reload\n await this.initConfigWatcher();\n\n await this.activityLog.log(\"heartbeat\", \"Supervisor heartbeat loop started\");\n await this.emitSupervisorStarted();\n\n while (!this.stopping) {\n try {\n await this.runHeartbeat();\n this.consecutiveFailures = 0;\n } catch (error) {\n this.consecutiveFailures++;\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Heartbeat failed: ${msg}`, { error: msg });\n\n // Circuit breaker: exponential backoff after consecutive failures\n if (this.consecutiveFailures >= this.config.supervisor.maxConsecutiveFailures) {\n const backoffMs = Math.min(\n this.config.supervisor.eventTimeoutMs *\n 2 ** (this.consecutiveFailures - this.config.supervisor.maxConsecutiveFailures),\n 15 * 60 * 1000, // max 15 minutes\n );\n await this.activityLog.log(\n \"error\",\n `Circuit breaker: backing off ${Math.round(backoffMs / 1000)}s after ${this.consecutiveFailures} failures`,\n );\n await this.sleep(backoffMs);\n continue;\n }\n }\n\n if (this.stopping) break;\n\n // Wait for next event or idle timeout\n await this.eventQueue.waitForEvent(this.config.supervisor.eventTimeoutMs);\n }\n\n await this.emitSupervisorStopped(\"shutdown\");\n await this.activityLog.log(\"heartbeat\", \"Supervisor heartbeat loop stopped\");\n }\n\n stop(): void {\n this.stopping = true;\n this.activeAbort?.abort(new Error(\"Supervisor shutting down\"));\n this.eventQueue.interrupt();\n\n // Stop config watcher\n if (this.configWatcher) {\n this.configWatcher.stop();\n this.configWatcher = null;\n }\n }\n\n /**\n * Initialize and start the ConfigWatcher for hot-reload support.\n * Subscribes to config file changes and logs reload events.\n */\n private async initConfigWatcher(): Promise<void> {\n // Create a ConfigStore for the watcher\n this.configStore = new ConfigStore(this.repoPath);\n await this.configStore.load();\n\n // Build options only with defined values to satisfy exactOptionalPropertyTypes\n const watcherOptions =\n this.configWatcherDebounceMs !== undefined\n ? { debounceMs: this.configWatcherDebounceMs }\n : undefined;\n\n this.configWatcher = new ConfigWatcher(this.configStore, watcherOptions);\n\n // Subscribe to config changes\n this.configWatcher.on(\"change\", () => {\n this.handleConfigChange();\n });\n\n this.configWatcher.start();\n await this.activityLog.log(\"event\", \"ConfigWatcher started for hot-reload\");\n }\n\n /**\n * Handle config file changes. Propagates reloaded config to the running\n * loop and triggers an immediate heartbeat.\n */\n private handleConfigChange(): void {\n // Propagate reloaded config to the running loop\n if (this.configStore) {\n this.config = this.configStore.getAll();\n }\n\n // Log the config change\n this.activityLog.log(\"event\", \"Configuration reloaded (hot-reload)\").catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Debug logging for config reload errors\n console.debug(\"[neo] Config reload log failed:\", err);\n });\n\n // Interrupt the event queue wait to trigger an immediate heartbeat\n // This ensures the supervisor reacts quickly to config changes\n this.eventQueue.interrupt();\n }\n\n private async runHeartbeat(): Promise<void> {\n const startTime = Date.now();\n const heartbeatId = randomUUID();\n const state = await this.readState();\n const today = new Date().toISOString().slice(0, 10);\n\n // Check budget and return early if exceeded\n const budgetCheck = await this.checkBudgetExceeded(state, today);\n if (budgetCheck.exceeded) return;\n\n // Gather event context\n const eventCtx = await this.gatherEventContext();\n\n // Process decision answers and expiry\n const { pendingDecisions, answeredDecisions, hasExpiredDecisions, hasPendingDecisions } =\n await this.processDecisions(eventCtx.rawEvents, state?.lastHeartbeat);\n\n // Check for pending consolidation entries\n const unconsolidatedEntries = await readUnconsolidated(this.supervisorDir);\n const hasPendingConsolidation = unconsolidatedEntries.length > 0;\n\n // Handle skip logic for idle/active-work scenarios\n const skipResult = await this.handleSkipLogic({\n state,\n totalEventCount: eventCtx.totalEventCount,\n activeRuns: eventCtx.activeRuns,\n hasPendingConsolidation,\n hasExpiredDecisions,\n });\n if (skipResult.shouldSkip) return;\n if (skipResult.resetCounters) {\n await this.updateState({ idleSkipCount: 0, activeWorkSkipCount: 0 });\n }\n\n // Determine heartbeat mode\n const modeResult = await this.determineHeartbeatMode(state);\n\n // Build prompt and log start\n const { prompt, modeLabel } = await this.buildHeartbeatModePrompt({\n grouped: eventCtx.grouped,\n todayCost: budgetCheck.todayCost,\n heartbeatCount: modeResult.heartbeatCount,\n unconsolidated: modeResult.unconsolidated,\n isCompaction: modeResult.isCompaction,\n isConsolidation: modeResult.isConsolidation,\n activeRuns: eventCtx.activeRuns,\n pendingDecisions,\n answeredDecisions,\n hasPendingDecisions,\n lastHeartbeat: state?.lastHeartbeat,\n lastConsolidationTimestamp: modeResult.lastConsolidationTs,\n memories: eventCtx.memories,\n recentActions: eventCtx.recentActions,\n mcpServerNames: eventCtx.mcpServerNames,\n });\n await this.activityLog.log(\n \"heartbeat\",\n `Heartbeat #${modeResult.heartbeatCount} starting (${modeLabel})`,\n {\n heartbeatId,\n eventCount: eventCtx.totalEventCount,\n messages: eventCtx.grouped.messages.length,\n webhooks: eventCtx.grouped.webhooks.length,\n runCompletions: eventCtx.grouped.runCompletions.length,\n isConsolidation: modeResult.isConsolidation,\n },\n );\n\n // Call SDK with timeout + shutdown abort\n const { costUsd, turnCount } = await this.callSdk(prompt, heartbeatId);\n\n // Warn if SDK stream completed without any turns — indicates silent timeout\n if (turnCount === 0) {\n await this.activityLog.log(\n \"warning\",\n `Heartbeat #${modeResult.heartbeatCount} completed with turnCount=0. SDK stream may have timed out before any turns completed.`,\n { heartbeatId },\n );\n }\n\n // Handle post-SDK processing\n await this.handlePostSdkProcessing({\n rawEvents: eventCtx.rawEvents,\n isConsolidation: modeResult.isConsolidation,\n unconsolidated: modeResult.unconsolidated,\n });\n\n // Build and apply state update\n const durationMs = Date.now() - startTime;\n const { stateUpdate } = this.buildStateUpdate({\n state,\n today,\n todayCost: budgetCheck.todayCost,\n costUsd,\n heartbeatCount: modeResult.heartbeatCount,\n isConsolidation: modeResult.isConsolidation,\n isCompaction: modeResult.isCompaction,\n });\n await this.updateState(stateUpdate);\n\n await this.activityLog.log(\n \"heartbeat\",\n `Heartbeat #${modeResult.heartbeatCount + 1} complete (${modeLabel})`,\n {\n heartbeatId,\n costUsd,\n durationMs,\n turnCount,\n isConsolidation: modeResult.isConsolidation,\n },\n );\n\n // Emit completion webhook events\n await this.emitCompletionEvents({\n heartbeatCount: modeResult.heartbeatCount,\n activeRuns: eventCtx.activeRuns,\n todayCost: budgetCheck.todayCost,\n costUsd,\n rawEvents: eventCtx.rawEvents,\n });\n }\n\n /**\n * Check if supervisor daily budget is exceeded.\n */\n private async checkBudgetExceeded(\n state: SupervisorDaemonState | null,\n today: string,\n ): Promise<BudgetCheckResult> {\n const todayCost = state?.costResetDate === today ? (state.todayCostUsd ?? 0) : 0;\n\n if (todayCost >= this.config.supervisor.dailyCapUsd) {\n await this.activityLog.log(\n \"error\",\n `Supervisor daily budget exceeded ($${todayCost.toFixed(2)} / $${this.config.supervisor.dailyCapUsd}). Skipping heartbeat.`,\n );\n await this.sleep(this.config.supervisor.eventTimeoutMs);\n return { todayCost, exceeded: true };\n }\n\n return { todayCost, exceeded: false };\n }\n\n /**\n * Process decision answers from inbox and expire old decisions.\n * Returns pending, answered, and expiry status for prompt context.\n */\n private async processDecisions(\n rawEvents: QueuedEvent[],\n lastHeartbeat: string | undefined,\n ): Promise<ProcessDecisionsResult> {\n const decisionStore = this.getDecisionStore();\n\n // Process decision answers from inbox messages\n await this.processDecisionAnswers(rawEvents, decisionStore);\n\n // Auto-answer expired decisions\n const expiredDecisions = await decisionStore.expire();\n const hasExpiredDecisions = expiredDecisions.length > 0;\n\n // Always fetch pending count for idle-check (determines whether to dispatch scout).\n // Only pass the full list to the prompt in autoDecide mode (supervisor answers them).\n const allPending = await decisionStore.pending();\n const hasPendingDecisions = allPending.length > 0;\n const pendingDecisions = this.config.supervisor.autoDecide ? allPending : [];\n const answeredDecisions = this.config.supervisor.autoDecide\n ? await decisionStore.answered(lastHeartbeat)\n : [];\n\n return { pendingDecisions, answeredDecisions, hasExpiredDecisions, hasPendingDecisions };\n }\n\n /**\n * Gather event context: drain queue, fetch active runs, memories, and recent actions.\n */\n private async gatherEventContext(): Promise<EventContext> {\n const { grouped, rawEvents } = this.eventQueue.drainAndGroup();\n const totalEventCount =\n grouped.messages.length + grouped.webhooks.length + grouped.runCompletions.length;\n const activeRuns = await this.getActiveRuns();\n\n const mcpServerNames = this.config.mcpServers ? Object.keys(this.config.mcpServers) : [];\n const store = this.getMemoryStore();\n const memories: MemoryEntry[] = store ? store.query({ limit: 40, sortBy: \"relevance\" }) : [];\n const recentActions = await this.activityLog.tail(20);\n\n return {\n grouped,\n rawEvents,\n totalEventCount,\n activeRuns,\n memories,\n recentActions,\n mcpServerNames,\n };\n }\n\n /**\n * Handle post-SDK processing: mark events as processed, consolidate log buffer.\n */\n private async handlePostSdkProcessing(input: PostSdkProcessingInput): Promise<void> {\n // Mark events as processed so they are not replayed on restart\n if (input.rawEvents.length > 0) {\n const inboxPath = path.join(this.supervisorDir, \"inbox.jsonl\");\n await this.eventQueue.markProcessed(inboxPath, this.eventsPath, input.rawEvents);\n }\n\n // Post-response: mark entries consolidated and compact log buffer\n if (input.isConsolidation) {\n const allIds = input.unconsolidated.map((e) => e.id);\n if (allIds.length > 0) {\n await markConsolidated(this.supervisorDir, allIds);\n }\n await compactLogBuffer(this.supervisorDir);\n }\n }\n\n /**\n * Emit completion webhook events: heartbeat completed and run completed events.\n */\n private async emitCompletionEvents(input: CompletionEventsInput): Promise<void> {\n // Emit heartbeat completed webhook event\n await this.emitHeartbeatCompleted({\n heartbeatNumber: input.heartbeatCount + 1,\n runsActive: input.activeRuns.length,\n todayUsd: input.todayCost + input.costUsd,\n limitUsd: this.config.supervisor.dailyCapUsd,\n });\n\n // Emit run completed events for any run completions processed\n for (const event of input.rawEvents) {\n if (event.kind === \"run_complete\") {\n const runData = await this.readPersistedRun(event.runId);\n const emitOpts: Parameters<typeof this.emitRunCompleted>[0] = {\n runId: event.runId,\n status: runData?.status === \"failed\" ? \"failed\" : \"completed\",\n costUsd: runData?.totalCostUsd ?? 0,\n durationMs: runData?.durationMs ?? 0,\n };\n if (runData?.output) {\n emitOpts.output = runData.output;\n }\n await this.emitRunCompleted(emitOpts);\n }\n }\n }\n\n /**\n * Handle skip logic for idle and active-work scenarios.\n * Uses IdleDetector to make skip decisions based on context.\n */\n private async handleSkipLogic(opts: SkipLogicInput): Promise<SkipLogicResult> {\n const { state, totalEventCount, activeRuns, hasPendingConsolidation, hasExpiredDecisions } =\n opts;\n const idleSkipCount = state?.idleSkipCount ?? 0;\n const activeWorkSkipCount = state?.activeWorkSkipCount ?? 0;\n const hasActiveWork = activeRuns.length > 0;\n\n // Calculate time since last heartbeat\n const lastHeartbeatMs = state?.lastHeartbeat\n ? new Date(state.lastHeartbeat).getTime()\n : Date.now();\n const timeSinceLastHeartbeatMs = Date.now() - lastHeartbeatMs;\n\n // Build context for IdleDetector\n const context: IdleContext = {\n eventCount: totalEventCount,\n activeRuns: activeRuns.length,\n hasPendingConsolidation,\n hasExpiredDecisions,\n timeSinceLastHeartbeatMs,\n idleSkipCount,\n activeWorkSkipCount,\n };\n\n // Create detector with current config values\n const detector = new IdleDetector({\n idleSkipMax: this.config.supervisor.idleSkipMax,\n activeWorkSkipMax: this.config.supervisor.activeWorkSkipMax,\n });\n\n const result = detector.shouldSkip(context);\n\n if (result.shouldSkip) {\n // Update skip counters based on whether there's active work\n if (hasActiveWork) {\n await this.updateState({\n activeWorkSkipCount: activeWorkSkipCount + 1,\n idleSkipCount: 0,\n });\n await this.activityLog.log(\n \"heartbeat\",\n `Active-work skip #${activeWorkSkipCount + 1}/${this.config.supervisor.activeWorkSkipMax} — ${result.reason}`,\n );\n } else {\n await this.updateState({\n idleSkipCount: idleSkipCount + 1,\n activeWorkSkipCount: 0,\n });\n await this.activityLog.log(\n \"heartbeat\",\n `Idle skip #${idleSkipCount + 1}/${this.config.supervisor.idleSkipMax} — ${result.reason}`,\n );\n }\n return { shouldSkip: true, resetCounters: false };\n }\n\n const needsReset = idleSkipCount > 0 || activeWorkSkipCount > 0;\n return { shouldSkip: false, resetCounters: needsReset };\n }\n\n /**\n * Determine heartbeat mode: compaction > consolidation > standard.\n */\n private async determineHeartbeatMode(\n state: SupervisorDaemonState | null,\n ): Promise<HeartbeatModeResult> {\n const heartbeatCount = state?.heartbeatCount ?? 0;\n const lastConsolidation = state?.lastConsolidationHeartbeat ?? 0;\n const lastCompaction = state?.lastCompactionHeartbeat ?? 0;\n const lastConsolidationTs = state?.lastConsolidationTimestamp;\n const unconsolidated = await readUnconsolidated(this.supervisorDir);\n\n const hasNewEntriesSinceLastConsolidation = lastConsolidationTs\n ? unconsolidated.some((e) => e.timestamp > lastConsolidationTs)\n : unconsolidated.length > 0;\n\n const hasPendingEntries = unconsolidated.length > 0;\n const isCompaction = shouldCompact(heartbeatCount, lastCompaction);\n const wouldConsolidate = shouldConsolidate(\n heartbeatCount,\n lastConsolidation,\n DEFAULT_CONSOLIDATION_INTERVAL,\n hasPendingEntries,\n );\n const isConsolidation =\n isCompaction || (wouldConsolidate && hasNewEntriesSinceLastConsolidation);\n\n return {\n isConsolidation,\n isCompaction,\n unconsolidated,\n heartbeatCount,\n lastConsolidationTs,\n };\n }\n\n /**\n * Build the state update object after heartbeat completion.\n */\n private buildStateUpdate(opts: {\n state: SupervisorDaemonState | null;\n today: string;\n todayCost: number;\n costUsd: number;\n heartbeatCount: number;\n isConsolidation: boolean;\n isCompaction: boolean;\n }): StateUpdateResult {\n const stateUpdate: Partial<SupervisorDaemonState> = {\n sessionId: this.sessionId,\n lastHeartbeat: new Date().toISOString(),\n heartbeatCount: opts.heartbeatCount + 1,\n totalCostUsd: (opts.state?.totalCostUsd ?? 0) + opts.costUsd,\n todayCostUsd: opts.todayCost + opts.costUsd,\n costResetDate: opts.today,\n };\n\n if (opts.isConsolidation) {\n stateUpdate.lastConsolidationHeartbeat = opts.heartbeatCount + 1;\n stateUpdate.lastConsolidationTimestamp = new Date().toISOString();\n }\n\n if (opts.isCompaction) {\n stateUpdate.lastCompactionHeartbeat = opts.heartbeatCount + 1;\n }\n\n return { stateUpdate };\n }\n\n /**\n * Build the prompt for the current heartbeat mode.\n */\n private async buildHeartbeatModePrompt(opts: {\n grouped: GroupedEvents;\n todayCost: number;\n heartbeatCount: number;\n unconsolidated: LogBufferEntry[];\n isCompaction: boolean;\n isConsolidation: boolean;\n activeRuns: string[];\n pendingDecisions: Decision[];\n answeredDecisions: Decision[];\n hasPendingDecisions: boolean;\n lastHeartbeat: string | undefined;\n lastConsolidationTimestamp: string | undefined;\n memories: MemoryEntry[];\n recentActions: ActivityEntry[];\n mcpServerNames: string[];\n }): Promise<{ prompt: string; modeLabel: string }> {\n const sharedOpts = {\n repos: this.config.repos,\n grouped: opts.grouped,\n budgetStatus: {\n todayUsd: opts.todayCost,\n capUsd: this.config.supervisor.dailyCapUsd,\n remainingPct:\n ((this.config.supervisor.dailyCapUsd - opts.todayCost) /\n this.config.supervisor.dailyCapUsd) *\n 100,\n },\n activeRuns: opts.activeRuns,\n heartbeatCount: opts.heartbeatCount,\n mcpServerNames: opts.mcpServerNames,\n customInstructions: this.customInstructions,\n supervisorDir: this.supervisorDir,\n memories: opts.memories,\n recentActions: opts.recentActions,\n pendingDecisions: opts.pendingDecisions,\n answeredDecisions: opts.answeredDecisions,\n hasPendingDecisions: opts.hasPendingDecisions,\n autoDecide: this.config.supervisor.autoDecide,\n };\n\n if (opts.isCompaction) {\n return {\n prompt: buildCompactionPrompt({\n ...sharedOpts,\n lastConsolidationTimestamp: opts.lastConsolidationTimestamp,\n }),\n modeLabel: \"compaction\",\n };\n }\n\n if (opts.isConsolidation) {\n return {\n prompt: buildConsolidationPrompt({\n ...sharedOpts,\n lastConsolidationTimestamp: opts.lastConsolidationTimestamp,\n }),\n modeLabel: \"consolidation\",\n };\n }\n\n if (isIdleHeartbeat(sharedOpts)) {\n return {\n prompt: buildIdlePrompt(sharedOpts),\n modeLabel: \"idle\",\n };\n }\n\n return {\n prompt: buildStandardPrompt(sharedOpts),\n modeLabel: \"standard\",\n };\n }\n\n /**\n * Call the Claude SDK and stream results.\n *\n * Uses Promise.race to enable non-blocking abort detection. The standard\n * `for await (const message of stream)` pattern only checks the abort signal\n * AFTER each yield — if the SDK hangs (no messages), the abort never executes.\n * This implementation races each iterator.next() against an abort promise,\n * allowing immediate response to shutdown/timeout signals.\n */\n private async callSdk(\n prompt: string,\n heartbeatId: string,\n ): Promise<{ output: string; costUsd: number; turnCount: number }> {\n const abortController = new AbortController();\n this.activeAbort = abortController;\n const timeout = setTimeout(() => {\n abortController.abort(new Error(\"Heartbeat timeout exceeded\"));\n }, this.config.supervisor.heartbeatTimeoutMs);\n\n let output = \"\";\n let costUsd = 0;\n let turnCount = 0;\n\n try {\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\");\n\n // Build allowed tools list — include MCP tool patterns for configured servers\n const allowedTools: string[] = [\"Bash\", \"Read\"];\n if (this.config.mcpServers) {\n for (const name of Object.keys(this.config.mcpServers)) {\n allowedTools.push(`mcp__${name}__*`);\n }\n }\n\n const queryOptions: Record<string, unknown> = {\n cwd: homedir(),\n allowedTools,\n permissionMode: \"bypassPermissions\",\n allowDangerouslySkipPermissions: true,\n mcpServers: this.config.mcpServers ?? {},\n // Don't persist session history — each heartbeat is a fresh conversation.\n // Without this, supervisor restarts could replay old messages.\n persistSession: false,\n };\n\n const stream = sdk.query({ prompt, options: queryOptions as never });\n\n // Create abort promise that resolves when signal fires\n const abortPromise = new Promise<{ aborted: true }>((resolve) => {\n if (abortController.signal.aborted) {\n resolve({ aborted: true });\n return;\n }\n abortController.signal.addEventListener(\"abort\", () => resolve({ aborted: true }), {\n once: true,\n });\n });\n\n // Use Promise.race pattern for abortable stream iteration\n const iterator = stream[Symbol.asyncIterator]();\n try {\n while (true) {\n const raceResult = await Promise.race([iterator.next(), abortPromise]);\n\n // Check if abort triggered\n if (\"aborted\" in raceResult) {\n await this.activityLog.log(\"heartbeat\", \"Heartbeat aborted\", { heartbeatId });\n break;\n }\n\n // Normal iterator result\n const iterResult = raceResult as IteratorResult<unknown>;\n if (iterResult.done) break;\n\n const msg = iterResult.value as SDKStreamMessage;\n\n if (isInitMessage(msg)) {\n this.sessionId = msg.session_id;\n }\n\n if (isResultMessage(msg)) {\n output = msg.result ?? \"\";\n costUsd = msg.total_cost_usd ?? 0;\n turnCount = msg.num_turns ?? 0;\n }\n\n await this.logStreamMessage(msg, heartbeatId);\n }\n } finally {\n // Properly cleanup iterator when done or aborted\n await iterator.return?.();\n }\n } finally {\n clearTimeout(timeout);\n this.activeAbort = null;\n }\n\n return { output, costUsd, turnCount };\n }\n\n private async readState(): Promise<SupervisorDaemonState | null> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch {\n return null;\n }\n }\n\n private async updateState(updates: Partial<SupervisorDaemonState>): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const state = JSON.parse(raw) as SupervisorDaemonState;\n Object.assign(state, updates);\n await writeFile(this.statePath, JSON.stringify(state, null, 2), \"utf-8\");\n } catch {\n // Non-critical\n }\n }\n\n /**\n * Read persisted run files and return summaries of active (running/paused) runs.\n * Validates that \"running\" runs are actually alive by checking their PID.\n * Stale runs (dead PID past grace period) are filtered out to prevent ghost runs.\n */\n private async getActiveRuns(): Promise<string[]> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return [];\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n const active: string[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const subDir = path.join(runsDir, entry.name);\n const files = await readdir(subDir);\n\n for (const f of files) {\n if (!f.endsWith(\".json\")) continue;\n try {\n const raw = await readFile(path.join(subDir, f), \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n\n if (isRunActive(run)) {\n active.push(\n `${run.runId} [${run.status}] ${run.agent} on ${path.basename(run.repo)}`,\n );\n }\n } catch {\n // Corrupted or partial file — skip\n }\n }\n }\n\n return active;\n } catch {\n return [];\n }\n }\n\n /**\n * Load custom instructions from SUPERVISOR.md.\n * Resolution order:\n * 1. Explicit path via `supervisor.instructions` in config\n * 2. User default: ~/.neo/SUPERVISOR.md\n * 3. Bundled default from @neotx/agents (if path provided)\n */\n private async loadInstructions(): Promise<string | undefined> {\n const candidates: string[] = [];\n\n if (this.config.supervisor.instructions) {\n candidates.push(path.resolve(this.config.supervisor.instructions));\n }\n\n candidates.push(path.join(getDataDir(), \"SUPERVISOR.md\"));\n\n if (this.defaultInstructionsPath) {\n candidates.push(this.defaultInstructionsPath);\n }\n\n for (const filePath of candidates) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n await this.activityLog.log(\"event\", `Loaded instructions from ${filePath}`);\n return content;\n } catch {\n // File not found — try next candidate\n }\n }\n\n return undefined;\n }\n\n /** Route a single SDK stream message to the appropriate log handler. */\n private async logStreamMessage(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (isAssistantMessage(msg)) {\n await this.logContentBlocks(msg, heartbeatId);\n } else if (isToolUseMessage(msg)) {\n await this.logToolUse(msg, heartbeatId);\n } else if (isToolResultMessage(msg)) {\n await this.logToolResult(msg, heartbeatId);\n }\n }\n\n /** Log thinking and plan blocks from assistant content — no truncation. */\n private async logContentBlocks(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (!isAssistantMessage(msg)) return;\n const content = msg.message?.content;\n if (!content) return;\n\n for (const block of content) {\n if (block.type === \"thinking\" && block.thinking) {\n await this.activityLog.log(\"thinking\", block.thinking, { heartbeatId });\n }\n if (block.type === \"text\" && block.text) {\n await this.activityLog.log(\"plan\", block.text, { heartbeatId });\n break; // Only log first text block per message\n }\n }\n }\n\n /** Log tool use events — distinguish MCP tools from built-in tools. */\n private async logToolUse(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (!isToolUseMessage(msg)) return;\n const toolName = msg.tool;\n const isMcp = toolName.startsWith(\"mcp__\");\n await this.activityLog.log(\n isMcp ? \"tool_use\" : \"action\",\n isMcp ? toolName : `Tool use: ${toolName}`,\n { heartbeatId, tool: toolName, input: msg.input },\n );\n }\n\n /** Detect agent dispatches from bash tool results. */\n private async logToolResult(msg: SDKStreamMessage, heartbeatId: string): Promise<void> {\n if (!isToolResultMessage(msg)) return;\n const result = msg.result ?? \"\";\n const runMatch = /Run\\s+(\\S+)\\s+dispatched/i.exec(result);\n const runId = runMatch?.[1];\n if (runId) {\n await this.activityLog.log(\"dispatch\", `Agent dispatched: ${runId}`, {\n heartbeatId,\n runId,\n });\n\n // Emit run dispatched webhook event\n // Extract additional info from the result if available.\n //\n // Expected tool result formats from `neo run` command output:\n // - \"Run <runId> dispatched\"\n // - \"agent: <name>\" or \"Agent: <name>\" or \"agent <name>\"\n // - \"repo: <path>\" or \"Repo: <path>\" or \"repo <path>\"\n // - \"branch: <name>\" or \"Branch: <name>\" or \"branch <name>\"\n //\n // These patterns are best-effort extraction. If the format changes,\n // values will default to \"unknown\" without breaking the event emission.\n const agentMatch = /agent[:\\s]+(\\S+)/i.exec(result);\n const repoMatch = /repo[:\\s]+(\\S+)/i.exec(result);\n const branchMatch = /branch[:\\s]+(\\S+)/i.exec(result);\n\n const agent = agentMatch?.[1] ?? \"unknown\";\n const repo = repoMatch?.[1] ?? \"unknown\";\n const branch = branchMatch?.[1] ?? \"unknown\";\n\n await this.emitRunDispatched({\n runId,\n agent,\n repo,\n branch,\n prompt: result.slice(0, 500),\n });\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Process decision:answer events from inbox messages.\n * Expected format: \"decision:answer <decisionId> <answer>\"\n */\n private async processDecisionAnswers(\n rawEvents: QueuedEvent[],\n store: DecisionStore,\n ): Promise<void> {\n for (const event of rawEvents) {\n if (event.kind !== \"message\") continue;\n\n const text = event.data.text.trim();\n const match = /^decision:answer\\s+(\\S+)\\s+(.+)$/i.exec(text);\n if (!match) continue;\n\n const decisionId = match[1];\n const answer = match[2];\n if (!decisionId || !answer) continue;\n\n try {\n await store.answer(decisionId, answer);\n await this.activityLog.log(\"event\", `Decision answered: ${decisionId}`, {\n decisionId,\n answer,\n });\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Failed to answer decision ${decisionId}: ${msg}`, {\n decisionId,\n answer,\n });\n }\n }\n }\n\n /**\n * Read persisted run data to extract actual status, cost, and duration.\n * Returns null if the run file cannot be found or parsed.\n */\n private async readPersistedRun(runId: string): Promise<{\n status: PersistedRun[\"status\"];\n totalCostUsd: number;\n durationMs: number;\n output: string | undefined;\n } | null> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return null;\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const subDir = path.join(runsDir, entry.name);\n const runPath = path.join(subDir, `${runId}.json`);\n\n if (existsSync(runPath)) {\n const raw = await readFile(runPath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n\n // Calculate total cost from all steps\n const totalCostUsd = Object.values(run.steps).reduce(\n (sum, step) => sum + (step.costUsd ?? 0),\n 0,\n );\n\n // Calculate duration from createdAt to updatedAt\n const durationMs = new Date(run.updatedAt).getTime() - new Date(run.createdAt).getTime();\n\n // Get output from the last completed step\n const completedSteps = Object.values(run.steps).filter(\n (s) => s.status === \"success\" || s.status === \"failure\",\n );\n const lastStep = completedSteps[completedSteps.length - 1];\n const output =\n typeof lastStep?.rawOutput === \"string\" ? lastStep.rawOutput.slice(0, 1000) : undefined;\n\n return { status: run.status, totalCostUsd, durationMs, output };\n }\n }\n } catch {\n // Non-critical — return null if we can't read run data\n }\n\n return null;\n }\n\n // ─── Webhook event emission ───────────────────────────────\n\n /**\n * Emit a webhook event if a callback is configured.\n * Validates the event against its schema before emission.\n */\n private async emitWebhookEvent(event: SupervisorWebhookEvent): Promise<void> {\n if (!this.onWebhookEvent) return;\n\n try {\n // Validate event against schema before emission\n switch (event.type) {\n case \"supervisor_started\":\n supervisorStartedEventSchema.parse(event);\n break;\n case \"heartbeat\":\n heartbeatEventSchema.parse(event);\n break;\n case \"run_dispatched\":\n runDispatchedEventSchema.parse(event);\n break;\n case \"run_completed\":\n runCompletedEventSchema.parse(event);\n break;\n case \"supervisor_stopped\":\n supervisorStoppedEventSchema.parse(event);\n break;\n }\n\n await this.onWebhookEvent(event);\n } catch (error) {\n // Log validation/emission errors but don't fail the heartbeat\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Webhook event emission failed: ${msg}`, {\n eventType: event.type,\n });\n }\n }\n\n /** Emit SupervisorStartedEvent */\n private async emitSupervisorStarted(): Promise<void> {\n const event: SupervisorStartedEvent = {\n type: \"supervisor_started\",\n supervisorId: this.sessionId,\n startedAt: new Date().toISOString(),\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit SupervisorStoppedEvent */\n private async emitSupervisorStopped(\n reason: \"shutdown\" | \"budget_exceeded\" | \"error\" | \"manual\",\n ): Promise<void> {\n const event: SupervisorStoppedEvent = {\n type: \"supervisor_stopped\",\n supervisorId: this.sessionId,\n stoppedAt: new Date().toISOString(),\n reason,\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit HeartbeatEvent */\n private async emitHeartbeatCompleted(opts: {\n heartbeatNumber: number;\n runsActive: number;\n todayUsd: number;\n limitUsd: number;\n }): Promise<void> {\n const event: HeartbeatEvent = {\n type: \"heartbeat\",\n supervisorId: this.sessionId,\n heartbeatNumber: opts.heartbeatNumber,\n timestamp: new Date().toISOString(),\n runsActive: opts.runsActive,\n budget: {\n todayUsd: opts.todayUsd,\n limitUsd: opts.limitUsd,\n },\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit RunDispatchedEvent from tool result detection */\n private async emitRunDispatched(opts: {\n runId: string;\n agent: string;\n repo: string;\n branch: string;\n prompt: string;\n }): Promise<void> {\n const event: RunDispatchedEvent = {\n type: \"run_dispatched\",\n supervisorId: this.sessionId,\n runId: opts.runId,\n agent: opts.agent,\n repo: opts.repo,\n branch: opts.branch,\n prompt: opts.prompt.slice(0, 500), // Truncate to schema max\n };\n await this.emitWebhookEvent(event);\n }\n\n /** Emit RunCompletedEvent when processing run_complete events */\n private async emitRunCompleted(opts: {\n runId: string;\n status: \"completed\" | \"failed\" | \"cancelled\";\n output?: string;\n costUsd: number;\n durationMs: number;\n }): Promise<void> {\n const event: RunCompletedEvent = {\n type: \"run_completed\",\n supervisorId: this.sessionId,\n runId: opts.runId,\n status: opts.status,\n output: opts.output?.slice(0, 1000), // Truncate to schema max\n costUsd: opts.costUsd,\n durationMs: opts.durationMs,\n };\n await this.emitWebhookEvent(event);\n }\n}\n","import { z } from \"zod\";\n\n// ─── Schemas ─────────────────────────────────────────────\n\nexport const idleDetectorConfigSchema = z.object({\n idleSkipMax: z.number(),\n activeWorkSkipMax: z.number(),\n});\n\nexport const idleContextSchema = z.object({\n eventCount: z.number(),\n activeRuns: z.number(),\n hasPendingConsolidation: z.boolean(),\n hasExpiredDecisions: z.boolean(),\n timeSinceLastHeartbeatMs: z.number(),\n idleSkipCount: z.number(),\n activeWorkSkipCount: z.number(),\n});\n\nexport const skipResultSchema = z.object({\n shouldSkip: z.boolean(),\n reason: z.string(),\n});\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type IdleDetectorConfig = z.infer<typeof idleDetectorConfigSchema>;\nexport type IdleContext = z.infer<typeof idleContextSchema>;\nexport type SkipResult = z.infer<typeof skipResultSchema>;\n\n// ─── Detector ────────────────────────────────────────────\n\n/**\n * Determines whether a supervisor heartbeat cycle should be skipped.\n * Extracts skip logic into a testable, single-responsibility class.\n */\nexport class IdleDetector {\n private readonly config: IdleDetectorConfig;\n\n constructor(config: IdleDetectorConfig) {\n this.config = config;\n }\n\n /**\n * Evaluate whether the current heartbeat should be skipped.\n * @returns SkipResult with shouldSkip flag and reason\n */\n shouldSkip(context: IdleContext): SkipResult {\n // Events pending — must process\n if (context.eventCount > 0) {\n return { shouldSkip: false, reason: \"events pending\" };\n }\n\n // Consolidation waiting — must process\n if (context.hasPendingConsolidation) {\n return { shouldSkip: false, reason: \"pending consolidation\" };\n }\n\n // Expired decisions — must process\n if (context.hasExpiredDecisions) {\n return { shouldSkip: false, reason: \"expired decisions\" };\n }\n\n // Active runs — check threshold\n if (context.activeRuns > 0) {\n if (context.activeWorkSkipCount >= this.config.activeWorkSkipMax) {\n return { shouldSkip: false, reason: \"active work skip threshold exceeded\" };\n }\n return { shouldSkip: true, reason: \"active runs, within threshold\" };\n }\n\n // Idle — check threshold\n if (context.idleSkipCount >= this.config.idleSkipMax) {\n return { shouldSkip: false, reason: \"idle skip threshold exceeded\" };\n }\n\n return { shouldSkip: true, reason: \"idle, within threshold\" };\n }\n}\n","import { appendFile, readFile, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { LogBufferEntry } from \"./schemas.js\";\n\nconst LOG_BUFFER_FILE = \"log-buffer.jsonl\";\nconst MAX_FILE_BYTES = 1024 * 1024; // 1MB cap\nconst COMPACTION_AGE_MS = 24 * 60 * 60 * 1000; // 24h\nconst MAX_ENTRIES_PER_RUN = 5;\nconst MAX_DIGEST_ENTRIES = 30;\n\n// ─── Type markers for digest formatting ─────────────────\n\nconst TYPE_MARKERS: Record<string, string> = {\n milestone: \"★\",\n decision: \"◆\",\n blocker: \"⚠\",\n progress: \"·\",\n action: \"→\",\n discovery: \"◇\",\n};\n\n// ─── Core read/write ────────────────────────────────────\n\nfunction bufferPath(dir: string): string {\n return path.join(dir, LOG_BUFFER_FILE);\n}\n\nfunction parseLines(content: string): LogBufferEntry[] {\n const entries: LogBufferEntry[] = [];\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n try {\n entries.push(JSON.parse(line) as LogBufferEntry);\n } catch (err) {\n // Skip malformed JSONL line\n console.debug(\n `[log-buffer] Skipping malformed line: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n return entries;\n}\n\n/**\n * Read all entries from log-buffer.jsonl.\n */\nexport async function readLogBuffer(dir: string): Promise<LogBufferEntry[]> {\n try {\n const content = await readFile(bufferPath(dir), \"utf-8\");\n return parseLines(content);\n } catch (err) {\n // Buffer file not found or unreadable\n console.debug(\n `[log-buffer] Failed to read buffer: ${err instanceof Error ? err.message : String(err)}`,\n );\n return [];\n }\n}\n\n/**\n * Read entries with timestamp > since.\n */\nexport async function readLogBufferSince(dir: string, since: string): Promise<LogBufferEntry[]> {\n const entries = await readLogBuffer(dir);\n return entries.filter((e) => e.timestamp > since);\n}\n\n/**\n * Read entries where consolidatedAt is null/undefined.\n */\nexport async function readUnconsolidated(dir: string): Promise<LogBufferEntry[]> {\n const entries = await readLogBuffer(dir);\n return entries.filter((e) => !e.consolidatedAt);\n}\n\n/**\n * Set consolidatedAt on entries by id.\n * Rewrites the file with updated entries.\n */\nexport async function markConsolidated(dir: string, ids: string[]): Promise<void> {\n const filePath = bufferPath(dir);\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (err) {\n // Buffer file not found — nothing to mark\n console.debug(\n `[log-buffer] Failed to read for consolidation: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n\n const idSet = new Set(ids);\n const now = new Date().toISOString();\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const updated: string[] = [];\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as LogBufferEntry;\n if (idSet.has(entry.id) && !entry.consolidatedAt) {\n entry.consolidatedAt = now;\n }\n updated.push(JSON.stringify(entry));\n } catch (err) {\n // Preserve malformed lines as-is during consolidation\n console.debug(\n `[log-buffer] Preserving malformed line during consolidation: ${err instanceof Error ? err.message : String(err)}`,\n );\n updated.push(line);\n }\n }\n\n await writeFile(filePath, `${updated.join(\"\\n\")}\\n`, \"utf-8\");\n}\n\n/**\n * Remove entries with consolidatedAt older than 24h. Cap file at 1MB.\n */\nexport async function compactLogBuffer(dir: string): Promise<void> {\n const filePath = bufferPath(dir);\n let content: string;\n try {\n content = await readFile(filePath, \"utf-8\");\n } catch (err) {\n // Buffer file not found — nothing to compact\n console.debug(\n `[log-buffer] Failed to read for compaction: ${err instanceof Error ? err.message : String(err)}`,\n );\n return;\n }\n\n const now = Date.now();\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const kept: string[] = [];\n\n for (const line of lines) {\n try {\n const entry = JSON.parse(line) as LogBufferEntry;\n if (entry.consolidatedAt) {\n const consolidatedTime = new Date(entry.consolidatedAt).getTime();\n if (now - consolidatedTime > COMPACTION_AGE_MS) {\n continue; // Drop old consolidated entries\n }\n }\n kept.push(JSON.stringify(entry));\n } catch (err) {\n // Drop malformed lines during compaction\n console.debug(\n `[log-buffer] Dropping malformed line during compaction: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // Cap at 1MB — drop oldest entries first\n let result = `${kept.join(\"\\n\")}\\n`;\n while (Buffer.byteLength(result, \"utf-8\") > MAX_FILE_BYTES && kept.length > 0) {\n kept.shift();\n result = `${kept.join(\"\\n\")}\\n`;\n }\n\n await writeFile(filePath, result, \"utf-8\");\n}\n\n// ─── Digest helpers ──────────────────────────────────────\n\nfunction groupEntriesByRunId(entries: LogBufferEntry[]): Map<string, LogBufferEntry[]> {\n const groups = new Map<string, LogBufferEntry[]>();\n for (const entry of entries) {\n const key = entry.runId ?? \"unassigned\";\n const group = groups.get(key);\n if (group) {\n group.push(entry);\n } else {\n groups.set(key, [entry]);\n }\n }\n return groups;\n}\n\nfunction dedupeAdjacentEntries(entries: LogBufferEntry[]): LogBufferEntry[] {\n const deduped: LogBufferEntry[] = [];\n for (const entry of entries) {\n const last = deduped[deduped.length - 1];\n if (last && last.message === entry.message) continue;\n deduped.push(entry);\n }\n return deduped;\n}\n\n/**\n * Build a human-readable digest from log buffer entries.\n * Groups by runId, sorts chronologically, adds type markers,\n * deduplicates adjacent identical messages, truncates output.\n */\nexport function buildAgentDigest(entries: LogBufferEntry[]): string {\n if (entries.length === 0) return \"\";\n\n const groups = groupEntriesByRunId(entries);\n const lines: string[] = [];\n let totalCount = 0;\n\n for (const [runId, group] of groups) {\n group.sort((a, b) => a.timestamp.localeCompare(b.timestamp));\n\n const deduped = dedupeAdjacentEntries(group);\n const limited = deduped.slice(0, MAX_ENTRIES_PER_RUN);\n\n const agentLabel = limited[0]?.agent ?? \"unknown\";\n lines.push(`[${runId}] (${agentLabel}):`);\n\n for (const entry of limited) {\n if (totalCount >= MAX_DIGEST_ENTRIES) break;\n const marker = TYPE_MARKERS[entry.type] ?? \"·\";\n lines.push(` ${marker} ${entry.message}`);\n totalCount++;\n }\n\n if (totalCount >= MAX_DIGEST_ENTRIES) {\n lines.push(\" ... (truncated)\");\n break;\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Append a single entry to the log buffer file.\n */\nexport async function appendLogBuffer(dir: string, entry: LogBufferEntry): Promise<void> {\n try {\n // Ensure directory exists (appendFile will create the file but not the dir)\n await appendFile(bufferPath(dir), `${JSON.stringify(entry)}\\n`, \"utf-8\");\n } catch (err) {\n // Best-effort — don't crash the CLI if buffer write fails\n console.debug(\n `[log-buffer] Failed to append entry: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\n/**\n * Get file size of the log buffer (for monitoring).\n */\nexport async function getLogBufferSize(dir: string): Promise<number> {\n try {\n const stats = await stat(bufferPath(dir));\n return stats.size;\n } catch (err) {\n // Buffer file not found or inaccessible\n console.debug(\n `[log-buffer] Failed to get buffer size: ${err instanceof Error ? err.message : String(err)}`,\n );\n return 0;\n }\n}\n","import type { RepoConfig } from \"@/config\";\nimport type { Decision } from \"./decisions.js\";\nimport type { GroupedEvents } from \"./event-queue.js\";\nimport type { MemoryEntry } from \"./memory/entry.js\";\nimport type { ActivityEntry, QueuedEvent } from \"./schemas.js\";\n\n// ─── Shared options ─────────────────────────────────────\n\nexport interface PromptOptions {\n repos: RepoConfig[];\n grouped: GroupedEvents;\n budgetStatus: {\n todayUsd: number;\n capUsd: number;\n remainingPct: number;\n };\n activeRuns: string[];\n heartbeatCount: number;\n mcpServerNames: string[];\n customInstructions?: string | undefined;\n supervisorDir: string;\n memories: MemoryEntry[];\n recentActions: ActivityEntry[];\n pendingDecisions?: Decision[] | undefined;\n answeredDecisions?: Decision[] | undefined;\n /** When true, supervisor answers decisions autonomously instead of waiting for human input */\n autoDecide?: boolean | undefined;\n /**\n * True when there are pending decisions regardless of autoDecide mode.\n * Used by buildIdlePrompt to block scout dispatch when the user has unanswered decisions.\n */\n hasPendingDecisions?: boolean | undefined;\n}\n\nexport interface StandardPromptOptions extends PromptOptions {}\n\nexport interface ConsolidationPromptOptions extends PromptOptions {\n /** ISO timestamp of last consolidation — used to filter run history */\n lastConsolidationTimestamp?: string | undefined;\n}\n\n// ─── Role (identity only — behavioral rules go in <instructions>) ──\n\nconst ROLE = `You are the neo autonomous supervisor — accountable for delivery across parallel initiatives.\n\nYou do not write code directly; you ensure the right work is assigned, executed, reviewed, and completed by the right agent.`;\n\n// ─── Operating principles (behavioral contract — lives in <instructions>) ──\n\nconst OPERATING_PRINCIPLES = `### Operating principles\n\n- Own delivery end-to-end: any queued task without an active owner is your responsibility.\n- Operate like a strong engineering lead: provide clear context, dispatch deliberately, validate outcomes, and remove blockers quickly.\n- On run completion: read \\`neo runs <runId>\\`, verify acceptance criteria, then decide next action (done, follow-up, redispatch, escalate).\n- On run failure: diagnose root cause before retrying (prompt quality, branch conflict, known issue, environment/tooling), then fix the cause.\n- Prevent silent stalls: monitor long-running jobs, detect blocked work early, and actively unblock.\n- Keep initiative boundaries strict: decisions for initiative A must not be influenced by unrelated state from B.\n- Your user-visible channel is \\`neo log\\` only; produce concise tool calls (not reasoning/explanations) and avoid wasted tokens.\n- You may inspect repositories available via \\`neo repos\\`, read-only to launch agents.\n- Task hygiene is non-negotiable: update task outcomes EVERY heartbeat. A task without a current outcome is a blind spot.\n- **No duplicate dispatches**: before dispatching a \\`developer\\` for any finding, ALWAYS check for open or recently merged PRs on the same topic: \\`gh pr list --repo <repo> --search \"<keywords>\" --state open\\` and \\`--state merged --limit 5\\`. If a similar PR exists → skip and log with \\`neo log discovery\\`. Dispatching duplicate agents wastes budget and pollutes the PR list.`;\n\n// ─── Commands reference (data — lives in <reference>) ───\n\nconst COMMANDS = `### Dispatching agents\n\\`\\`\\`bash\nneo run <agent> --prompt \"...\" --repo <path> --branch <name> [--priority critical|high|medium|low] [--meta '<json>']\n\\`\\`\\`\n\n| Flag | Required | Description |\n|------|----------|-------------|\n| \\`--prompt\\` | always | Task description for the agent |\n| \\`--repo\\` | always | Target repository path |\n| \\`--branch\\` | always | Branch name for the isolated clone |\n| \\`--priority\\` | optional | \\`critical\\`, \\`high\\`, \\`medium\\`, \\`low\\` |\n| \\`--meta\\` | **always** | JSON with \\`\"label\"\\` for identification + \\`\"ticketId\"\\`, \\`\"stage\"\\`, etc. |\n\nAll agents require \\`--branch\\`. Each agent session runs in an isolated clone on that branch.\nAlways include \\`--meta '{\"label\":\"T1-auth-middleware\",\"ticketId\":\"YC-42\",\"stage\":\"develop\"}'\\` so you can identify runs later.\n\n### Monitoring & reading agent output\n\\`\\`\\`bash\nneo runs --short # check recent runs\nneo runs --short --status running # check active runs are alive\nneo runs <runId> # full run details + agent output (MUST READ on completion)\nneo cost --short [--all] # check budget\n\\`\\`\\`\n\n\\`neo runs <runId>\\` returns the agent's full output. **ALWAYS read it when a run completes** — it contains structured JSON (PR URLs, issues, plans, milestones) that you need to decide next steps.\n\n### Memory\n\\`\\`\\`bash\nneo memory write --type fact --scope /path \"Stable fact about repo\"\nneo memory write --type focus --expires 2h \"Current working context\"\nneo memory write --type procedure --scope /path \"How to do X\"\nneo memory write --type task --scope /path --severity high --category \"neo runs <id>\" \"Task description\"\nneo memory update <id> --outcome in_progress|done|blocked|abandoned\nneo memory forget <id>\nneo memory search \"keyword\"\nneo memory list --type fact\n\\`\\`\\`\n\n### Configuration\n\\`\\`\\`bash\nneo config get <key> # read a value (dot notation)\nneo config set <key> <value> --global # update global config (~/.neo/config.yml)\nneo config list # show full merged config\n\\`\\`\\`\n\nKeys use dot notation (e.g., \\`budget.dailyCapUsd\\`, \\`supervisor.dailyCapUsd\\`, \\`concurrency.maxSessions\\`).\nChanges are hot-reloaded — the new values take effect at the next heartbeat.\n\nUse cases: raise budget cap mid-run, adjust concurrency, change heartbeat timeout.\n\n### Decisions\nWhen you need human input on something that cannot be decided autonomously:\n\\`\\`\\`bash\nneo decision create \"<question>\" --options \"key1:label1,key2:label2:description\" [--default <key>] [--expires-in 24h] [--context \"...\"]\nneo decision list # show pending decisions\nneo decision answer <id> <answer> # answer a decision (usually done by human via TUI)\n\\`\\`\\`\nThe decision ID is returned by \\`create\\`. If no answer arrives before expiration, the \\`--default\\` answer is applied automatically (or the decision expires without resolution).\n\n### Reporting\n\\`\\`\\`bash\nneo log <type> \"<message>\" # visible in TUI only\n\\`\\`\\``;\n\nconst COMMANDS_COMPACT = `### Commands (reference)\n\\`neo run <agent> --prompt \"...\" --repo <path> --branch <name> --meta '{\"label\":\"T1-auth\",...}'\\`\n\\`neo runs [--short | <runId>]\\` \\u00b7 \\`neo runs --short --status running\\` \\u00b7 \\`neo cost --short\\`\n\\`neo memory write|update|forget|search|list\\` \\u00b7 \\`neo log <type> \"<msg>\"\\`\n\\`neo config get <key>\\` \\u00b7 \\`neo config set <key> <value> --global\\` \\u00b7 \\`neo config list\\`\n\\`neo decision create \"<question>\" --options \"...\" [--default <key>]\\` \\u00b7 \\`neo decision list\\``;\n\n// ─── Instruction blocks ─────────────────────────────────\n\nconst HEARTBEAT_RULES = `### Heartbeat lifecycle\n\n<decision-tree>\n1. DEDUP FIRST — check focus for PROCESSED entries. Skip any runId already processed.\n2. MONITOR RUNS — \\`neo runs --short\\` to check active run status. If a run completed since last HB, read its output with \\`neo runs <runId>\\` BEFORE doing anything else.\n3. PENDING TASKS? — dispatch the next eligible task from work queue. Do not re-plan.\n4. EVENTS? — process run completions, messages, webhooks. Parse agent JSON output.\n5. FOLLOW-UPS? — check CI (\\`gh pr checks\\`), deferred dispatches.\n6. DISPATCH — route work to agents. Mark tasks \\`in_progress\\`, add ACTIVE to focus.\n7. UPDATE TASKS — review ALL in_progress/blocked tasks. For each: confirm status matches reality (run still active? PR merged? blocked resolved?). Update outcomes immediately — do not defer to next heartbeat.\n8. SERIALIZE & YIELD — rewrite focus (see <focus>), log your decisions, and yield. Do not poll.\n</decision-tree>\n\n<run-monitoring>\nRuns are your agents in the field. You MUST actively track them:\n- **On dispatch**: include a label in \\`--meta\\` for identification: \\`--meta '{\"label\":\"T6-csv-export\",\"ticketId\":\"YC-42\",...}'\\`\n- **On completion**: ALWAYS run \\`neo runs <runId>\\` to read the full output. Parse structured JSON (PR URLs, issues, plans). This is NOT optional — you cannot decide next steps without reading the output.\n- **On failure**: read the output to understand why. Decide: retry (blocked), abandon, or escalate.\n- **Active runs**: check \\`neo runs --short --status running\\` to verify your runs are still alive. If a run disappeared, investigate.\n</run-monitoring>\n\n<multi-task-initiatives>\n**Branch strategy:** one branch per initiative — all tasks push to the same branch sequentially (never in parallel). First task creates the branch; open PR after it completes. Later tasks add commits to the same PR. Independent initiatives CAN run in parallel on different branches.\n\n**Dispatch quality:** write a detailed \\`--prompt\\` with acceptance criteria, files to modify, and context from completed sibling tasks (commits, APIs added, files changed). When dispatching task N, summarize what tasks 1..N-1 produced.\n\n**Post-completion:** if agent opened a PR, dispatch \\`reviewer\\` in parallel with CI (do not wait). Update task outcome with concrete details (PR#, what was done) and update the initiative note.\n\n**Task tracking discipline:**\n- On dispatch: \\`neo memory update <id> --outcome in_progress\\` immediately — never dispatch without updating the task.\n- On run completion: update to \\`done\\` with details OR \\`blocked\\` with reason. Do this in the SAME heartbeat you read the run output.\n- On run failure: update to \\`blocked\\` with root cause. Never leave a failed run's task as \\`in_progress\\`.\n- Every heartbeat: cross-check active tasks against \\`neo runs --short\\`. If a run finished but the task is still \\`in_progress\\`, something was missed — fix it now.\n\n**Memory:** store key outputs as facts if they affect future tasks (e.g. \"T5 added dateRange param to fetchAllFstRecords\").\n</multi-task-initiatives>`;\n\nconst REPORTING_RULES = `### Reporting\n\n\\`neo log\\` is your ONLY visible output. Use telegraphic format.\n\n<log-format>\nneo log decision \"<ticket> \\u2192 <action> | <1-line reason>\"\nneo log action \"<agent> <repo>:<branch> run:<runId> | <context>\"\nneo log discovery \"<what> in <where>\"\n</log-format>\n\n<examples type=\"good\">\nneo log decision \"YC-42 \\u2192 developer | clear spec, complexity 3\"\nneo log action \"developer standards:feat/YC-42-auth run:5900a64a | task T1\"\nneo log discovery \"CI requires node 20 in api-service\"\n</examples>`;\n\nfunction buildMemoryRulesCore(supervisorDir: string): string {\n const notesDir = `${supervisorDir}/notes`;\n return `### Memory\n\n<memory-types>\n| Type | Store when | TTL |\n|------|-----------|-----|\n| \\`fact\\` | Stable truth affecting dispatch decisions | Permanent (decays) |\n| \\`procedure\\` | Same failure 3+ times | Permanent |\n| \\`focus\\` | After every dispatch/deferral | --expires required |\n| \\`task\\` | Any planned work (tickets, decompositions, follow-ups) | Until done/abandoned |\n| \\`feedback\\` | Same review complaint 3+ times | Permanent |\n</memory-types>\n\n<memory-rules>\n- Focus is free-form working memory — rewrite at end of EVERY heartbeat (see <focus>).\n- NEVER store: file counts, line numbers, completed work details, data available via \\`neo runs <id>\\`.\n- After PR merge: forget related facts unless they are reusable architectural truths.\n- Pattern escalation: same failure 3+ times \\u2192 write a \\`procedure\\`.\n- Every memory that references external context MUST include a retrieval command (in \\`--category\\` for tasks, in content for facts/procedures). You are stateless — if you can't retrieve it later, don't store it.\n</memory-rules>\n\n<task-workflow>\nQueue markers: \\u25cb pending \\u00b7 [ACTIVE] in_progress \\u00b7 [BLOCKED] blocked.\nCreate tasks for: incoming tickets, architect decompositions, sub-tickets, follow-ups, CI fixes.\n- \\`--tags \"initiative:<name>\"\\` — groups related tasks\n- \\`--tags \"depends:mem_<id>\"\\` — blocks until dependency is done\n- \\`--category\\` — retrieval command (MANDATORY). Examples: \\`\"neo runs <runId>\"\\` \\u00b7 \\`\"cat ${notesDir}/plan-feature.md\"\\` \\u00b7 \\`\"API-retrieve-a-page <notionPageId>\"\\`\nLifecycle: create → in_progress (on dispatch) → done | blocked | abandoned\n\n**Update frequency:** task outcomes MUST be updated in the same heartbeat as the triggering event. Never defer a task update to \"next heartbeat\" — by then you will have forgotten. Stale task states cause duplicate dispatches and wasted budget.\n\n**Mandatory cross-check:** before yielding, verify that:\n1. Every dispatched run has a corresponding \\`in_progress\\` task\n2. Every completed run has a corresponding \\`done\\` or \\`blocked\\` task\n3. No task is \\`in_progress\\` without an active run (unless manually worked)\n</task-workflow>\n\n<focus>\nYou are stateless between heartbeats. Focus is your scratchpad — the only thing future-you will read before acting.\n\nWrite it like a handoff note to yourself: what's happening, what you decided, what to do next, what to watch for. Free-form. No format imposed. The only rule: if you don't write it down, you lose it.\n\nRewrite focus at the END of every heartbeat. Never leave it empty after a heartbeat with activity.\n</focus>\n\n<notes>\nNotes directory: \\`${notesDir}/\\`\nUse notes for any initiative with 3+ tasks (persists across heartbeats).\n- Write: \\`cat > ${notesDir}/plan-<initiative>.md << 'EOF' ... EOF\\`\n- Link to tasks: \\`--category \"cat ${notesDir}/plan-<initiative>.md\"\\`\n- Update after each task: check off milestones, add PR numbers, note blockers\n- Delete when initiative is done\nUse cases: architect decompositions, initiative tracking, debugging across heartbeats, review checklists.\n</notes>`;\n}\n\nfunction buildMemoryRulesExamples(supervisorDir: string): string {\n const notesDir = `${supervisorDir}/notes`;\n return `<memory-examples>\nneo memory write --type focus --expires 2h \"ACTIVE: 5900a64a developer 'T1' branch:feat/x (cat ${notesDir}/plan-YC-2670-kanban.md)\"\nneo memory write --type fact --scope /repo \"main branch uses protected merges — agents must create PRs, never push directly\"\nneo memory write --type fact --scope /repo \"pnpm build must pass before push — CI does not rebuild, run 2g589f34a5a failed without it\"\nneo memory write --type procedure --scope /repo \"After architect run: parse milestones from JSON output, create one task per milestone with --tags initiative:<name>\"\nneo memory write --type procedure --scope /repo \"When developer run fails with ENOSPC: the repo has large fixtures — use --branch with shallow clone flag\"\nneo memory write --type feedback --scope /repo \"User wants PR descriptions in French even though code is in English\"\nneo memory write --type task --scope /repo --severity high --category \"neo runs 2g589f34a5a\" --tags \"initiative:auth-v2,depends:mem_xyz\" \"T1: Auth middleware\"\nneo memory update <id> --outcome in_progress|done|blocked|abandoned\nneo memory forget <id>\n</memory-examples>`;\n}\n\n// ─── Prompt assembly helpers ────────────────────────────\n//\n// Prompt structure follows Anthropic best practices:\n// <role> — Identity only (2 sentences)\n// <context> — Data top: focus → work state → knowledge → environment → events (query last)\n// <reference> — Command documentation (stable reference data)\n// <instructions> — All behavioral rules bottom: principles → lifecycle → reporting → memory → directive\n\nfunction buildRoleSection(heartbeatCount: number, label?: string): string {\n const suffix = label ? ` (${label})` : \"\";\n return `<role>\\n${ROLE}\\nHeartbeat #${heartbeatCount}${suffix}\\n</role>`;\n}\n\nfunction getCommandsSection(heartbeatCount: number): string {\n return heartbeatCount <= 3 ? COMMANDS : COMMANDS_COMPACT;\n}\n\nfunction buildReferenceSection(heartbeatCount: number): string {\n return `<reference>\\n${getCommandsSection(heartbeatCount)}\\n</reference>`;\n}\n\n/**\n * Build the focus section from memory entries.\n * Rendered at the top of <context> — first thing the supervisor reads to re-orient.\n */\nfunction buildFocusSection(memories: MemoryEntry[]): string {\n const focusEntries = memories.filter((m) => m.type === \"focus\");\n\n if (focusEntries.length > 0) {\n const lines = focusEntries.map((m) => `- ${m.content}`).join(\"\\n\");\n return `<focus>\\n${lines}\\n</focus>`;\n }\n\n return \"<focus>\\n(empty \\u2014 use neo memory write --type focus to set working context)\\n</focus>\";\n}\n\n// ─── Decision sections ──────────────────────────────────\n\n/**\n * Build the pending decisions section.\n * Shows decisions awaiting supervisor response with autoDecide instructions.\n * Only rendered in autoDecide mode (decisions are empty otherwise).\n */\nfunction buildPendingDecisionsSection(decisions: Decision[] | undefined): string {\n if (!decisions || decisions.length === 0) {\n return \"\";\n }\n\n const lines: string[] = [];\n for (const d of decisions) {\n const expiry = d.expiresAt ? ` (expires: ${d.expiresAt})` : \"\";\n const defaultHint = d.defaultAnswer ? ` [default: ${d.defaultAnswer}]` : \"\";\n lines.push(`- **${d.id}**: ${d.question}${expiry}${defaultHint}`);\n\n if (d.options && d.options.length > 0) {\n for (const opt of d.options) {\n const desc = opt.description ? ` — ${opt.description}` : \"\";\n lines.push(` • \\`${opt.key}\\`: ${opt.label}${desc}`);\n }\n }\n\n if (d.context) {\n lines.push(` Context: ${d.context}`);\n }\n }\n\n const instruction = `You are in **autoDecide** mode — answer each pending decision yourself based on available context, project knowledge, and best engineering judgment.\n\n\\`\\`\\`bash\nneo decision answer <decision_id> <answer>\n\\`\\`\\`\n\nFor each decision: analyze the options, consider the project context and risk, then answer decisively. Prefer safe, incremental choices when uncertain. Log your reasoning before answering.\n\n**Merge authority:** In autoDecide mode you MAY merge branches when the PR is ready (CI green, reviews approved). Use \\`gh pr merge\\` with the appropriate merge strategy.`;\n\n return `Pending decisions (${decisions.length}):\n${lines.join(\"\\n\")}\n\n${instruction}`;\n}\n\n/**\n * Build the recent answered decisions section.\n * Provides context continuity by showing recently resolved decisions.\n */\nfunction buildAnsweredDecisionsSection(decisions: Decision[] | undefined): string {\n if (!decisions || decisions.length === 0) {\n return \"\";\n }\n\n const lines = decisions.map((d) => {\n const answeredBy = d.source ? ` (by ${d.source})` : \"\";\n return `- ${d.id}: \"${d.question}\" → **${d.answer}**${answeredBy}`;\n });\n\n return `Recent decisions (${decisions.length}):\\n${lines.join(\"\\n\")}`;\n}\n\n/**\n * Build the full context block shared by standard & consolidation prompts.\n * Order: focus (orientation) \\u2192 work state \\u2192 knowledge \\u2192 environment \\u2192 events (query last).\n * Compaction uses a subset via buildCompactionContext.\n */\nfunction buildFullContext(opts: PromptOptions): string {\n const parts: string[] = [];\n\n // 1. Focus — orientation (first thing read after role)\n parts.push(buildFocusSection(opts.memories));\n\n // 2. Work state — what's happening right now\n const workQueue = buildWorkQueueSection(opts.memories);\n if (workQueue) {\n parts.push(workQueue);\n }\n\n if (opts.activeRuns.length > 0) {\n parts.push(`Active runs:\\n${opts.activeRuns.map((r) => `- ${r}`).join(\"\\n\")}`);\n }\n\n const recentActions = buildRecentActionsSection(opts.recentActions);\n if (recentActions) {\n parts.push(recentActions);\n }\n\n // 2b. Decisions — pending questions requiring supervisor response\n const pendingDecisions = buildPendingDecisionsSection(opts.pendingDecisions);\n if (pendingDecisions) {\n parts.push(pendingDecisions);\n }\n\n const answeredDecisions = buildAnsweredDecisionsSection(opts.answeredDecisions);\n if (answeredDecisions) {\n parts.push(answeredDecisions);\n }\n\n // 3. Knowledge — accumulated memory (facts, procedures, feedback)\n parts.push(buildKnowledgeSection(opts.memories));\n\n // 4. Environment — stable infra (repos, MCP, budget)\n parts.push(...buildEnvironmentSections(opts));\n\n // 5. Events — the \"query\" (last = highest attention per Anthropic guidelines)\n parts.push(`Events:\\n${buildEventsSection(opts.grouped)}`);\n\n return `<context>\\n${parts.join(\"\\n\\n\")}\\n</context>`;\n}\n\n/**\n * Build a lighter context for compaction heartbeats.\n * No active runs, no recent actions, no events — just memory for cleanup review.\n */\nfunction buildCompactionContext(opts: PromptOptions): string {\n const parts: string[] = [];\n\n parts.push(buildFocusSection(opts.memories));\n parts.push(buildKnowledgeSection(opts.memories));\n\n const workQueue = buildWorkQueueSection(opts.memories);\n if (workQueue) {\n parts.push(workQueue);\n }\n\n parts.push(...buildEnvironmentSections(opts));\n\n return `<context>\\n${parts.join(\"\\n\\n\")}\\n</context>`;\n}\n\n/**\n * Build the base instruction parts shared by all prompt variants.\n * Order: principles \\u2192 lifecycle \\u2192 reporting \\u2192 memory \\u2192 custom \\u2192 (caller adds directive last)\n */\nfunction buildBaseInstructions(\n opts: PromptOptions,\n options: { includeExamples: boolean },\n): string[] {\n const parts: string[] = [];\n parts.push(OPERATING_PRINCIPLES);\n parts.push(HEARTBEAT_RULES);\n parts.push(REPORTING_RULES);\n parts.push(buildMemoryRulesCore(opts.supervisorDir));\n\n if (options.includeExamples) {\n parts.push(buildMemoryRulesExamples(opts.supervisorDir));\n }\n\n if (opts.customInstructions) {\n parts.push(`### Custom instructions\\n${opts.customInstructions}`);\n }\n\n return parts;\n}\n\nfunction wrapInstructions(parts: string[]): string {\n return `<instructions>\\n${parts.join(\"\\n\\n\")}\\n</instructions>`;\n}\n\n// ─── Context section builders ───────────────────────────\n\nfunction buildEnvironmentSections(opts: PromptOptions): string[] {\n const parts: string[] = [];\n\n if (opts.repos.length > 0) {\n const repoList = opts.repos.map((r) => `- ${r.path} (branch: ${r.defaultBranch})`).join(\"\\n\");\n parts.push(`Repositories:\\n${repoList}`);\n }\n\n if (opts.mcpServerNames.length > 0) {\n const mcpList = opts.mcpServerNames.map((n) => `- ${n}`).join(\"\\n\");\n parts.push(`Integrations (MCP):\\n${mcpList}`);\n }\n\n parts.push(\n `Budget: $${opts.budgetStatus.todayUsd.toFixed(2)} / $${opts.budgetStatus.capUsd.toFixed(2)} (${opts.budgetStatus.remainingPct.toFixed(0)}% remaining)`,\n );\n\n return parts;\n}\n\n/**\n * Build the knowledge section: facts, procedures, and feedback.\n * Focus is excluded — it's rendered separately at context top level.\n */\nfunction buildKnowledgeSection(memories: MemoryEntry[]): string {\n const factEntries = memories.filter((m) => m.type === \"fact\");\n const procedureEntries = memories.filter((m) => m.type === \"procedure\");\n const feedbackEntries = memories.filter((m) => m.type === \"feedback\");\n\n const parts: string[] = [];\n\n // Known facts — grouped by scope with staleness signal\n if (factEntries.length > 0) {\n const byScope = new Map<string, MemoryEntry[]>();\n for (const m of factEntries) {\n const scope = m.scope === \"global\" ? \"global\" : (m.scope.split(\"/\").pop() ?? m.scope);\n const group = byScope.get(scope) ?? [];\n group.push(m);\n byScope.set(scope, group);\n }\n\n const scopeSections: string[] = [];\n for (const [scope, entries] of byScope) {\n const oldestAccess = Math.min(\n ...entries.map((m) => Date.now() - new Date(m.lastAccessedAt).getTime()),\n );\n const daysAgo = Math.floor(oldestAccess / 86_400_000);\n const staleHint = daysAgo >= 5 ? ` (last accessed ${daysAgo}d ago)` : \"\";\n const lines = entries\n .map((m) => {\n const confidence = m.accessCount >= 3 ? \"\" : \" (unconfirmed)\";\n return ` - ${m.content}${confidence}`;\n })\n .join(\"\\n\");\n scopeSections.push(` [${scope}]${staleHint} (${entries.length})\\n${lines}`);\n }\n parts.push(`Known facts:\\n${scopeSections.join(\"\\n\")}`);\n }\n\n // Procedures\n if (procedureEntries.length > 0) {\n const lines = procedureEntries.map((m) => `- ${m.content}`).join(\"\\n\");\n parts.push(`Procedures:\\n${lines}`);\n }\n\n // Recurring feedback\n if (feedbackEntries.length > 0) {\n const lines = feedbackEntries\n .map((m) => `- [${m.category ?? \"general\"}] ${m.content}`)\n .join(\"\\n\");\n parts.push(`Recurring review issues:\\n${lines}`);\n }\n\n return parts.join(\"\\n\\n\");\n}\n\n// ─── Work queue (tasks) ─────────────────────────────────\n\nconst DONE_OUTCOMES = new Set([\"done\", \"abandoned\"]);\nconst MAX_TASKS = 15;\n\ninterface TaskGroup {\n initiative: string | null;\n tasks: MemoryEntry[];\n}\n\nexport function buildWorkQueueSection(memories: MemoryEntry[]): string {\n const tasks = memories.filter((m) => m.type === \"task\" && !DONE_OUTCOMES.has(m.outcome ?? \"\"));\n const doneCount = countDoneTasks(memories);\n\n if (tasks.length === 0) {\n if (doneCount > 0) {\n return `Work queue (0 remaining, ${doneCount} done) \\u2014 all tasks complete. Pick up new work or wait for events.`;\n }\n return \"\";\n }\n\n const groups = groupTasksByInitiative(tasks);\n const lines = renderTaskGroups(groups);\n\n if (tasks.length > MAX_TASKS) {\n lines.push(` ... and ${tasks.length - MAX_TASKS} more pending`);\n }\n\n const header = `Work queue (${tasks.length} remaining, ${doneCount} done) \\u2014 dispatch the next eligible task:`;\n return `${header}\\n${lines.join(\"\\n\")}`;\n}\n\nfunction countDoneTasks(memories: MemoryEntry[]): number {\n return memories.filter((m) => m.type === \"task\" && DONE_OUTCOMES.has(m.outcome ?? \"\")).length;\n}\n\nfunction groupTasksByInitiative(tasks: MemoryEntry[]): TaskGroup[] {\n const initiativeMap = new Map<string, MemoryEntry[]>();\n const noInitiative: MemoryEntry[] = [];\n\n for (const task of tasks) {\n const tag = task.tags.find((t) => t.startsWith(\"initiative:\"));\n if (tag) {\n const key = tag.slice(\"initiative:\".length);\n const group = initiativeMap.get(key) ?? [];\n group.push(task);\n initiativeMap.set(key, group);\n } else {\n noInitiative.push(task);\n }\n }\n\n const groups: TaskGroup[] = [];\n for (const [initiative, taskList] of initiativeMap) {\n groups.push({ initiative, tasks: taskList });\n }\n if (noInitiative.length > 0) {\n groups.push({ initiative: null, tasks: noInitiative });\n }\n return groups;\n}\n\nconst SEVERITY_ORDER: Record<string, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\nfunction bySeverity(a: MemoryEntry, b: MemoryEntry): number {\n const aOrder = SEVERITY_ORDER[a.severity ?? \"medium\"] ?? 2;\n const bOrder = SEVERITY_ORDER[b.severity ?? \"medium\"] ?? 2;\n return aOrder - bOrder;\n}\n\nfunction partitionTasks(tasks: MemoryEntry[]): {\n active: MemoryEntry[];\n blocked: MemoryEntry[];\n pending: MemoryEntry[];\n} {\n const active: MemoryEntry[] = [];\n const blocked: MemoryEntry[] = [];\n const pending: MemoryEntry[] = [];\n for (const t of tasks) {\n if (t.outcome === \"in_progress\") active.push(t);\n else if (t.outcome === \"blocked\") blocked.push(t);\n else pending.push(t);\n }\n return { active, blocked, pending };\n}\n\nfunction renderInitiativeSummary(group: TaskGroup): string {\n const { active, pending } = partitionTasks(group.tasks);\n const nextEligible = [...pending].sort(bySeverity)[0];\n const cat = nextEligible?.category ? ` -> ${nextEligible.category}` : \"\";\n const nextLabel = nextEligible\n ? ` (next: ${nextEligible.content.slice(0, 30)}${nextEligible.content.length > 30 ? \"...\" : \"\"} [${nextEligible.severity ?? \"medium\"}])`\n : \"\";\n return `[${group.initiative}] ${active.length} active, ${pending.length} pending${nextLabel}${cat}`;\n}\n\nfunction renderCompactInitiative(group: TaskGroup, lines: string[], rendered: number): number {\n lines.push(` ${renderInitiativeSummary(group)}`);\n\n const { active, blocked, pending } = partitionTasks(group.tasks);\n const nextEligible = [...pending].sort(bySeverity)[0];\n\n for (const task of [...active, ...blocked]) {\n if (rendered >= MAX_TASKS) break;\n lines.push(` ${formatTaskLine(task)}`);\n rendered++;\n }\n\n // Show next eligible pending if no active/blocked tasks\n if (nextEligible && active.length === 0 && blocked.length === 0 && rendered < MAX_TASKS) {\n lines.push(` ${formatTaskLine(nextEligible)}`);\n rendered++;\n }\n\n return rendered;\n}\n\nfunction renderFlatGroup(\n group: TaskGroup,\n showHeader: boolean,\n lines: string[],\n rendered: number,\n): number {\n if (showHeader && group.initiative) {\n lines.push(` [${group.initiative}]`);\n }\n for (const task of group.tasks) {\n if (rendered >= MAX_TASKS) break;\n lines.push(` ${formatTaskLine(task)}`);\n rendered++;\n }\n return rendered;\n}\n\nfunction renderTaskGroups(groups: TaskGroup[]): string[] {\n const lines: string[] = [];\n let rendered = 0;\n\n for (const group of groups) {\n if (rendered >= MAX_TASKS) break;\n\n const useCompactMode = group.initiative && group.tasks.length >= 3;\n if (useCompactMode) {\n rendered = renderCompactInitiative(group, lines, rendered);\n } else {\n const showHeader = group.initiative !== null && groups.length > 1;\n rendered = renderFlatGroup(group, showHeader, lines, rendered);\n }\n }\n\n return lines;\n}\n\nfunction formatTaskLine(task: MemoryEntry): string {\n const marker = formatTaskMarker(task.outcome);\n const severity = task.severity ? `[${task.severity}] ` : \"\";\n const scope = task.scope !== \"global\" ? ` (${getBasename(task.scope)})` : \"\";\n const run = task.runId ? ` [run ${task.runId.slice(0, 8)}]` : \"\";\n const cat = task.category ? ` \\u2192 ${task.category}` : \"\";\n return `${marker} ${severity}${task.content}${scope}${run}${cat}`;\n}\n\nfunction formatTaskMarker(outcome: string | undefined): string {\n switch (outcome) {\n case \"in_progress\":\n return \"[ACTIVE]\";\n case \"blocked\":\n return \"[BLOCKED]\";\n default:\n return \"\\u25cb\";\n }\n}\n\nfunction getBasename(scopePath: string): string {\n const parts = scopePath.split(\"/\");\n return parts[parts.length - 1] || scopePath;\n}\n\n// ─── Recent actions ─────────────────────────────────────\n\nconst SIGNIFICANT_TYPES = new Set([\"decision\", \"action\", \"dispatch\", \"error\"]);\n\nfunction buildRecentActionsSection(entries: ActivityEntry[]): string {\n const significant = entries.filter((e) => SIGNIFICANT_TYPES.has(e.type));\n if (significant.length === 0) return \"\";\n\n const lines = significant.map((e) => {\n const ago = formatTimeAgo(Date.now() - new Date(e.timestamp).getTime());\n return `- [${e.type}] ${e.summary} (${ago})`;\n });\n\n return `Recent actions (your last heartbeats):\\n${lines.join(\"\\n\")}`;\n}\n\nfunction formatTimeAgo(ms: number): string {\n if (ms < 60_000) return \"just now\";\n const minutes = Math.floor(ms / 60_000);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h${minutes % 60}m ago`;\n return `${Math.floor(hours / 24)}d ago`;\n}\n\n// ─── Events ─────────────────────────────────────────────\n\nfunction buildEventsSection(grouped: GroupedEvents): string {\n const { messages, webhooks, runCompletions } = grouped;\n const totalEvents = messages.length + webhooks.length + runCompletions.length;\n\n if (totalEvents === 0) {\n return \"No new events.\";\n }\n\n const parts: string[] = [];\n for (const msg of messages) {\n const countSuffix = msg.count > 1 ? ` (x${msg.count})` : \"\";\n parts.push(`Message from ${msg.from}${countSuffix}: ${msg.text}`);\n }\n for (const evt of webhooks) {\n parts.push(formatEvent(evt));\n }\n for (const evt of runCompletions) {\n parts.push(formatEvent(evt));\n }\n return `${totalEvents} pending event(s):\\n${parts.join(\"\\n\\n\")}`;\n}\n\nfunction formatEvent(event: QueuedEvent): string {\n switch (event.kind) {\n case \"webhook\":\n return `Webhook [${event.data.source ?? \"unknown\"}] ${event.data.event ?? \"\"}\\n\\`\\`\\`json\\n${JSON.stringify(event.data.payload ?? {}, null, 2)}\\n\\`\\`\\``;\n case \"message\":\n return `Message from ${event.data.from}: ${event.data.text}`;\n case \"run_complete\":\n return `Run completed: ${event.runId} (check with \\`neo runs\\`)`;\n case \"internal\":\n return `Internal event: ${event.eventKind}`;\n }\n}\n\n// ─── Event count helper ─────────────────────────────────\n\nfunction countEvents(grouped: GroupedEvents): number {\n return grouped.messages.length + grouped.webhooks.length + grouped.runCompletions.length;\n}\n\n// ─── Idle prompt (minimal — no events, no runs, no tasks) ─\n\n/**\n * Check if this heartbeat has nothing to do.\n */\nexport function isIdleHeartbeat(opts: PromptOptions): boolean {\n const hasWork = buildWorkQueueSection(opts.memories) !== \"\";\n return countEvents(opts.grouped) === 0 && opts.activeRuns.length === 0 && !hasWork;\n}\n\n/**\n * Build the idle prompt.\n * Used when there are no events, no active runs, and no pending tasks.\n * If there are pending decisions, surfaces them. Otherwise, yields.\n */\nexport function buildIdlePrompt(opts: StandardPromptOptions): string {\n const budgetLine = `Budget: $${opts.budgetStatus.todayUsd.toFixed(2)} / $${opts.budgetStatus.capUsd.toFixed(2)} (${opts.budgetStatus.remainingPct.toFixed(0)}% remaining)`;\n const hasRepos = opts.repos.length > 0;\n const hasBudget = opts.budgetStatus.remainingPct > 10;\n // Use hasPendingDecisions (always reflects reality) rather than pendingDecisions.length\n // (which is empty in non-autoDecide mode even when decisions exist).\n const hasPendingDecisions = opts.hasPendingDecisions ?? (opts.pendingDecisions?.length ?? 0) > 0;\n\n // If no repos or no budget, just yield\n if (!hasRepos || !hasBudget) {\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n</context>\n\n<directive>\nNothing to do. Run \\`neo log discovery \"idle\"\\` and yield. Do not produce any other output.\n</directive>`;\n }\n\n const repoList = opts.repos.map((r) => `- ${r.path} (branch: ${r.defaultBranch})`).join(\"\\n\");\n\n // If there are pending decisions from a previous scout\n if (hasPendingDecisions) {\n const pendingSection = buildPendingDecisionsSection(opts.pendingDecisions);\n\n // In autoDecide mode, supervisor should answer decisions instead of waiting\n if (opts.autoDecide) {\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\n${pendingSection}\n\nRepositories:\n${repoList}\n</context>\n\n<reference>\n${getCommandsSection(opts.heartbeatCount)}\n</reference>\n\n<directive>\nIdle — but there are pending decisions to resolve. You are in **autoDecide** mode: answer each pending decision now using your best engineering judgment, then yield. You MAY merge branches when PRs are ready (CI green, reviews approved).\n</directive>`;\n }\n\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\n${pendingSection}\n\nRepositories:\n${repoList}\n</context>\n\n<directive>\nIdle — but there are pending decisions awaiting user response.\nRun \\`neo log discovery \"idle — waiting on ${String(opts.pendingDecisions?.length ?? 0)} pending decision(s)\"\\` and yield.\n</directive>`;\n }\n\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\nRepositories:\n${repoList}\n</context>\n\n<directive>\nNothing to do. Run \\`neo log discovery \"idle\"\\` and yield. Do not produce any other output.\n</directive>`;\n}\n\n// ─── Standard prompt ────────────────────────────────────\n\n/**\n * Build the standard heartbeat prompt (4 out of 5 heartbeats).\n *\n * Structure (Anthropic best practices: data top, instructions bottom):\n * <role> — Identity only\n * <context> — Focus \\u2192 work state \\u2192 knowledge \\u2192 environment \\u2192 events (query last)\n * <reference> — Command documentation\n * <instructions> — Principles \\u2192 lifecycle \\u2192 reporting \\u2192 memory \\u2192 directive\n */\nexport function buildStandardPrompt(opts: StandardPromptOptions): string {\n const instructionParts = buildBaseInstructions(opts, { includeExamples: false });\n const hasEvents = countEvents(opts.grouped) > 0;\n\n instructionParts.push(\n hasEvents\n ? \"Process events, dispatch eligible work, yield. Each heartbeat costs ~$0.10 \\u2014 be efficient.\"\n : \"No events. If pending work exists, dispatch it. Otherwise yield immediately.\",\n );\n\n return [\n buildRoleSection(opts.heartbeatCount),\n buildFullContext(opts),\n buildReferenceSection(opts.heartbeatCount),\n wrapInstructions(instructionParts),\n ].join(\"\\n\\n\");\n}\n\n// ─── Consolidation prompt ────────────────────────────────\n\n/**\n * Build the consolidation heartbeat prompt (1 out of 5 heartbeats).\n */\nexport function buildConsolidationPrompt(opts: ConsolidationPromptOptions): string {\n const instructionParts = buildBaseInstructions(opts, { includeExamples: true });\n\n instructionParts.push(\n `### Consolidation\nThis is a CONSOLIDATION heartbeat.\n\n**Idle guard**: if there are NO active runs AND no new events since last consolidation, log \"idle, no changes\" and yield immediately. Do NOT re-validate facts you already reviewed.\n\nIf there IS active work, your job:\n\n1. **Review memory** \\u2014 check facts and procedures for accuracy. Remove outdated entries. Resolve contradictions (keep newer). Remove facts about completed work (merged PRs, finished initiatives).\n2. **Update focus** \\u2014 rewrite focus using the MANDATORY structured format (ACTIVE/PENDING/WAITING/PROCESSED). Remove resolved items. Add new context.\n3. **Pattern escalation** \\u2014 if agents hit the same issue 3+ times (check recent actions), write a \\`procedure\\` to prevent recurrence.\n4. **Prune completed work** \\u2014 if a PR is merged or an initiative is done, forget related facts that are no longer actionable. Keep only reusable architectural truths.\n5. **Prune done tasks** \\u2014 forget tasks with outcome \\`done\\` or \\`abandoned\\` older than 7 days.`,\n );\n\n return [\n buildRoleSection(opts.heartbeatCount, \"CONSOLIDATION\"),\n buildFullContext(opts),\n buildReferenceSection(opts.heartbeatCount),\n wrapInstructions(instructionParts),\n ].join(\"\\n\\n\");\n}\n\n// ─── Compaction prompt ──────────────────────────────────\n\n/**\n * Build the compaction heartbeat prompt (every ~50 heartbeats).\n */\nexport function buildCompactionPrompt(opts: ConsolidationPromptOptions): string {\n const notesDir = `${opts.supervisorDir}/notes`;\n const instructionParts = buildBaseInstructions(opts, { includeExamples: true });\n\n instructionParts.push(`### Compaction\nThis is a COMPACTION heartbeat. Deep-clean your ENTIRE memory.\n\n1. **Remove stale facts** \\u2014 facts >7 days old with no recent reinforcement. Check the \"(last accessed Xd ago)\" hints in the facts section.\n2. **Remove completed-work facts** \\u2014 if all PRs for a repo initiative are merged/closed, forget related facts. Keep only reusable architectural truths (build system, CI config, tooling).\n3. **Remove trivial facts** \\u2014 file counts, line numbers, structural details that \\`ls\\` or \\`cat package.json\\` can answer. These waste context.\n4. **Merge duplicates** \\u2014 combine similar facts within the same scope into one.\n5. **Clean up focus** \\u2014 forget resolved items, rewrite remaining in structured format.\n6. **Prune done tasks** \\u2014 forget tasks with outcome \\`done\\` or \\`abandoned\\` older than 7 days.\n7. **Delete completed notes** from \\`${notesDir}/\\` directory.\n8. **Stay under 15 facts per scope** \\u2014 prioritize facts that affect dispatch decisions.\n\nFlag contradictions: if two facts contradict, keep the newer one.\n\n\\`\\`\\`bash\nneo memory list --type fact\nneo memory forget <stale-id>\n\\`\\`\\``);\n\n return [\n buildRoleSection(opts.heartbeatCount, \"COMPACTION\"),\n buildCompactionContext(opts),\n buildReferenceSection(opts.heartbeatCount),\n wrapInstructions(instructionParts),\n ].join(\"\\n\\n\");\n}\n","import { z } from \"zod\";\n\n// ─── Supervisor started event ────────────────────────────\n\nexport const supervisorStartedEventSchema = z.object({\n type: z.literal(\"supervisor_started\"),\n supervisorId: z.string(),\n startedAt: z.string().datetime(),\n});\n\nexport type SupervisorStartedEvent = z.infer<typeof supervisorStartedEventSchema>;\n\n// ─── Heartbeat event ─────────────────────────────────────\n\nexport const heartbeatEventSchema = z.object({\n type: z.literal(\"heartbeat\"),\n supervisorId: z.string(),\n heartbeatNumber: z.number().int().min(0),\n timestamp: z.string().datetime(),\n runsActive: z.number().int().min(0),\n budget: z.object({\n todayUsd: z.number().min(0),\n limitUsd: z.number().min(0),\n }),\n});\n\nexport type HeartbeatEvent = z.infer<typeof heartbeatEventSchema>;\n\n// ─── Run dispatched event ────────────────────────────────\n\nexport const runDispatchedEventSchema = z.object({\n type: z.literal(\"run_dispatched\"),\n supervisorId: z.string(),\n runId: z.string(),\n agent: z.string(),\n repo: z.string(),\n branch: z.string(),\n prompt: z.string().max(500), // truncated\n});\n\nexport type RunDispatchedEvent = z.infer<typeof runDispatchedEventSchema>;\n\n// ─── Run completed event ─────────────────────────────────\n\nexport const runCompletedEventSchema = z.object({\n type: z.literal(\"run_completed\"),\n supervisorId: z.string(),\n runId: z.string(),\n status: z.enum([\"completed\", \"failed\", \"cancelled\"]),\n output: z.string().max(1000).optional(), // truncated\n costUsd: z.number().min(0),\n durationMs: z.number().int().min(0),\n});\n\nexport type RunCompletedEvent = z.infer<typeof runCompletedEventSchema>;\n\n// ─── Supervisor stopped event ────────────────────────────\n\nexport const supervisorStoppedEventSchema = z.object({\n type: z.literal(\"supervisor_stopped\"),\n supervisorId: z.string(),\n stoppedAt: z.string().datetime(),\n reason: z.enum([\"shutdown\", \"budget_exceeded\", \"error\", \"manual\"]),\n});\n\nexport type SupervisorStoppedEvent = z.infer<typeof supervisorStoppedEventSchema>;\n\n// ─── Union of all webhook events ─────────────────────────\n\nexport const supervisorWebhookEventSchema = z.discriminatedUnion(\"type\", [\n supervisorStartedEventSchema,\n heartbeatEventSchema,\n runDispatchedEventSchema,\n runCompletedEventSchema,\n supervisorStoppedEventSchema,\n]);\n\nexport type SupervisorWebhookEvent = z.infer<typeof supervisorWebhookEventSchema>;\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { appendFile } from \"node:fs/promises\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { WebhookIncomingEvent } from \"./schemas.js\";\n\nconst MAX_BODY_SIZE = 1024 * 1024; // 1MB\n\ninterface WebhookServerOptions {\n port: number;\n secret?: string | undefined;\n eventsPath: string;\n onEvent: (event: WebhookIncomingEvent) => void;\n getHealth: () => Record<string, unknown>;\n}\n\n/**\n * Minimal HTTP server for receiving incoming webhooks.\n *\n * Routes:\n * POST /webhook — receive any JSON payload, persist to disk, push to queue\n * GET /health — liveness check with daemon status\n *\n * Uses raw http.createServer — zero external dependencies.\n */\nexport class WebhookServer {\n private server: Server | null = null;\n private readonly port: number;\n private readonly secret: string | undefined;\n private readonly eventsPath: string;\n private readonly onEvent: (event: WebhookIncomingEvent) => void;\n private readonly getHealth: () => Record<string, unknown>;\n\n constructor(options: WebhookServerOptions) {\n this.port = options.port;\n this.secret = options.secret;\n this.eventsPath = options.eventsPath;\n this.onEvent = options.onEvent;\n this.getHealth = options.getHealth;\n }\n\n async start(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n this.server = createServer((req, res) => {\n this.handleRequest(req, res).catch((err) => {\n this.sendJson(res, 500, { error: \"Internal server error\", detail: String(err) });\n });\n });\n\n this.server.on(\"error\", reject);\n\n this.server.listen(this.port, () => {\n resolve();\n });\n });\n }\n\n async stop(): Promise<void> {\n return new Promise<void>((resolve) => {\n if (!this.server) {\n resolve();\n return;\n }\n this.server.close(() => resolve());\n });\n }\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url ?? \"/\";\n\n if (req.method === \"GET\" && url === \"/health\") {\n this.sendJson(res, 200, this.getHealth());\n return;\n }\n\n if (req.method === \"POST\" && url === \"/webhook\") {\n await this.handleWebhook(req, res);\n return;\n }\n\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n\n private async handleWebhook(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // Read body first (needed for both parsing and HMAC verification)\n const body = await this.readBody(req);\n if (body === null) {\n this.sendJson(res, 413, { error: \"Payload too large (max 1MB)\" });\n return;\n }\n\n // Validate HMAC signature if secret is configured\n if (this.secret) {\n const signature = req.headers[\"x-neo-signature\"] as string | undefined;\n if (!signature) {\n this.sendJson(res, 401, { error: \"Missing X-Neo-Signature header\" });\n return;\n }\n\n const expected = createHmac(\"sha256\", this.secret).update(body).digest(\"hex\");\n const expectedBuf = Buffer.from(expected, \"utf-8\");\n const actualBuf = Buffer.from(signature, \"utf-8\");\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {\n this.sendJson(res, 403, { error: \"Invalid signature\" });\n return;\n }\n }\n\n // Parse JSON\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(body) as Record<string, unknown>;\n } catch {\n this.sendJson(res, 400, { error: \"Invalid JSON\" });\n return;\n }\n\n const event: WebhookIncomingEvent = {\n id: typeof parsed.id === \"string\" ? parsed.id : undefined,\n source: typeof parsed.source === \"string\" ? parsed.source : undefined,\n event: typeof parsed.event === \"string\" ? parsed.event : undefined,\n payload: (parsed.payload as Record<string, unknown> | undefined) ?? parsed,\n receivedAt: new Date().toISOString(),\n };\n\n // Disk-first: persist before pushing to memory\n await appendFile(this.eventsPath, `${JSON.stringify(event)}\\n`, \"utf-8\");\n\n // Push to in-memory queue\n this.onEvent(event);\n\n this.sendJson(res, 200, { ok: true, id: event.id });\n }\n\n private readBody(req: IncomingMessage): Promise<string | null> {\n return new Promise((resolve) => {\n const chunks: Buffer[] = [];\n let size = 0;\n\n req.on(\"data\", (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_SIZE) {\n resolve(null);\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n\n req.on(\"end\", () => {\n resolve(Buffer.concat(chunks).toString(\"utf-8\"));\n });\n\n req.on(\"error\", () => resolve(null));\n });\n }\n\n private sendJson(res: ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(data));\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getRunsDir } from \"@/paths\";\nimport type { PersistedRun } from \"@/types\";\nimport type {\n ActivityEntry,\n ActivityQueryOptions,\n SupervisorDaemonState,\n SupervisorStatus,\n} from \"./schemas.js\";\nimport { activityEntrySchema, supervisorDaemonStateSchema } from \"./schemas.js\";\n\nconst STATE_FILE = \"state.json\";\nconst ACTIVITY_FILE = \"activity.jsonl\";\n\n/**\n * Reads supervisor status from the daemon state file.\n * Returns null if the supervisor is not running or state file doesn't exist.\n */\nexport class StatusReader {\n readonly dataDir: string;\n private readonly statePath: string;\n private readonly activityPath: string;\n\n constructor(dataDir: string) {\n this.dataDir = dataDir;\n this.statePath = path.join(dataDir, STATE_FILE);\n this.activityPath = path.join(dataDir, ACTIVITY_FILE);\n }\n\n /**\n * Read and parse supervisor status from disk.\n * Returns null if the state file doesn't exist (supervisor not running).\n */\n async getStatus(): Promise<SupervisorStatus | null> {\n let raw: string;\n try {\n raw = await readFile(this.statePath, \"utf-8\");\n } catch (err) {\n // File not found — supervisor not running\n console.debug(\n `[StatusReader] State file not found: ${err instanceof Error ? err.message : String(err)}`,\n );\n return null;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n // Malformed JSON — treat as not running\n console.debug(\n `[StatusReader] Malformed state JSON: ${err instanceof Error ? err.message : String(err)}`,\n );\n return null;\n }\n\n const result = supervisorDaemonStateSchema.safeParse(parsed);\n if (!result.success) {\n // Schema validation failed — state file is incompatible\n return null;\n }\n\n const daemon = result.data;\n\n // Map daemon status to API status\n const statusMap: Record<SupervisorDaemonState[\"status\"], SupervisorStatus[\"status\"]> = {\n running: \"running\",\n draining: \"stopping\",\n stopped: \"idle\",\n };\n\n // Read recent activity for summary\n const recentActivity = this.queryActivity({ limit: 5 });\n\n // Count active runs from .neo/runs/\n const activeRunCount = await this.countActiveRuns();\n\n return {\n pid: daemon.pid,\n sessionId: daemon.sessionId,\n startedAt: daemon.startedAt,\n heartbeatCount: daemon.heartbeatCount,\n totalCostUsd: daemon.totalCostUsd,\n todayCostUsd: daemon.todayCostUsd,\n status: statusMap[daemon.status],\n lastHeartbeat: daemon.lastHeartbeat ?? daemon.startedAt,\n activeRunCount,\n recentActivitySummary: recentActivity.map((e) => `[${e.type}] ${e.summary}`),\n };\n }\n\n /**\n * Query activity entries with optional filtering.\n * Returns empty array if the activity file doesn't exist or is empty.\n */\n queryActivity(options: ActivityQueryOptions = {}): ActivityEntry[] {\n const { limit = 50, offset = 0, type, since, until } = options;\n\n let content: string;\n try {\n content = readFileSync(this.activityPath, \"utf-8\");\n } catch (err) {\n // File not found — no activity yet\n console.debug(\n `[StatusReader] Activity file not found: ${err instanceof Error ? err.message : String(err)}`,\n );\n return [];\n }\n\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n let entries: ActivityEntry[] = [];\n\n // Parse all valid entries\n for (const line of lines) {\n try {\n const parsed = JSON.parse(line);\n const result = activityEntrySchema.safeParse(parsed);\n if (result.success) {\n entries.push(result.data);\n }\n } catch (err) {\n // Skip malformed JSONL line\n console.debug(\n `[StatusReader] Skipping malformed activity line: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // Apply type filter\n if (type) {\n entries = entries.filter((e) => e.type === type);\n }\n\n // Apply date range filters\n if (since) {\n const sinceDate = new Date(since);\n entries = entries.filter((e) => new Date(e.timestamp) >= sinceDate);\n }\n\n if (until) {\n const untilDate = new Date(until);\n entries = entries.filter((e) => new Date(e.timestamp) <= untilDate);\n }\n\n // Apply offset and limit\n return entries.slice(offset, offset + limit);\n }\n\n /**\n * Count runs with status \"running\" from .neo/runs/.\n * Fails silently — returns 0 if the runs directory doesn't exist.\n */\n private async countActiveRuns(): Promise<number> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return 0;\n\n try {\n const runFiles = await this.collectRunFiles(runsDir);\n let count = 0;\n for (const filePath of runFiles) {\n if (await this.isRunning(filePath)) count++;\n }\n return count;\n } catch (err) {\n // Runs directory unreadable or corrupted\n console.debug(\n `[StatusReader] Failed to count active runs: ${err instanceof Error ? err.message : String(err)}`,\n );\n return 0;\n }\n }\n\n /**\n * Collect all run JSON files from the runs directory tree.\n * Searches both top-level and repo subdirectories.\n */\n private async collectRunFiles(runsDir: string): Promise<string[]> {\n const entries = await readdir(runsDir, { withFileTypes: true });\n const jsonFiles: string[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const subDir = path.join(runsDir, entry.name);\n const subFiles = await readdir(subDir);\n for (const f of subFiles) {\n if (this.isRunFile(f)) {\n jsonFiles.push(path.join(subDir, f));\n }\n }\n } else if (this.isRunFile(entry.name)) {\n jsonFiles.push(path.join(runsDir, entry.name));\n }\n }\n\n return jsonFiles;\n }\n\n /**\n * Check if a filename is a run file (JSON but not dispatch).\n */\n private isRunFile(filename: string): boolean {\n return filename.endsWith(\".json\") && !filename.endsWith(\".dispatch.json\");\n }\n\n /**\n * Check if a run file represents an active (running) run.\n */\n private async isRunning(filePath: string): Promise<boolean> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n return run.status === \"running\";\n } catch (err) {\n // Run file corrupted or unreadable\n console.debug(\n `[StatusReader] Failed to read run file ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return false;\n }\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { removeSessionClone } from \"@/isolation/clone\";\nimport type { PersistedRun } from \"@/types\";\nimport type { ActivityLog } from \"./activity-log.js\";\n\n// ─── Constants ──────────────────────────────────────────\n\nconst GRACEFUL_TIMEOUT_MS = 30_000; // 30 seconds for graceful shutdown\nconst FORCE_KILL_DELAY_MS = 5_000; // 5 seconds before SIGKILL after SIGTERM\n\n// ─── Types ──────────────────────────────────────────────\n\nexport interface ShutdownOptions {\n /** Activity log for recording shutdown events */\n activityLog?: ActivityLog | undefined;\n /** Callback to invoke before shutdown begins */\n onShutdownStart?: () => void | Promise<void>;\n /** Callback to invoke after shutdown completes */\n onShutdownComplete?: () => void | Promise<void>;\n /** Timeout in milliseconds for graceful shutdown (default: 30s) */\n timeoutMs?: number | undefined;\n}\n\nexport interface ShutdownContext {\n /** Active child processes to terminate */\n childProcesses: Set<ChildProcess>;\n /** Active session clone paths to clean up */\n sessionPaths: Set<string>;\n /** Pending write operations to flush */\n pendingWrites: Set<Promise<void>>;\n /** Runs directory for marking runs as failed */\n runsDir?: string | undefined;\n}\n\nexport type ShutdownHandler = () => Promise<void>;\n\n// ─── ShutdownManager ────────────────────────────────────\n\n/**\n * Manages graceful shutdown for daemon and supervisor processes.\n *\n * Handles:\n * - SIGTERM and SIGINT signals\n * - Session clone cleanup\n * - Flushing pending writes\n * - Graceful child process termination\n *\n * Usage:\n * ```ts\n * const shutdown = new ShutdownManager({ activityLog });\n * shutdown.registerChildProcess(child);\n * shutdown.registerSession('/path/to/session');\n * shutdown.trackWrite(writePromise);\n * shutdown.install();\n * ```\n */\nexport class ShutdownManager {\n private readonly options: ShutdownOptions;\n private readonly context: ShutdownContext;\n private readonly handlers: Set<ShutdownHandler> = new Set();\n private isShuttingDown = false;\n private signalHandlersInstalled = false;\n private shutdownPromise: Promise<void> | null = null;\n\n constructor(options: ShutdownOptions = {}) {\n this.options = {\n timeoutMs: GRACEFUL_TIMEOUT_MS,\n ...options,\n };\n this.context = {\n childProcesses: new Set(),\n sessionPaths: new Set(),\n pendingWrites: new Set(),\n };\n }\n\n // ─── Registration ──────────────────────────────────────\n\n /**\n * Register a child process for graceful termination during shutdown.\n */\n registerChildProcess(child: ChildProcess): void {\n this.context.childProcesses.add(child);\n child.once(\"exit\", () => {\n this.context.childProcesses.delete(child);\n });\n }\n\n /**\n * Unregister a child process (e.g., after it has been terminated elsewhere).\n */\n unregisterChildProcess(child: ChildProcess): void {\n this.context.childProcesses.delete(child);\n }\n\n /**\n * Register a session clone path for cleanup during shutdown.\n */\n registerSession(sessionPath: string): void {\n this.context.sessionPaths.add(sessionPath);\n }\n\n /**\n * Unregister a session clone (e.g., after it has been cleaned up elsewhere).\n */\n unregisterSession(sessionPath: string): void {\n this.context.sessionPaths.delete(sessionPath);\n }\n\n /**\n * Track a pending write operation to flush during shutdown.\n * The promise is automatically removed when it settles.\n */\n trackWrite(writePromise: Promise<void>): void {\n this.context.pendingWrites.add(writePromise);\n writePromise.finally(() => {\n this.context.pendingWrites.delete(writePromise);\n });\n }\n\n /**\n * Register a custom shutdown handler.\n * Handlers are called in registration order during shutdown.\n */\n registerHandler(handler: ShutdownHandler): void {\n this.handlers.add(handler);\n }\n\n /**\n * Unregister a custom shutdown handler.\n */\n unregisterHandler(handler: ShutdownHandler): void {\n this.handlers.delete(handler);\n }\n\n /**\n * Set the runs directory for marking orphaned runs as failed.\n */\n setRunsDir(dir: string): void {\n this.context.runsDir = dir;\n }\n\n // ─── Installation ──────────────────────────────────────\n\n /**\n * Install signal handlers for SIGTERM and SIGINT.\n * Safe to call multiple times; handlers are only installed once.\n */\n install(): void {\n if (this.signalHandlersInstalled) return;\n\n const handler = (signal: string) => {\n this.initiateShutdown(signal).catch((error) => {\n // biome-ignore lint/suspicious/noConsole: Intentional daemon logging for shutdown errors\n console.error(`Shutdown error (${signal}):`, error);\n process.exit(1);\n });\n };\n\n process.on(\"SIGTERM\", () => handler(\"SIGTERM\"));\n process.on(\"SIGINT\", () => handler(\"SIGINT\"));\n\n this.signalHandlersInstalled = true;\n }\n\n /**\n * Manually trigger shutdown (e.g., from a stop() method).\n * Returns a promise that resolves when shutdown is complete.\n */\n async shutdown(): Promise<void> {\n return this.initiateShutdown(\"manual\");\n }\n\n // ─── Status ────────────────────────────────────────────\n\n /**\n * Check if shutdown is in progress.\n */\n get shuttingDown(): boolean {\n return this.isShuttingDown;\n }\n\n // ─── Internal ──────────────────────────────────────────\n\n private async initiateShutdown(signal: string): Promise<void> {\n // Ensure shutdown only runs once\n if (this.isShuttingDown) {\n return this.shutdownPromise ?? Promise.resolve();\n }\n\n this.isShuttingDown = true;\n this.shutdownPromise = this.executeShutdown(signal);\n return this.shutdownPromise;\n }\n\n private async executeShutdown(signal: string): Promise<void> {\n const { activityLog, onShutdownStart, onShutdownComplete, timeoutMs } = this.options;\n\n await activityLog?.log(\"event\", `Shutdown initiated (${signal})`);\n await onShutdownStart?.();\n\n // Race shutdown tasks against timeout\n const shutdownTasks = this.runShutdownTasks();\n const timeout = new Promise<void>((resolve) => {\n setTimeout(() => {\n activityLog?.log(\"error\", `Shutdown timeout (${timeoutMs}ms) exceeded, forcing exit`);\n resolve();\n }, timeoutMs);\n });\n\n await Promise.race([shutdownTasks, timeout]);\n\n await activityLog?.log(\"event\", \"Shutdown complete\");\n await onShutdownComplete?.();\n }\n\n private async runShutdownTasks(): Promise<void> {\n const { activityLog } = this.options;\n const { childProcesses, sessionPaths, pendingWrites, runsDir } = this.context;\n\n // Phase 1: Run custom handlers\n for (const handler of this.handlers) {\n try {\n await handler();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n await activityLog?.log(\"error\", `Shutdown handler failed: ${msg}`);\n }\n }\n\n // Phase 2: Flush pending writes\n if (pendingWrites.size > 0) {\n await activityLog?.log(\"event\", `Flushing ${pendingWrites.size} pending write(s)`);\n await Promise.allSettled([...pendingWrites]);\n }\n\n // Phase 3: Mark orphaned runs as failed\n if (runsDir) {\n await this.markOrphanedRunsFailed(runsDir, activityLog);\n }\n\n // Phase 4: Terminate child processes gracefully\n if (childProcesses.size > 0) {\n await activityLog?.log(\"event\", `Terminating ${childProcesses.size} child process(es)`);\n await this.terminateChildProcesses([...childProcesses], activityLog);\n }\n\n // Phase 5: Clean up session clones\n if (sessionPaths.size > 0) {\n await activityLog?.log(\"event\", `Cleaning up ${sessionPaths.size} session clone(s)`);\n await this.cleanupSessions([...sessionPaths], activityLog);\n }\n }\n\n private async terminateChildProcesses(\n processes: ChildProcess[],\n activityLog?: ActivityLog,\n ): Promise<void> {\n const terminations = processes.map(async (child) => {\n if (child.killed || child.exitCode !== null) {\n return; // Already terminated\n }\n\n const pid = child.pid;\n\n // Send SIGTERM first\n child.kill(\"SIGTERM\");\n\n // Wait for graceful exit or force kill\n await new Promise<void>((resolve) => {\n const forceKillTimer = setTimeout(() => {\n if (!child.killed && child.exitCode === null) {\n activityLog?.log(\"event\", `Force killing child process ${pid}`);\n child.kill(\"SIGKILL\");\n }\n resolve();\n }, FORCE_KILL_DELAY_MS);\n\n child.once(\"exit\", () => {\n clearTimeout(forceKillTimer);\n resolve();\n });\n });\n });\n\n await Promise.allSettled(terminations);\n }\n\n private async cleanupSessions(paths: string[], activityLog?: ActivityLog): Promise<void> {\n const cleanups = paths.map(async (sessionPath) => {\n try {\n await removeSessionClone(sessionPath);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n await activityLog?.log(\"error\", `Failed to cleanup session clone ${sessionPath}: ${msg}`);\n }\n });\n\n await Promise.allSettled(cleanups);\n }\n\n private async markOrphanedRunsFailed(runsDir: string, activityLog?: ActivityLog): Promise<void> {\n if (!existsSync(runsDir)) return;\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const subDir = path.join(runsDir, entry.name);\n const files = await readdir(subDir);\n\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n\n const filePath = path.join(subDir, file);\n await this.markRunAsFailed(filePath, activityLog);\n }\n }\n } catch (err) {\n // Non-critical — best effort cleanup\n console.debug(\n `[ShutdownManager] Failed to mark orphaned runs: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async markRunAsFailed(filePath: string, activityLog?: ActivityLog): Promise<void> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n\n if (run.status !== \"running\") return;\n\n // Only mark as failed if this process owns the run\n if (run.pid && run.pid !== process.pid) return;\n\n run.status = \"failed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n\n await activityLog?.log(\"event\", `Marked orphaned run ${run.runId} as failed`);\n } catch (err) {\n // Non-critical — file may be corrupt or locked\n console.debug(\n `[ShutdownManager] Failed to mark run as failed in ${filePath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n\n// ─── Utility Functions ──────────────────────────────────\n\n/**\n * Create and install a shutdown manager with the given options.\n * Returns the manager for registration of resources.\n */\nexport function createShutdownManager(options: ShutdownOptions = {}): ShutdownManager {\n const manager = new ShutdownManager(options);\n manager.install();\n return manager;\n}\n\n/**\n * Wait for a child process to exit with a timeout.\n * Returns true if the process exited, false if timeout was reached.\n */\nexport function waitForExit(child: ChildProcess, timeoutMs: number): Promise<boolean> {\n return new Promise((resolve) => {\n if (child.killed || child.exitCode !== null) {\n resolve(true);\n return;\n }\n\n const timer = setTimeout(() => {\n resolve(false);\n }, timeoutMs);\n\n child.once(\"exit\", () => {\n clearTimeout(timer);\n resolve(true);\n });\n });\n}\n\n/**\n * Send SIGTERM to a child process and wait for exit, then SIGKILL if needed.\n * Returns true if the process exited gracefully, false if force killed.\n */\nexport async function terminateGracefully(\n child: ChildProcess,\n gracePeriodMs: number = FORCE_KILL_DELAY_MS,\n): Promise<boolean> {\n if (child.killed || child.exitCode !== null) {\n return true;\n }\n\n child.kill(\"SIGTERM\");\n const exited = await waitForExit(child, gracePeriodMs);\n\n if (!exited) {\n child.kill(\"SIGKILL\");\n await waitForExit(child, 1000);\n return false;\n }\n\n return true;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { getDataDir } from \"@/paths\";\n\n// ─── Webhook Entry Schema ───────────────────────────────\n\nexport const webhookEntrySchema = z.object({\n url: z.string().url(),\n events: z.array(z.string()).optional(),\n secret: z.string().optional(),\n timeoutMs: z.number().default(5000),\n createdAt: z.string().default(() => new Date().toISOString()),\n});\n\nexport type WebhookEntry = z.infer<typeof webhookEntrySchema>;\nexport type WebhookEntryInput = z.input<typeof webhookEntrySchema>;\n\n// ─── Webhooks Config Schema ─────────────────────────────\n\nconst webhooksConfigSchema = z.object({\n webhooks: z.array(webhookEntrySchema).default([]),\n});\n\ntype WebhooksConfig = z.infer<typeof webhooksConfigSchema>;\n\n// ─── File Path ──────────────────────────────────────────\n\nfunction getWebhooksConfigPath(): string {\n return path.join(getDataDir(), \"webhooks.json\");\n}\n\n// ─── Loaders ────────────────────────────────────────────\n\nasync function loadWebhooksConfig(): Promise<WebhooksConfig> {\n const configPath = getWebhooksConfigPath();\n\n if (!existsSync(configPath)) {\n return { webhooks: [] };\n }\n\n const raw = await readFile(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n return webhooksConfigSchema.parse(parsed);\n}\n\nasync function saveWebhooksConfig(config: WebhooksConfig): Promise<void> {\n const configPath = getWebhooksConfigPath();\n await mkdir(getDataDir(), { recursive: true });\n await writeFile(configPath, JSON.stringify(config, null, 2), \"utf-8\");\n}\n\n// ─── CRUD Operations ────────────────────────────────────\n\n/**\n * Add a webhook endpoint to ~/.neo/webhooks.json.\n * Deduplicates by URL.\n */\nexport async function addWebhook(input: WebhookEntryInput): Promise<WebhookEntry> {\n const config = await loadWebhooksConfig();\n const entry = webhookEntrySchema.parse(input);\n\n const existing = config.webhooks.findIndex((w) => w.url === entry.url);\n if (existing >= 0) {\n config.webhooks[existing] = entry;\n } else {\n config.webhooks.push(entry);\n }\n\n await saveWebhooksConfig(config);\n return entry;\n}\n\n/**\n * Remove a webhook endpoint by URL.\n * Returns true if removed, false if not found.\n */\nexport async function removeWebhook(url: string): Promise<boolean> {\n const config = await loadWebhooksConfig();\n const initialLength = config.webhooks.length;\n\n config.webhooks = config.webhooks.filter((w) => w.url !== url);\n\n if (config.webhooks.length === initialLength) {\n return false;\n }\n\n await saveWebhooksConfig(config);\n return true;\n}\n\n/**\n * List all configured webhooks.\n */\nexport async function listWebhooks(): Promise<WebhookEntry[]> {\n const config = await loadWebhooksConfig();\n return config.webhooks;\n}\n\n// ─── Test Webhook Payload ───────────────────────────────\n\nexport interface WebhookTestPayload {\n type: \"test\";\n timestamp: string;\n runId: string;\n status: \"test\";\n summary: string;\n}\n\nexport interface WebhookTestResult {\n url: string;\n success: boolean;\n statusCode?: number;\n error?: string;\n durationMs: number;\n}\n\n/**\n * Send a test payload to all configured webhooks.\n * Returns results for each endpoint.\n */\nexport async function testWebhooks(): Promise<WebhookTestResult[]> {\n const webhooks = await listWebhooks();\n\n if (webhooks.length === 0) {\n return [];\n }\n\n const payload: WebhookTestPayload = {\n type: \"test\",\n timestamp: new Date().toISOString(),\n runId: `test-${Date.now()}`,\n status: \"test\",\n summary: \"Test webhook from neo CLI\",\n };\n\n const results = await Promise.all(\n webhooks.map(async (webhook): Promise<WebhookTestResult> => {\n const start = Date.now();\n const body = JSON.stringify(payload);\n\n try {\n const response = await fetch(webhook.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body,\n signal: AbortSignal.timeout(webhook.timeoutMs),\n });\n\n return {\n url: webhook.url,\n success: response.ok,\n statusCode: response.status,\n durationMs: Date.now() - start,\n };\n } catch (err) {\n return {\n url: webhook.url,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n durationMs: Date.now() - start,\n };\n }\n }),\n );\n\n return results;\n}\n","export const VERSION = \"0.1.0\";\n\n// ─── Orchestrator (public API) ──────────────────────────\n\nexport { loadAgentFile } from \"@/agents/loader\";\nexport { AgentRegistry } from \"@/agents/registry\";\nexport { resolveAgent } from \"@/agents/resolver\";\nexport {\n agentConfigSchema,\n agentModelSchema,\n agentSandboxSchema,\n agentToolEntrySchema,\n agentToolSchema,\n} from \"@/agents/schema\";\nexport type {\n SemaphoreCallbacks,\n SemaphoreConfig,\n} from \"@/concurrency/semaphore\";\n// ─── Concurrency ────────────────────────────────────────\nexport { Semaphore } from \"@/concurrency/semaphore\";\nexport type {\n GlobalConfig,\n McpServerConfig,\n NeoConfig,\n RepoConfig,\n RepoConfigInput,\n} from \"@/config\";\nexport {\n addRepoToGlobalConfig,\n ConfigStore,\n globalConfigSchema,\n listReposFromGlobalConfig,\n loadConfig,\n loadGlobalConfig,\n mcpServerConfigSchema,\n neoConfigSchema,\n removeRepoFromGlobalConfig,\n repoConfigSchema,\n repoOverrideConfigSchema,\n} from \"@/config\";\n// ─── Cost ──────────────────────────────────────────────\nexport { CostJournal } from \"@/cost/journal\";\n// ─── Events ────────────────────────────────────────────\nexport {\n EventJournal,\n matchesFilter,\n NeoEventEmitter,\n WebhookDispatcher,\n} from \"@/events\";\nexport type { SessionCloneInfo } from \"@/isolation/clone\";\n// ─── Isolation ──────────────────────────────────────────\nexport {\n createSessionClone,\n listSessionClones,\n removeSessionClone,\n} from \"@/isolation/clone\";\nexport {\n createBranch,\n deleteBranch,\n fetchRemote,\n getBranchName,\n getCurrentBranch,\n pushBranch,\n pushSessionBranch,\n} from \"@/isolation/git\";\nexport type { SandboxConfig } from \"@/isolation/sandbox\";\nexport { buildSandboxConfig } from \"@/isolation/sandbox\";\nexport type { AuditLogMiddleware } from \"@/middleware/audit-log\";\n// ─── Middleware ─────────────────────────────────────────\nexport { auditLog } from \"@/middleware/audit-log\";\nexport { budgetGuard } from \"@/middleware/budget-guard\";\nexport type { MiddlewareChain, SDKHooks } from \"@/middleware/chain\";\nexport { buildMiddlewareChain, buildSDKHooks } from \"@/middleware/chain\";\nexport type { LoopDetectionMiddleware } from \"@/middleware/loop-detection\";\nexport { loopDetection } from \"@/middleware/loop-detection\";\nexport type { OrchestratorOptions } from \"@/orchestrator\";\nexport { Orchestrator } from \"@/orchestrator\";\n// ─── Paths ─────────────────────────────────────────────\nexport {\n getDataDir,\n getJournalsDir,\n getRepoRunsDir,\n getRunDispatchPath,\n getRunLogPath,\n getRunsDir,\n getSupervisorActivityPath,\n getSupervisorDecisionsPath,\n getSupervisorDir,\n getSupervisorEventsPath,\n getSupervisorInboxPath,\n getSupervisorLockPath,\n getSupervisorStatePath,\n getSupervisorsDir,\n toRepoSlug,\n} from \"@/paths\";\nexport type { ParsedOutput } from \"@/runner/output-parser\";\n// ─── Runner ────────────────────────────────────────────\nexport { parseOutput } from \"@/runner/output-parser\";\nexport type { RecoveryOptions } from \"@/runner/recovery\";\nexport { runWithRecovery } from \"@/runner/recovery\";\nexport type {\n SessionEvent,\n SessionOptions,\n SessionResult,\n} from \"@/runner/session\";\nexport { runSession, SessionError } from \"@/runner/session\";\nexport type {\n SessionExecutionConfig,\n SessionExecutionDeps,\n SessionExecutionInput,\n SessionExecutionResult,\n} from \"@/runner/session-executor\";\nexport {\n buildFullPrompt,\n buildGitStrategyInstructions,\n buildReportingInstructions,\n loadRepoInstructions,\n SessionExecutor,\n} from \"@/runner/session-executor\";\n// ─── Process utilities ─────────────────────────────────\nexport { isProcessAlive } from \"@/shared/process\";\nexport type { SupervisorState } from \"@/supervisor\";\n// ─── Supervisor (legacy) ──────────────────────────────\nexport { supervisorStateSchema } from \"@/supervisor\";\n// ─── Decisions ─────────────────────────────────────────\nexport type {\n ActivityEntry,\n ActivityQueryOptions,\n Decision,\n DecisionInput,\n DecisionOption,\n HeartbeatLoopOptions,\n InboxMessage,\n QueuedEvent,\n SupervisorDaemonOptions,\n SupervisorDaemonState,\n SupervisorStatus,\n WebhookIncomingEvent,\n} from \"@/supervisor/index\";\n// ─── Supervisor (daemon) ──────────────────────────────\nexport {\n ActivityLog,\n activityEntrySchema,\n appendLogBuffer,\n DecisionStore,\n decisionOptionSchema,\n decisionSchema,\n EventQueue,\n HeartbeatLoop,\n inboxMessageSchema,\n StatusReader,\n SupervisorDaemon,\n supervisorDaemonStateSchema,\n supervisorStatusSchema,\n WebhookServer,\n webhookIncomingEventSchema,\n} from \"@/supervisor/index\";\nexport type {\n Embedder,\n MemoryEntry,\n MemoryQuery,\n MemoryStats,\n MemoryType,\n MemoryWriteInput,\n} from \"@/supervisor/memory/index\";\n// ─── Memory ───────────────────────────────────────────\nexport { LocalEmbedder, MemoryStore } from \"@/supervisor/memory/index\";\nexport * from \"@/types\";\n// ─── Webhook Config ────────────────────────────────────\nexport type {\n WebhookEntry,\n WebhookEntryInput,\n WebhookTestPayload,\n WebhookTestResult,\n} from \"@/webhook-config\";\nexport {\n addWebhook,\n listWebhooks,\n removeWebhook,\n testWebhooks,\n webhookEntrySchema,\n} from \"@/webhook-config\";\n"],"mappings":"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","names":["path","path","resolve","existsSync","readFile","path","parseYaml","path","z","path","homedir","parseYaml","homedir","parseYaml","homedir","join","parseYaml","readFile","path","existsSync","path","mkdir","EventEmitter","appendFile","stat","JournalFileSizeError","stat","appendFile","resolve","existsSync","mkdir","readdir","execFile","resolve","promisify","execFileAsync","promisify","execFile","GIT_TIMEOUT","resolve","resolve","appendFile","mkdir","path","ensureDir","randomUUID","existsSync","mkdir","readFile","path","existsSync","mkdir","readdir","readFile","writeFile","path","mkdir","path","writeFile","existsSync","readdir","readFile","readFile","path","resolve","z","randomUUID","existsSync","path","limit","path","resolve","mkdir","randomUUID","strategy","existsSync","readdir","readFile","z","randomUUID","appendFile","readFile","writeFile","path","z","z","path","randomUUID","appendFile","readFile","writeFile","z","randomUUID","appendFile","readFile","stat","path","randomUUID","existsSync","mkdir","readFile","rm","writeFile","homedir","path","watch","readFile","writeFile","resolve","randomUUID","existsSync","readdir","readFile","writeFile","homedir","path","z","appendFile","readFile","stat","writeFile","path","path","readFile","readFile","writeFile","appendFile","z","path","randomUUID","homedir","resolve","readFile","writeFile","existsSync","readdir","createHmac","appendFile","resolve","mkdir","path","existsSync","rm","writeFile","rename","randomUUID","homedir","readFile","existsSync","readFileSync","readdir","readFile","path","ACTIVITY_FILE","path","readFile","readFileSync","existsSync","readdir","existsSync","readdir","readFile","writeFile","path","existsSync","mkdir","readFile","writeFile","path","z","z","path","existsSync","readFile","mkdir","writeFile"]}