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

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/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"]}
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/shared/time.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/entry.ts","../src/supervisor/memory/format.ts","../src/supervisor/memory/store.ts","../src/supervisor/activity-log.ts","../src/supervisor/adapters/claude.ts","../src/supervisor/child-command-parser.ts","../src/supervisor/child-spawner.ts","../src/supervisor/children-file.ts","../src/supervisor/daemon.ts","../src/supervisor/child-registry.ts","../src/supervisor/decisions.ts","../src/supervisor/event-queue.ts","../src/supervisor/heartbeat.ts","../src/supervisor/task-store.ts","../src/supervisor/directive-store.ts","../src/supervisor/failure-report.ts","../src/supervisor/heartbeat-error-boundary.ts","../src/supervisor/idle-detector.ts","../src/supervisor/log-buffer.ts","../src/supervisor/prompt-builder.ts","../src/supervisor/schemas.ts","../src/supervisor/webhookEvents.ts","../src/supervisor/webhook-server.ts","../src/supervisor/focused-loop.ts","../src/supervisor/supervisor-tools.ts","../src/supervisor/StatusReader.ts","../src/supervisor/shutdown.ts","../src/supervisor/spawn-child-tool.ts","../src/supervisor/stores/jsonl.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 // If agents have prompt paths ending in .md, resolve them\n if (config.agents) {\n for (const [name, subagent] of Object.entries(config.agents)) {\n if (subagent.prompt.endsWith(\".md\")) {\n const subagentPromptPath = path.resolve(path.dirname(filePath), subagent.prompt);\n try {\n subagent.prompt = await readFile(subagentPromptPath, \"utf-8\");\n } catch (err) {\n throw new Error(\n `Subagent \"${name}\" prompt file not found: ${subagentPromptPath} (referenced in ${filePath}). Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\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// ─── Subagent definition (for SDK agents parameter) ───\n\nexport const subagentDefinitionSchema = z.object({\n description: z.string(),\n prompt: z.string(),\n tools: z.array(agentToolSchema).optional(),\n model: agentModelSchema.optional(),\n});\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 version: 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 /**\n * Maximum cost in USD for this agent session.\n * Checked post-session (SDK provides cost only after session ends).\n * If session cost >= maxCost, a budget_exceeded error is thrown.\n * Child agents can override the parent's maxCost.\n */\n maxCost: z.number().min(0).optional(),\n mcpServers: z.array(z.string()).optional(),\n agents: z.record(z.string(), subagentDefinitionSchema).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 // biome-ignore lint/suspicious/noConsole: debug logging for missing custom agents dir\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, SubagentDefinition } 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 const agents = mergeAgents(\n base.agents as Record<string, SubagentDefinition> | undefined,\n config.agents as Record<string, SubagentDefinition> | undefined,\n );\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 ...(agents ? { agents } : {}),\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 ...(config.maxCost !== undefined\n ? { maxCost: config.maxCost }\n : base.maxCost !== undefined\n ? { maxCost: base.maxCost }\n : {}),\n ...(config.version !== undefined\n ? { version: config.version }\n : base.version !== undefined\n ? { version: base.version }\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 ...(config.agents ? { agents: config.agents as Record<string, SubagentDefinition> } : {}),\n };\n\n return {\n name: config.name,\n definition,\n sandbox: config.sandbox,\n ...(config.maxTurns !== undefined ? { maxTurns: config.maxTurns } : {}),\n ...(config.maxCost !== undefined ? { maxCost: config.maxCost } : {}),\n ...(config.version !== undefined ? { version: config.version } : {}),\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\nfunction mergeAgents(\n base: Record<string, SubagentDefinition> | undefined,\n override: Record<string, SubagentDefinition> | undefined,\n): Record<string, SubagentDefinition> | undefined {\n if (!base && !override) return undefined;\n if (!base) return override;\n if (!override) return base;\n return { ...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 * Path to the worker startup confirmation file for a detached run.\n * This file is written immediately after worker process starts to confirm\n * it survived the spawn phase. The parent process checks for this file\n * to detect early worker crashes.\n */\nexport function getWorkerStartedPath(repoSlug: string, runId: string): string {\n return path.join(getRepoRunsDir(repoSlug), `${runId}.started`);\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\n/**\n * Path to the children registry file: ~/.neo/supervisors/<name>/children.json\n * Written by ChildRegistry, read by the TUI to display focused child supervisors.\n */\nexport function getSupervisorChildrenPath(name: string): string {\n return path.join(getSupervisorDir(name), \"children.json\");\n}\n\n/**\n * Directory for all focused supervisor instances: ~/.neo/supervisors/focused/\n */\nexport function getFocusedSupervisorsDir(): string {\n return path.join(getSupervisorsDir(), \"focused\");\n}\n\n/**\n * Directory for a specific focused supervisor: ~/.neo/supervisors/focused/<id>/\n */\nexport function getFocusedSupervisorDir(supervisorId: string): string {\n return path.join(getFocusedSupervisorsDir(), supervisorId);\n}\n\n/**\n * Session file for a focused supervisor: ~/.neo/supervisors/focused/<id>/session.json\n */\nexport function getFocusedSupervisorSessionPath(supervisorId: string): string {\n return path.join(getFocusedSupervisorDir(supervisorId), \"session.json\");\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 // biome-ignore lint/suspicious/noConsole: config parsing errors must be visible to the user\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 // biome-ignore lint/suspicious/noConsole: config parsing errors must be visible to the user\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 // biome-ignore lint/suspicious/noConsole: last-resort error logging when emitter itself fails\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\";\nimport { sleep } from \"@/shared/time\";\n\nconst execFileAsync = promisify(execFile);\nconst GIT_TIMEOUT = 60_000;\n\n// Retry configuration for clone operations\nconst CLONE_MAX_RETRIES = 3;\nconst CLONE_BACKOFF_BASE_MS = 1000;\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\n // Retry clone with exponential backoff to handle transient network failures\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= CLONE_MAX_RETRIES; attempt++) {\n try {\n await execFileAsync(\n \"git\",\n [\"clone\", \"--branch\", options.baseBranch, cloneSource, sessionDir],\n { timeout: GIT_TIMEOUT },\n );\n lastError = undefined;\n break;\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n console.debug(\n `[neo] Clone attempt ${attempt}/${CLONE_MAX_RETRIES} failed: ${lastError.message}`,\n );\n\n // Clean up partial clone if it exists before retrying\n if (existsSync(sessionDir)) {\n await rm(sessionDir, { recursive: true, force: true }).catch((rmErr) => {\n console.debug(\n `[neo] Failed to clean up partial clone: ${rmErr instanceof Error ? rmErr.message : String(rmErr)}`,\n );\n });\n }\n\n if (attempt < CLONE_MAX_RETRIES) {\n const backoffMs = CLONE_BACKOFF_BASE_MS * 2 ** (attempt - 1);\n console.debug(`[neo] Retrying clone in ${backoffMs}ms...`);\n await sleep(backoffMs);\n }\n }\n }\n\n if (lastError) {\n throw new Error(\n `Clone failed after ${CLONE_MAX_RETRIES} attempts. Last error: ${lastError.message}`,\n { cause: lastError },\n );\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","/**\n * Delay execution for a specified number of milliseconds.\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\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 // Episode writes removed — episode type was deprecated (write-only, never read)\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 // Episode writes removed — episode type was deprecated (write-only, never read)\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: [\"knowledge\", \"warning\"],\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 { getRunsDir, toRepoSlug } from \"@/paths\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport type { PersistedRun } from \"@/types\";\n\n/** Fatal filesystem error codes that indicate system problems (disk full, permission denied). */\nconst FATAL_FS_ERRORS = new Set([\"ENOSPC\", \"EACCES\", \"EROFS\", \"EDQUOT\"]);\n\n/** Check if an error is a fatal filesystem error that should be re-thrown. */\nfunction isFatalFsError(err: unknown): boolean {\n return (\n err instanceof Error &&\n \"code\" in err &&\n typeof err.code === \"string\" &&\n FATAL_FS_ERRORS.has(err.code)\n );\n}\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 /** In-memory index for O(1) lookups by runId. Null = needs rebuild. */\n private runIdIndex: Map<string, string> | null = null;\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 * Logs errors but does not throw — run persistence is non-critical for dispatch.\n * However, fatal errors (ENOSPC, EACCES) are re-thrown as they indicate system problems.\n */\n async persistRun(run: PersistedRun): Promise<void> {\n try {\n const slug = toRepoSlug({ path: run.repo });\n // Use custom runsDir if provided, otherwise fall back to global path\n const repoDir = path.join(this.runsDir, 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 // Invalidate index — will be rebuilt on next query\n this.runIdIndex = null;\n } catch (err) {\n console.debug(`[neo] persistRun failed for ${run.runId}:`, err);\n // Re-throw fatal filesystem errors — these indicate system problems\n if (isFatalFsError(err)) {\n throw err;\n }\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 (err) {\n console.debug(\"[neo] recoverOrphanedRuns failed:\", err);\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 * Also populates the runIdIndex for O(1) lookups.\n */\n async collectRunFiles(): Promise<string[]> {\n const entries = await readdir(this.runsDir, { withFileTypes: true });\n const jsonFiles: string[] = [];\n const index = new Map<string, 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\")) {\n const filePath = path.join(subDir, f);\n jsonFiles.push(filePath);\n // Extract runId from filename (e.g., \"abc123.json\" -> \"abc123\")\n index.set(path.basename(f, \".json\"), filePath);\n }\n }\n } else if (entry.name.endsWith(\".json\")) {\n const filePath = path.join(this.runsDir, entry.name);\n jsonFiles.push(filePath);\n index.set(path.basename(entry.name, \".json\"), filePath);\n }\n }\n\n this.runIdIndex = index;\n return jsonFiles;\n }\n\n /**\n * Get all persisted runs from the runs directory.\n */\n async getAllRuns(): Promise<PersistedRun[]> {\n if (!existsSync(this.runsDir)) return [];\n\n const runs: PersistedRun[] = [];\n try {\n const jsonFiles = await this.collectRunFiles();\n for (const filePath of jsonFiles) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n runs.push(run);\n } catch (err) {\n console.debug(`[neo] getAllRuns: skipping corrupted file ${filePath}:`, err);\n }\n }\n } catch (err) {\n console.debug(\"[neo] getAllRuns failed:\", err);\n }\n return runs;\n }\n\n /**\n * Get a specific run by ID.\n * Returns null if not found.\n * Uses O(1) index lookup when available.\n */\n async getRunById(runId: string): Promise<PersistedRun | null> {\n if (!existsSync(this.runsDir)) return null;\n\n try {\n // Rebuild index if invalidated\n if (!this.runIdIndex) {\n await this.collectRunFiles();\n }\n\n // Index is guaranteed to be populated by collectRunFiles()\n const filePath = this.runIdIndex!.get(runId);\n if (!filePath) return null;\n\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content) as PersistedRun;\n } catch (err) {\n console.debug(`[neo] getRunById failed for ${runId}:`, err);\n }\n return null;\n }\n\n /**\n * Scan for stale (ghost) runs on startup.\n * For each run with status='running', check if the PID is alive.\n * If dead, mark as 'failed' with blockedReason explaining the crash.\n * Returns the list of recovered ghost runs for event emission.\n */\n async scanForStaleRuns(): Promise<PersistedRun[]> {\n if (!existsSync(this.runsDir)) return [];\n\n const recovered: PersistedRun[] = [];\n\n try {\n const jsonFiles = await this.collectRunFiles();\n for (const filePath of jsonFiles) {\n const run = await this.recoverGhostRun(filePath);\n if (run) recovered.push(run);\n }\n } catch (err) {\n console.debug(\"[neo] scanForStaleRuns failed:\", err);\n }\n\n return recovered;\n }\n\n /**\n * Check if a run file represents a ghost run (crashed supervisor).\n * Unlike recoverRunIfOrphaned, this method:\n * - Does NOT skip runs from the current process (we're a new process)\n * - Marks with blockedReason to indicate supervisor crash\n * If the run is a ghost, update its status to \"failed\" and return it.\n */\n private async recoverGhostRun(filePath: string): Promise<PersistedRun | null> {\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 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 ghost — 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.blockedReason = \"supervisor crashed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(filePath, JSON.stringify(run, null, 2), \"utf-8\");\n this.runIdIndex = null; // Invalidate index after direct file write\n\n return run;\n } catch (err) {\n console.debug(`[neo] recoverGhostRun failed for ${filePath}:`, err);\n return null;\n }\n }\n\n /**\n * Mark a run as blocked after all retries have been exhausted.\n * Blocked runs are visible to the supervisor but don't halt other work.\n */\n async markBlocked(runId: string, reason: string): Promise<void> {\n const run = await this.getRunById(runId);\n if (!run) {\n throw new Error(`Run not found: ${runId}`);\n }\n\n run.status = \"blocked\";\n run.blockedReason = reason;\n run.blockedAt = new Date().toISOString();\n run.updatedAt = new Date().toISOString();\n\n await this.persistRun(run);\n }\n\n /**\n * Get all blocked runs that need attention.\n */\n async getBlockedRuns(): Promise<PersistedRun[]> {\n const allRuns = await this.getAllRuns();\n return allRuns.filter((run) => run.status === \"blocked\");\n }\n\n /**\n * Unblock a run, setting it back to 'running' status.\n * Call this when the blocker has been resolved.\n */\n async unblock(runId: string): Promise<void> {\n const run = await this.getRunById(runId);\n if (!run) {\n throw new Error(`Run not found: ${runId}`);\n }\n\n if (run.status !== \"blocked\") {\n throw new Error(`Run ${runId} is not blocked (status: ${run.status})`);\n }\n\n run.status = \"running\";\n run.blockedReason = undefined;\n run.blockedAt = undefined;\n run.updatedAt = new Date().toISOString();\n\n await this.persistRun(run);\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 this.runIdIndex = null; // Invalidate index after direct file write\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 maxTurns?: number | undefined;\n resumeSessionId?: string | undefined;\n agents?: Record<string, unknown> | 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 ...(options.maxTurns ? { maxTurns: options.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.agents && Object.keys(options.agents).length > 0) {\n queryOptions.agents = options.agents;\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\";\nimport { sleep } from \"@/shared/time\";\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// ─── Failure Context ────────────────────────────────────\n\ninterface FailureContext {\n errorMessage: string;\n errorType: string;\n attempt: number;\n strategy: string;\n}\n\n/**\n * Build a prompt prefix that injects the previous failure context.\n * This gives the agent information to try a different approach.\n */\nfunction buildFailureContextPrefix(ctx: FailureContext): string {\n return `## PREVIOUS ATTEMPT FAILED\n\nYour previous attempt (attempt ${ctx.attempt}, strategy: ${ctx.strategy}) failed with:\n- **Error type:** ${ctx.errorType}\n- **Error message:** ${ctx.errorMessage}\n\nPlease try a different approach to complete this task. Consider what caused the failure and how to avoid it.\n\n---\n\n`;\n}\n\n/**\n * Inject failure context into the prompt for retry attempts.\n */\nfunction injectFailureContext(originalPrompt: string, ctx: FailureContext): string {\n return buildFailureContextPrefix(ctx) + originalPrompt;\n}\n\n/**\n * Extract error information from an unknown error.\n */\nfunction extractErrorInfo(error: unknown): { message: string; type: string } {\n if (error instanceof SessionError) {\n return { message: error.message, type: error.errorType };\n }\n if (error instanceof Error) {\n return { message: error.message, type: \"unknown\" };\n }\n return { message: String(error), type: \"unknown\" };\n}\n\n// ─── Default non-retryable errors ───────────────────────\n\nconst DEFAULT_NON_RETRYABLE = [\"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// ─── 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 *\n * On retry, the prompt is enriched with failure context from the previous\n * attempt, giving the agent information to try a different approach.\n */\nexport async function runWithRecovery(options: RecoveryOptions): Promise<SessionResult> {\n const {\n maxRetries,\n backoffBaseMs,\n nonRetryable = DEFAULT_NON_RETRYABLE,\n onAttempt,\n prompt: originalPrompt,\n ...rest\n } = options;\n\n let lastSessionId: string | undefined;\n let lastFailureContext: FailureContext | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const strategy = getStrategy(attempt);\n onAttempt?.(attempt, strategy);\n\n // Inject failure context on retry attempts\n const prompt = lastFailureContext\n ? injectFailureContext(originalPrompt, lastFailureContext)\n : originalPrompt;\n\n try {\n const result = await runSession({\n ...rest,\n prompt,\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 // Capture failure context for next attempt\n const errorInfo = extractErrorInfo(error);\n lastFailureContext = {\n errorMessage: errorInfo.message,\n errorType: errorInfo.type,\n attempt,\n strategy,\n };\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 { SessionError } from \"@/runner/session\";\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 agents: agent.definition.agents,\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 ...(agent.maxTurns ? { maxTurns: agent.maxTurns } : {}),\n });\n\n // Post-session budget check (SDK provides cost only after session ends)\n if (agent.maxCost !== undefined && sessionResult.costUsd >= agent.maxCost) {\n throw new SessionError(\n `Agent session exceeded budget: $${sessionResult.costUsd.toFixed(4)} >= $${agent.maxCost.toFixed(4)} limit`,\n \"budget_exceeded\",\n sessionResult.sessionId,\n );\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","import { z } from \"zod\";\n\n// ─── Memory types ────────────────────────────────────────\n\nexport const memoryTypeSchema = z.enum([\n \"knowledge\", // replaces fact + procedure\n \"warning\", // replaces feedback, always injected\n \"focus\", // unchanged, ephemeral working memory\n]);\n\nexport type MemoryType = z.infer<typeof memoryTypeSchema>;\n\n// ─── Subtype for knowledge entries ───────────────────────\n\nexport const knowledgeSubtypeSchema = z.enum([\"fact\", \"procedure\"]);\n\nexport type KnowledgeSubtype = z.infer<typeof knowledgeSubtypeSchema>;\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(), // legacy, kept for task migration\n runId: z.string().optional(),\n category: z.string().optional(), // warning: category\n severity: z.string().optional(),\n subtype: z.string().optional(), // knowledge: \"fact\" | \"procedure\"\n // supersedes removed — dead code\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 subtype: z.string().optional(), // \"fact\" | \"procedure\" for knowledge type\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\n// ─── Search result (extends MemoryEntry with score) ─────\n\nexport interface SearchResult extends MemoryEntry {\n /** Relevance score from 0 to 1, where 1 is most relevant */\n score: number;\n}\n","import type { MemoryEntry } from \"./entry.js\";\n\nconst SUBTYPE_ICONS: Record<string, string> = {\n fact: \"·\",\n procedure: \"→\",\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 knowledge = memories.filter((m) => m.type === \"knowledge\");\n const warnings = memories.filter((m) => m.type === \"warning\");\n const focus = memories.filter((m) => m.type === \"focus\");\n\n const sections: string[] = [];\n\n // Knowledge section (facts and procedures)\n if (knowledge.length > 0) {\n const facts = knowledge.filter((m) => m.subtype === \"fact\" || !m.subtype);\n const procedures = knowledge.filter((m) => m.subtype === \"procedure\");\n\n if (facts.length > 0) {\n const lines = facts.map((e) => {\n const confidence = e.accessCount >= 3 ? \"\" : \" (unconfirmed)\";\n const icon = SUBTYPE_ICONS.fact;\n return `${icon} ${e.content}${confidence}`;\n });\n sections.push(`### Facts\\n${lines.join(\"\\n\")}`);\n }\n\n if (procedures.length > 0) {\n const lines = procedures.map((e) => {\n const confidence = e.accessCount >= 3 ? \"\" : \" (unconfirmed)\";\n const icon = SUBTYPE_ICONS.procedure;\n return `${icon} ${e.content}${confidence}`;\n });\n sections.push(`### How-tos\\n${lines.join(\"\\n\")}`);\n }\n }\n\n // Warnings section (always injected, replaces old feedback type)\n if (warnings.length > 0) {\n const lines = warnings.map((e) => {\n const category = e.category ? `[${e.category}] ` : \"\";\n return `⚠ ${category}${e.content}`;\n });\n sections.push(`### Warnings\\n${lines.join(\"\\n\")}`);\n }\n\n // Focus section (ephemeral working memory)\n if (focus.length > 0) {\n const lines = focus.map((e) => `★ ${e.content}`);\n sections.push(`### Current focus\\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 {\n MemoryEntry,\n MemoryQuery,\n MemoryStats,\n MemoryWriteInput,\n SearchResult,\n} from \"./entry.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\n// ─── MemoryStore ─────────────────────────────────────────\n// Vector search removed (ADR-cleanup). FTS5 is sufficient.\n\nexport class MemoryStore {\n private db: import(\"better-sqlite3\").Database;\n\n constructor(dbPath: string) {\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.initSchema();\n }\n\n // ─── Schema initialization ───────────────────────────\n\n private initSchema(): void {\n // CRITICAL: Check for existing table with old schema BEFORE creating new table\n // The old schema has CHECK(type IN ('fact','procedure','feedback','episode','task','focus'))\n // We must migrate existing data before applying new CHECK constraint\n this.migrateSchemaIfNeeded();\n\n // Create table with new type constraint (only runs if table doesn't exist)\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('knowledge','warning','focus')),\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 subtype 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 // 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\n /**\n * Migrate from old schema to new schema BEFORE applying new constraints.\n *\n * This MUST run before CREATE TABLE IF NOT EXISTS with new CHECK constraints.\n * Otherwise, existing databases with old constraints will fail UPDATE operations\n * because the old CHECK constraint rejects new type values ('knowledge', 'warning').\n *\n * Migration steps:\n * - fact, procedure → knowledge (with subtype)\n * - feedback → warning\n * - episode → delete\n * - task → deleted (migrated by TaskStore)\n * - Add subtype column if missing\n * - Recreate table with new CHECK constraint\n */\n private migrateSchemaIfNeeded(): void {\n // Check if table exists\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\n // No table yet — nothing to migrate, initSchema will create fresh\n if (!tableInfo) return;\n\n // Check if old types exist in the CHECK constraint\n // This detects databases created with old schema\n const hasOldTypes =\n tableInfo.sql.includes(\"'fact'\") ||\n tableInfo.sql.includes(\"'procedure'\") ||\n tableInfo.sql.includes(\"'feedback'\") ||\n tableInfo.sql.includes(\"'episode'\") ||\n tableInfo.sql.includes(\"'task'\");\n\n // Already migrated or fresh schema — no migration needed\n if (!hasOldTypes) return;\n\n // ─── Migration required ───────────────────────────────\n\n // Check if subtype column exists (may be missing in very old schemas)\n const hasSubtype = tableInfo.sql.includes(\"subtype\");\n if (!hasSubtype) {\n try {\n this.db.exec(\"ALTER TABLE memories ADD COLUMN subtype TEXT\");\n } catch {\n // Column may already exist — race condition or partial migration\n }\n }\n\n // Migrate in a transaction\n this.db.exec(\"BEGIN TRANSACTION\");\n try {\n // Step 1: Rename old table\n this.db.exec(\"ALTER TABLE memories RENAME TO memories_old\");\n\n // Step 2: Create new table with new CHECK constraint\n this.db.exec(`\n CREATE TABLE memories (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('knowledge','warning','focus')),\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 subtype TEXT\n )\n `);\n\n // Step 3: Migrate data with type conversion in the INSERT\n // - fact, procedure → knowledge (with subtype preserving original)\n // - feedback → warning\n // - focus → focus (unchanged)\n // - episode, task → deleted (not inserted)\n this.db.exec(`\n INSERT INTO memories (\n id, type, scope, content, source, tags, created_at, last_accessed_at,\n access_count, expires_at, outcome, run_id, category, severity, subtype\n )\n SELECT\n id,\n CASE\n WHEN type IN ('fact', 'procedure') THEN 'knowledge'\n WHEN type = 'feedback' THEN 'warning'\n ELSE type\n END,\n scope, content, source, tags, created_at, last_accessed_at,\n access_count, expires_at, outcome, run_id, category, severity,\n CASE\n WHEN type = 'fact' THEN 'fact'\n WHEN type = 'procedure' THEN 'procedure'\n ELSE subtype\n END\n FROM memories_old\n WHERE type NOT IN ('episode', 'task')\n `);\n\n // Step 4: Drop old table\n this.db.exec(\"DROP TABLE memories_old\");\n\n // Step 5: Create indexes\n this.db.exec(`\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 // Step 6: Rebuild FTS index if it exists\n // After migration, the FTS table may have stale data pointing to old rowids\n // We need to rebuild it with the migrated content\n const ftsExists = this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='memories_fts'\")\n .get();\n if (ftsExists) {\n // Clear and rebuild FTS index from migrated data\n this.db.exec(\"DELETE FROM memories_fts\");\n this.db.exec(\n \"INSERT INTO memories_fts(rowid, content) SELECT rowid, content FROM memories\",\n );\n }\n\n this.db.exec(\"COMMIT\");\n } catch (err) {\n // Attempt rollback — may fail if transaction already aborted\n try {\n this.db.exec(\"ROLLBACK\");\n } catch {\n // Rollback failed — transaction may already be aborted\n }\n\n // Log the error with context so users know migration failed\n // biome-ignore lint/suspicious/noConsole: Intentional error logging for migration failures\n console.error(\n \"[neo] Memory schema migration failed. The database may be in an inconsistent state.\",\n \"\\n Error:\",\n err instanceof Error ? err.message : err,\n \"\\n Action: Neo will continue but some memories may not be accessible.\",\n \"\\n To fix: Back up and delete ~/.neo/memory.sqlite, or manually inspect the schema.\",\n );\n // Do NOT re-throw — neo should continue working with graceful degradation\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, subtype)\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.subtype ?? null,\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\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 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 // Tag filter using JSON_EACH\n if (opts.tags && opts.tags.length > 0) {\n const tagConditions = opts.tags.map(\n () => \"EXISTS (SELECT 1 FROM json_each(tags) WHERE value = ?)\",\n );\n conditions.push(`(${tagConditions.join(\" OR \")})`);\n params.push(...opts.tags);\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 (FTS5 full-text search) ────────────────\n\n async search(text: string, opts: MemoryQuery = {}): Promise<SearchResult[]> {\n // 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) {\n return this.query(opts).map((e) => ({ ...e, score: 0 }));\n }\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 & { rank: number })[];\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 if (filtered.length === 0) {\n return [];\n }\n\n // Normalize FTS rank to 0-1 score\n // FTS5 rank is negative, lower (more negative) is better match\n // We invert and normalize: best match gets score close to 1\n const ranks = filtered.map((r) => r.rank);\n const minRank = Math.min(...ranks);\n const maxRank = Math.max(...ranks);\n\n return filtered.map((row) => {\n let score: number;\n if (minRank === maxRank) {\n // All same rank, give them equal high score\n score = 0.8;\n } else {\n // Normalize: minRank (best) -> 1, maxRank (worst) -> 0\n score = 1 - (row.rank - minRank) / (maxRank - minRank);\n }\n return {\n ...rowToEntry(row),\n score: Math.max(0, Math.min(1, score)),\n };\n });\n } catch {\n // FTS query syntax error — fall back to LIKE\n return this.query(opts).map((e) => ({ ...e, score: 0 }));\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 (focus excluded)\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')`,\n )\n .run(minAccessCount, maxAgeDays);\n\n return staleResult.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 /**\n * Get the top N most-accessed memories.\n */\n topAccessed(limit = 5): MemoryEntry[] {\n const rows = this.db\n .prepare(\n `SELECT * FROM memories\n ORDER BY access_count DESC\n LIMIT ?`,\n )\n .all(limit) as RawMemoryRow[];\n\n return rows.map(rowToEntry);\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 subtype: 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 subtype: row.subtype ?? undefined,\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 /** Promise-based mutex to serialize write operations */\n private writeLock: Promise<void> = Promise.resolve();\n\n constructor(dir: string) {\n this.dir = dir;\n this.filePath = path.join(dir, ACTIVITY_FILE);\n }\n\n /**\n * Acquire the write lock and execute a callback.\n * Serializes write operations to prevent race conditions during rotation.\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 * Append a structured entry to the activity log.\n * Rotates the file if it exceeds MAX_SIZE_BYTES.\n * Uses a mutex to serialize concurrent calls and prevent race conditions.\n */\n async append(entry: ActivityEntry): Promise<void> {\n return this.withWriteLock(async () => {\n await this.checkRotation();\n const line = `${JSON.stringify(entry)}\\n`;\n await appendFile(this.filePath, line, \"utf-8\");\n });\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 { query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { isAssistantMessage, isInitMessage, isResultMessage, isToolUseMessage } from \"@/sdk-types\";\nimport type { AIAdapter, AIQueryOptions, SessionHandle, SupervisorMessage } from \"../ai-adapter.js\";\n\nexport class ClaudeAdapter implements AIAdapter {\n private sessionHandle: SessionHandle | undefined;\n\n getSessionHandle(): SessionHandle | undefined {\n return this.sessionHandle;\n }\n\n restoreSession(handle: SessionHandle): void {\n if (handle.provider !== \"claude\") {\n throw new Error(\"ClaudeAdapter only accepts claude session handles\");\n }\n this.sessionHandle = handle;\n }\n\n async *query(options: AIQueryOptions): AsyncIterable<SupervisorMessage> {\n const sdkTools = options.tools.map((t) => ({\n name: t.name,\n description: t.description,\n input_schema: t.inputSchema as Record<string, unknown>,\n }));\n\n // Use `as never` to bypass SDK's strict tools type — the SDK runtime accepts\n // JSON Schema tool definitions even though the TypeScript types only expose\n // built-in tool names. This mirrors the pattern used in heartbeat.ts.\n const queryOptions = {\n prompt: options.prompt,\n options: {\n tools: sdkTools,\n ...(options.model ? { model: options.model } : {}),\n ...(this.sessionHandle ? { resume: this.sessionHandle.sessionId } : {}),\n },\n };\n\n for await (const message of query(queryOptions as never)) {\n if (isInitMessage(message)) {\n this.sessionHandle = { provider: \"claude\", sessionId: message.session_id };\n continue;\n }\n\n if (isToolUseMessage(message)) {\n yield {\n kind: \"tool_use\",\n toolName: message.tool,\n toolInput: message.input,\n };\n continue;\n }\n\n if (isAssistantMessage(message)) {\n for (const block of message.message?.content ?? []) {\n if (block.type === \"text\" && block.text !== undefined) {\n yield { kind: \"text\", text: block.text };\n }\n }\n continue;\n }\n\n if (isResultMessage(message)) {\n yield { kind: \"end\" };\n }\n }\n }\n}\n","export type ChildCommand =\n | { type: \"inject\"; supervisorId: string; context: string }\n | { type: \"unblock\"; supervisorId: string; answer: string }\n | { type: \"stop\"; supervisorId: string };\n\nexport interface ChildSpawnCommand {\n objective: string;\n acceptanceCriteria: string[];\n maxCostUsd?: number;\n}\n\n/**\n * Parse a TUI inbox message text into a child supervisor command.\n * Returns null if the text is not a child command.\n *\n * Formats:\n * child:inject <supervisorId> <context...>\n * child:unblock <supervisorId> <answer...>\n * child:stop <supervisorId>\n */\nexport function parseChildCommand(text: string): ChildCommand | null {\n const trimmed = text.trim();\n\n const injectMatch = /^child:inject\\s+(\\S+)\\s+(.+)$/i.exec(trimmed);\n if (injectMatch) {\n const supervisorId = injectMatch[1];\n const context = injectMatch[2];\n if (!supervisorId || !context) return null;\n return { type: \"inject\", supervisorId, context };\n }\n\n const unblockMatch = /^child:unblock\\s+(\\S+)\\s+(.+)$/i.exec(trimmed);\n if (unblockMatch) {\n const supervisorId = unblockMatch[1];\n const answer = unblockMatch[2];\n if (!supervisorId || !answer) return null;\n return { type: \"unblock\", supervisorId, answer };\n }\n\n const stopMatch = /^child:stop\\s+(\\S+)$/i.exec(trimmed);\n if (stopMatch) {\n const supervisorId = stopMatch[1];\n if (!supervisorId) return null;\n return { type: \"stop\", supervisorId };\n }\n\n return null;\n}\n\n/**\n * Parse a child:spawn command from inbox message.\n * Format: \"child:spawn <JSON payload>\"\n */\nexport function parseChildSpawnCommand(text: string): ChildSpawnCommand | null {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"child:spawn \")) return null;\n\n const jsonPart = trimmed.slice(\"child:spawn \".length).trim();\n\n try {\n const parsed = JSON.parse(jsonPart) as Record<string, unknown>;\n\n if (typeof parsed.objective !== \"string\" || !parsed.objective) {\n return null;\n }\n\n if (!Array.isArray(parsed.acceptanceCriteria) || parsed.acceptanceCriteria.length === 0) {\n return null;\n }\n\n const criteria = parsed.acceptanceCriteria.filter((c): c is string => typeof c === \"string\");\n\n if (criteria.length === 0) {\n return null;\n }\n\n const result: ChildSpawnCommand = {\n objective: parsed.objective,\n acceptanceCriteria: criteria,\n };\n\n if (typeof parsed.maxCostUsd === \"number\") {\n result.maxCostUsd = parsed.maxCostUsd;\n }\n\n return result;\n } catch {\n return null;\n }\n}\n","import { type ChildProcess, fork } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ChildRegistry } from \"./child-registry.js\";\nimport type { ChildHandle, ChildToParentMessage } from \"./schemas.js\";\n\nexport interface SpawnChildOptions {\n objective: string;\n acceptanceCriteria: string[];\n registry: ChildRegistry;\n workerPath: string;\n parentName: string;\n maxCostUsd?: number;\n depth?: number;\n}\n\nexport interface SpawnChildResult {\n supervisorId: string;\n childProcess: ChildProcess;\n}\n\n/** Maximum allowed depth for child supervisors. Children cannot spawn children. */\nconst MAX_DEPTH = 1;\n\n/**\n * Spawn a focused child supervisor as a forked process.\n * The child communicates via IPC and is tracked by the ChildRegistry.\n */\nexport async function spawnChildSupervisor(options: SpawnChildOptions): Promise<SpawnChildResult> {\n const {\n objective,\n acceptanceCriteria,\n registry,\n workerPath,\n parentName,\n maxCostUsd,\n depth = 0,\n } = options;\n\n // Enforce depth limit: children cannot spawn children\n if (depth > MAX_DEPTH) {\n throw new Error(`Maximum depth exceeded: ${depth} > ${MAX_DEPTH}`);\n }\n\n const supervisorId = randomUUID();\n const now = new Date().toISOString();\n\n // Fork the worker process\n const childProcess = fork(workerPath, [], {\n stdio: [\"pipe\", \"pipe\", \"pipe\", \"ipc\"],\n env: {\n ...process.env,\n NEO_CHILD_SUPERVISOR_ID: supervisorId,\n NEO_CHILD_OBJECTIVE: objective,\n NEO_CHILD_CRITERIA: JSON.stringify(acceptanceCriteria),\n NEO_CHILD_PARENT_NAME: parentName,\n NEO_CHILD_MAX_COST_USD: maxCostUsd?.toString() ?? \"\",\n NEO_CHILD_DEPTH: String(depth),\n },\n });\n\n // Build handle for registry\n const handle: ChildHandle = {\n supervisorId,\n objective,\n depth,\n startedAt: now,\n lastProgressAt: now,\n costUsd: 0,\n maxCostUsd,\n status: \"running\",\n };\n\n // Stop callback for budget exceeded or manual stop\n const stopCallback = () => {\n if (childProcess.connected) {\n childProcess.send({ type: \"stop\" });\n }\n };\n\n // Wire IPC message handling\n childProcess.on(\"message\", (msg: unknown) => {\n // Validate and route to registry\n if (isChildToParentMessage(msg)) {\n registry.handleMessage(msg);\n }\n });\n\n childProcess.on(\"exit\", (code) => {\n // Clean up on unexpected exit\n const currentHandle = registry.get(supervisorId);\n if (currentHandle && currentHandle.status === \"running\") {\n registry.handleMessage({\n type: \"failed\",\n supervisorId,\n error: `Process exited with code ${code}`,\n });\n }\n registry.remove(supervisorId);\n });\n\n // Register with the parent's ChildRegistry\n registry.register(handle, stopCallback, childProcess);\n\n return { supervisorId, childProcess };\n}\n\n/**\n * Type guard for IPC messages from child.\n */\nfunction isChildToParentMessage(msg: unknown): msg is ChildToParentMessage {\n if (typeof msg !== \"object\" || msg === null) return false;\n const obj = msg as Record<string, unknown>;\n return (\n typeof obj.type === \"string\" &&\n typeof obj.supervisorId === \"string\" &&\n [\"progress\", \"complete\", \"blocked\", \"failed\", \"session\"].includes(obj.type)\n );\n}\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ChildHandle } from \"./schemas.js\";\n\n/**\n * Write the current list of child handles to children.json.\n * Called by ChildRegistry after every state mutation so the TUI can poll it.\n */\nexport async function writeChildrenFile(filePath: string, handles: ChildHandle[]): Promise<void> {\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, JSON.stringify(handles, null, 2), \"utf-8\");\n}\n\n/**\n * Read child handles from children.json.\n * Returns empty array if file does not exist or is malformed.\n */\nexport async function readChildrenFile(filePath: string): Promise<ChildHandle[]> {\n try {\n const raw = await readFile(filePath, \"utf-8\");\n return JSON.parse(raw) as ChildHandle[];\n } catch (err) {\n // biome-ignore lint/suspicious/noConsole: Log file read failures for debugging\n console.debug(\"[neo] Failed to read children file:\", err);\n return [];\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { constants } from \"node:fs\";\nimport { mkdir, open, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport type { GlobalConfig } from \"@/config\";\nimport { getSupervisorChildrenPath, getSupervisorDecisionsPath, getSupervisorDir } from \"@/paths\";\nimport { isProcessAlive } from \"@/shared/process\";\nimport { ActivityLog } from \"./activity-log.js\";\nimport { ChildRegistry } from \"./child-registry.js\";\nimport { DecisionStore } from \"./decisions.js\";\nimport { EventQueue } from \"./event-queue.js\";\nimport { HeartbeatLoop } from \"./heartbeat.js\";\nimport {\n type SupervisorDaemonState,\n supervisorDaemonStateSchema,\n type WebhookIncomingEvent,\n} 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 /** Path to child-supervisor-worker.js for spawning child processes */\n workerPath?: 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 readonly workerPath: 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 childRegistry: ChildRegistry | 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 this.workerPath = options.workerPath;\n }\n\n async start(): Promise<void> {\n // Create supervisor directory\n await mkdir(this.dir, { recursive: true });\n\n // Acquire lockfile atomically using O_EXCL to prevent TOCTOU race\n const lockPath = path.join(this.dir, \"daemon.lock\");\n await this.acquireLock(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 // Initialize child registry\n this.childRegistry = new ChildRegistry({\n onMessage: (message) => {\n this.eventQueue?.push({\n kind: \"child_supervisor\",\n message,\n timestamp: new Date().toISOString(),\n });\n },\n childrenFilePath: getSupervisorChildrenPath(this.name),\n });\n\n // Start heartbeat loop (blocks until stopped)\n const statePath = path.join(this.dir, \"state.json\");\n const directivesPath = path.join(this.dir, \"directives.jsonl\");\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 childRegistry: this.childRegistry,\n workerPath: this.workerPath,\n supervisorName: this.name,\n directivesPath,\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 const parsed = JSON.parse(raw);\n const result = supervisorDaemonStateSchema.safeParse(parsed);\n if (!result.success) {\n console.debug(`[SupervisorDaemon] Invalid state schema: ${result.error.message}`);\n return null;\n }\n return result.data;\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 const content = JSON.stringify(state, null, 2);\n\n // Write atomically: temp file then rename to prevent corruption on crash\n const tempPath = `${statePath}.${process.pid}.tmp`;\n await writeFile(tempPath, content, \"utf-8\");\n await rename(tempPath, statePath);\n }\n\n /**\n * Atomically acquire a lockfile using O_EXCL flag.\n * Handles stale locks by checking if the owning process is still alive.\n *\n * Note: A small race window exists between stale lock removal and retry.\n * Another process could grab the lock during this window, which is acceptable\n * because we detect and report it on the retry attempt. This is a best-effort\n * pattern — a true CAS (compare-and-swap) would require platform-specific APIs.\n */\n private async acquireLock(lockPath: string): Promise<void> {\n const tryAcquire = async (): Promise<boolean> => {\n let handle: Awaited<ReturnType<typeof open>> | null = null;\n try {\n handle = await open(\n lockPath,\n constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL,\n 0o644,\n );\n await handle.write(String(process.pid), 0, \"utf-8\");\n await handle.close();\n handle = null;\n return true;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n return false;\n }\n throw err;\n } finally {\n // Ensure handle is closed even if an error occurs during write\n if (handle) {\n await handle.close().catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Debug logging for file handle close failure\n console.debug(`[SupervisorDaemon] Lock file close failed: ${err}`);\n });\n }\n }\n };\n\n // First attempt\n if (await tryAcquire()) {\n return;\n }\n\n // Lock exists — check if it's stale\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\n // Stale lock — remove and retry.\n // NOTE: There is an inherent race window between rm() and tryAcquire() where\n // another process could create the lock. This is accepted as best-effort behavior:\n // - The window is small (typically < 1ms on local filesystem)\n // - A true compare-and-swap would require OS-specific syscalls (flock, lockf)\n // - If another process wins the race, we detect it and report cleanly below\n await rm(lockPath, { force: true });\n\n // Retry lock acquisition\n if (await tryAcquire()) {\n return;\n }\n\n // Another process grabbed the lock during our retry\n const retryPid = await this.readLockPid(lockPath);\n throw new Error(\n `Supervisor \"${this.name}\" already running (PID ${retryPid ?? \"unknown\"}). Use --kill first.`,\n );\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 { ChildProcess } from \"node:child_process\";\nimport { writeChildrenFile } from \"./children-file.js\";\nimport type { ChildHandle, ChildToParentMessage, ParentToChildMessage } from \"./schemas.js\";\n\nexport interface ChildRegistryOptions {\n onMessage: (message: ChildToParentMessage) => void;\n stallTimeoutMs?: number;\n /** If provided, children.json is written here after every mutation. */\n childrenFilePath?: string;\n}\n\n/**\n * Tracks all active focused supervisor child processes.\n * Handles IPC message routing, budget enforcement, and stall detection.\n */\nexport class ChildRegistry {\n private readonly handles = new Map<string, ChildHandle>();\n private readonly processes = new Map<string, ChildProcess>();\n private readonly stopCallbacks = new Map<string, () => void>();\n private readonly stallTimers = new Map<string, ReturnType<typeof setTimeout>>();\n private readonly onMessage: (message: ChildToParentMessage) => void;\n private readonly stallTimeoutMs: number;\n private readonly childrenFilePath: string | undefined;\n\n constructor(options: ChildRegistryOptions) {\n this.onMessage = options.onMessage;\n this.stallTimeoutMs = options.stallTimeoutMs ?? 10 * 60 * 1000;\n this.childrenFilePath = options.childrenFilePath;\n }\n\n /**\n * Register a child handle.\n */\n register(handle: ChildHandle, stopCallback?: () => void, childProcess?: ChildProcess): void {\n this.handles.set(handle.supervisorId, { ...handle });\n if (stopCallback) this.stopCallbacks.set(handle.supervisorId, stopCallback);\n if (childProcess) this.processes.set(handle.supervisorId, childProcess);\n this.resetStallTimer(handle.supervisorId);\n this.persistChildren();\n }\n\n get(supervisorId: string): ChildHandle | undefined {\n return this.handles.get(supervisorId);\n }\n\n list(): ChildHandle[] {\n return Array.from(this.handles.values());\n }\n\n /**\n * Send a message to a child via IPC.\n */\n send(supervisorId: string, message: ParentToChildMessage): void {\n const proc = this.processes.get(supervisorId);\n if (proc?.connected) {\n proc.send(message);\n }\n }\n\n /**\n * Handle an incoming IPC message from a child.\n * Updates state, enforces budget, forwards to caller.\n */\n handleMessage(message: ChildToParentMessage): void {\n const handle = this.handles.get(message.supervisorId);\n if (!handle) return;\n\n switch (message.type) {\n case \"progress\": {\n handle.costUsd += message.costDelta;\n handle.lastProgressAt = new Date().toISOString();\n this.resetStallTimer(message.supervisorId);\n if (handle.maxCostUsd !== undefined && handle.costUsd >= handle.maxCostUsd) {\n this.stopChild(message.supervisorId);\n return;\n }\n break;\n }\n case \"session\": {\n handle.sessionId = message.sessionId;\n break;\n }\n case \"complete\": {\n handle.status = \"complete\";\n this.clearStallTimer(message.supervisorId);\n break;\n }\n case \"blocked\": {\n handle.status = \"blocked\";\n this.clearStallTimer(message.supervisorId);\n break;\n }\n case \"failed\": {\n handle.status = \"failed\";\n this.clearStallTimer(message.supervisorId);\n break;\n }\n }\n\n this.persistChildren();\n this.onMessage(message);\n }\n\n /**\n * Remove a child from the registry and clean up.\n */\n remove(supervisorId: string): void {\n this.handles.delete(supervisorId);\n this.processes.delete(supervisorId);\n this.stopCallbacks.delete(supervisorId);\n this.clearStallTimer(supervisorId);\n this.persistChildren();\n }\n\n /**\n * Send stop to all children (called on daemon shutdown).\n */\n stopAll(): void {\n for (const supervisorId of this.handles.keys()) {\n this.send(supervisorId, { type: \"stop\" });\n this.clearStallTimer(supervisorId);\n }\n }\n\n private stopChild(supervisorId: string): void {\n const handle = this.handles.get(supervisorId);\n if (handle) {\n handle.status = \"failed\";\n }\n this.send(supervisorId, { type: \"stop\" });\n this.clearStallTimer(supervisorId);\n const stopCb = this.stopCallbacks.get(supervisorId);\n if (stopCb) stopCb();\n this.persistChildren();\n this.onMessage({\n type: \"failed\",\n supervisorId,\n error: \"Budget exceeded\",\n });\n }\n\n private persistChildren(): void {\n if (!this.childrenFilePath) return;\n const handles = this.list();\n // fire-and-forget — TUI polling is tolerant of brief inconsistency\n writeChildrenFile(this.childrenFilePath, handles).catch((err) => {\n // biome-ignore lint/suspicious/noConsole: Debug logging for persistence failures\n console.debug(\n `[ChildRegistry] persistChildren failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n\n private resetStallTimer(supervisorId: string): void {\n this.clearStallTimer(supervisorId);\n const timer = setTimeout(() => {\n const handle = this.handles.get(supervisorId);\n if (handle?.status === \"running\") {\n handle.status = \"stalled\";\n this.persistChildren();\n this.onMessage({\n type: \"failed\",\n supervisorId,\n error: `Stall detected: no progress for ${this.stallTimeoutMs}ms`,\n });\n }\n }, this.stallTimeoutMs);\n this.stallTimers.set(supervisorId, timer);\n }\n\n private clearStallTimer(supervisorId: string): void {\n const timer = this.stallTimers.get(supervisorId);\n if (timer) {\n clearTimeout(timer);\n this.stallTimers.delete(supervisorId);\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, readFile, rename, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { ensureDir } from \"@/shared/fs\";\n\n// ─── Errors ──────────────────────────────────────────────\n\n/**\n * Error thrown when a decision journal file exceeds the maximum allowed size.\n */\nexport class DecisionFileSizeError extends Error {\n constructor(\n public readonly filePath: string,\n public readonly fileSizeBytes: number,\n public readonly maxSizeBytes: number,\n ) {\n super(\n `Decision file exceeds maximum size: ${filePath} (${(fileSizeBytes / 1024 / 1024).toFixed(2)}MB > ${(maxSizeBytes / 1024 / 1024).toFixed(2)}MB)`,\n );\n this.name = \"DecisionFileSizeError\";\n }\n}\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/**\n * Tombstone record for marking deleted or expired decisions in append-only JSONL.\n * Tombstones are written to the journal instead of removing entries,\n * enabling true append-only semantics with periodic compaction.\n */\nexport const tombstoneSchema = z.object({\n action: z.literal(\"tombstone\"),\n id: z.string(),\n createdAt: z.coerce.string(),\n reason: z.enum([\"deleted\", \"expired\", \"purged\"]),\n});\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type DecisionOption = z.infer<typeof decisionOptionSchema>;\nexport type Decision = z.infer<typeof decisionSchema>;\nexport type Tombstone = z.infer<typeof tombstoneSchema>;\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 *\n * Compaction Strategy:\n * - Threshold-based compaction triggers on either:\n * 1. Tombstone ratio exceeds 30% of total valid entries (tombstones / (valid decisions + tombstones), excluding malformed lines)\n * 2. File size exceeds 10MB (prevents unbounded growth)\n * - Compaction rebuilds the file, filtering out tombstoned entries and preserving active decisions\n * - In-memory index maintains O(1) lookup without full file scans\n * - Compaction runs synchronously within the write lock to maintain consistency\n * - During compaction: all write operations are blocked until compaction completes, preventing race conditions\n * - Concurrent reads during compaction may return stale data from before compaction started\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 /** Maximum file size in bytes before validation fails (default: 10MB) */\n private readonly maxFileSizeBytes: number = 10 * 1024 * 1024;\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 * Uses a mutex to serialize concurrent calls and prevent race conditions.\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 this.withWriteLock(async () => {\n await appendFile(this.filePath, `${JSON.stringify(decision)}\\n`, \"utf-8\");\n });\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 * Check if a decision has already been answered without throwing.\n * Returns true if answered, false otherwise (including non-existent decisions).\n */\n async isAnswered(id: string): Promise<boolean> {\n const decision = await this.get(id);\n return decision?.answer !== undefined;\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 // Validate file size before reading to prevent OOM attacks\n const stats = await stat(this.filePath);\n if (stats.size > this.maxFileSizeBytes) {\n throw new DecisionFileSizeError(this.filePath, stats.size, this.maxFileSizeBytes);\n }\n\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\n // Write atomically: temp file then rename to prevent corruption on crash\n const tempPath = `${this.filePath}.${process.pid}.tmp`;\n await writeFile(tempPath, content, \"utf-8\");\n await rename(tempPath, this.filePath);\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 /** Set of event IDs for deduplication. Map preserves insertion order, so first entry is oldest. */\n private readonly seenIds = new Map<string, true>();\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 /** Write locks keyed by file path to serialize read-modify-write operations */\n private readonly writeLocks = new Map<string, Promise<void>>();\n\n constructor(options: EventQueueOptions) {\n this.maxEventsPerSec = options.maxEventsPerSec;\n }\n\n /**\n * Acquire the write lock for a file path and execute a callback.\n * Serializes write operations per-file to prevent race conditions during read-modify-write.\n */\n private async withWriteLock<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n const release = this.writeLocks.get(filePath) ?? Promise.resolve();\n let releaseLock: () => void = () => {};\n const newLock = new Promise<void>((r) => {\n releaseLock = r;\n });\n this.writeLocks.set(filePath, newLock);\n\n try {\n await release;\n return await fn();\n } finally {\n releaseLock();\n if (this.writeLocks.get(filePath) === newLock) {\n this.writeLocks.delete(filePath);\n }\n }\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 for deduplication. Map preserves insertion order.\n if (id) {\n this.seenIds.set(id, true);\n if (this.seenIds.size > this.maxSeenIds) {\n this.evictOldestSeenId();\n }\n }\n\n this.queue.push(event);\n this.wakeUp?.();\n return true;\n }\n\n /**\n * Evicts the oldest entry from seenIds.\n * Map preserves insertion order, so the first key is the oldest — O(1) eviction.\n */\n private evictOldestSeenId(): void {\n const firstKey = this.seenIds.keys().next().value;\n if (firstKey !== undefined) {\n this.seenIds.delete(firstKey);\n }\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 if (!event.data.text) continue;\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 (err) {\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 // biome-ignore lint/suspicious/noConsole: Log file creation failures for debugging\n console.debug(`[neo] Failed to ensure file exists ${p}:`, err);\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\n // Clean up watcher on error (e.g., file deleted, permissions changed)\n watcher.on(\"error\", (err) => {\n // biome-ignore lint/suspicious/noConsole: Log watcher errors for debugging\n console.debug(`[neo] Watcher error for ${filePath}, cleaning up:`, err);\n this.cleanupWatcher(watcher);\n });\n\n this.watchers.push(watcher);\n } catch (err) {\n // Non-critical: file may not exist yet — watcher will be set up when file is created\n // biome-ignore lint/suspicious/noConsole: Log watcher setup failures for debugging\n console.debug(`[neo] Failed to watch file ${filePath}:`, err);\n }\n }\n\n /**\n * Properly close and remove a watcher from the active list.\n */\n private cleanupWatcher(watcher: FSWatcher): void {\n try {\n watcher.close();\n } catch (err) {\n // Ignore errors during close — watcher may already be closed\n // biome-ignore lint/suspicious/noConsole: Log watcher cleanup failures for debugging\n console.debug(\"[neo] Error closing watcher:\", err);\n }\n const index = this.watchers.indexOf(watcher);\n if (index !== -1) {\n this.watchers.splice(index, 1);\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 return this.withWriteLock(filePath, async () => {\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 (err) {\n // Non-critical: marking as processed may fail but events are already handled.\n // Worst case: duplicate processing on restart (idempotent operations).\n // biome-ignore lint/suspicious/noConsole: Log mark processed failures for debugging\n console.debug(`[neo] Failed to mark events processed in ${filePath}:`, err);\n }\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 { RunStore } from \"@/orchestrator/run-store\";\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 TaskEntry, TaskStore } from \"@/supervisor/task-store\";\nimport type { PersistedRun } from \"@/types\";\nimport type { ActivityLog } from \"./activity-log.js\";\nimport { parseChildCommand, parseChildSpawnCommand } from \"./child-command-parser.js\";\nimport type { ChildRegistry } from \"./child-registry.js\";\nimport { spawnChildSupervisor } from \"./child-spawner.js\";\nimport { type Decision, DecisionStore } from \"./decisions.js\";\nimport { type Directive, DirectiveStore } from \"./directive-store.js\";\nimport type { EventQueue, GroupedEvents } from \"./event-queue.js\";\nimport { createFailureReport, writeFailureReport } from \"./failure-report.js\";\nimport { HeartbeatErrorBoundary } from \"./heartbeat-error-boundary.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 {\n type ActivityEntry,\n type LogBufferEntry,\n type QueuedEvent,\n type SupervisorDaemonState,\n supervisorDaemonStateSchema,\n} from \"./schemas.js\";\nimport {\n type GhostRunRecoveredEvent,\n ghostRunRecoveredEventSchema,\n type HeartbeatEvent,\n heartbeatEventSchema,\n heartbeatFailureEventSchema,\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 * For \"blocked\" status: always considered active (waiting for blocker resolution).\n */\nexport function isRunActive(\n run: PersistedRun,\n isAlive: (pid: number) => boolean = isProcessAlive,\n now: number = Date.now(),\n): boolean {\n // Skip terminal statuses\n if (run.status === \"completed\" || run.status === \"failed\") {\n return false;\n }\n\n // Paused and blocked runs are always considered active (waiting for resolution)\n if (run.status === \"paused\" || run.status === \"blocked\") {\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 tasks: TaskEntry[];\n recentActions: ActivityEntry[];\n mcpServerNames: string[];\n activeDirectives: Directive[];\n}\n\ninterface PostSdkProcessingInput {\n rawEvents: QueuedEvent[];\n isConsolidation: boolean;\n isCompaction: 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 /** Optional child registry for focused supervisor IPC integration */\n childRegistry?: ChildRegistry | undefined;\n /** Path to child-supervisor-worker.js for spawning child processes */\n workerPath?: string | undefined;\n /** Name of this supervisor instance (for child spawn registration) */\n supervisorName?: string | undefined;\n /** Path to directives storage */\n directivesPath?: string | 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 /** Cache of decision IDs already answered in this session to prevent re-answer spam */\n private readonly answeredDecisionIds = new Set<string>();\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 private readonly childRegistry: ChildRegistry | undefined;\n private readonly workerPath: string | undefined;\n private readonly supervisorName: string | undefined;\n private directiveStore: DirectiveStore | null = null;\n private readonly directivesPath: string | undefined;\n private errorBoundary: HeartbeatErrorBoundary | null = null;\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 this.childRegistry = options.childRegistry;\n this.workerPath = options.workerPath;\n this.supervisorName = options.supervisorName;\n this.directivesPath = options.directivesPath;\n }\n\n /** Path to the inbox/events directory for markProcessed() calls */\n get eventsPath(): string {\n return this._eventsPath;\n }\n\n /** Track store initialization failures for health reporting */\n private storeInitErrors: Map<string, string> = new Map();\n\n private getMemoryStore(): MemoryStore | null {\n if (!this.memoryStore && this.memoryDbPath) {\n try {\n this.memoryStore = new MemoryStore(this.memoryDbPath);\n this.storeInitErrors.delete(\"memory\");\n } catch (error) {\n // Memory store unavailable — continue without it\n const msg = error instanceof Error ? error.message : String(error);\n this.storeInitErrors.set(\"memory\", msg);\n this.getErrorBoundary()?.handleSilentError(\"getMemoryStore\", error);\n }\n }\n return this.memoryStore;\n }\n\n private taskStore: TaskStore | null = null;\n\n private getTaskStore(): TaskStore | null {\n if (!this.taskStore && this.memoryDbPath) {\n try {\n this.taskStore = new TaskStore(this.memoryDbPath);\n this.storeInitErrors.delete(\"task\");\n } catch (error) {\n // Task store unavailable — continue without it\n const msg = error instanceof Error ? error.message : String(error);\n this.storeInitErrors.set(\"task\", msg);\n this.getErrorBoundary()?.handleSilentError(\"getTaskStore\", error);\n }\n }\n return this.taskStore;\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 private getDirectiveStore(): DirectiveStore | null {\n if (!this.directiveStore && this.directivesPath) {\n try {\n this.directiveStore = new DirectiveStore(this.directivesPath);\n this.storeInitErrors.delete(\"directive\");\n } catch (error) {\n // Directive store unavailable — continue without it\n const msg = error instanceof Error ? error.message : String(error);\n this.storeInitErrors.set(\"directive\", msg);\n this.getErrorBoundary()?.handleSilentError(\"getDirectiveStore\", error);\n }\n }\n return this.directiveStore;\n }\n\n /**\n * Returns the health status of all stores.\n * Useful for diagnostics and monitoring degraded mode.\n */\n getStoreHealth(): {\n memory: { available: boolean; error: string | undefined };\n task: { available: boolean; error: string | undefined };\n directive: { available: boolean; error: string | undefined };\n decision: { available: boolean };\n } {\n return {\n memory: {\n available: this.memoryStore !== null,\n error: this.storeInitErrors.get(\"memory\"),\n },\n task: {\n available: this.taskStore !== null,\n error: this.storeInitErrors.get(\"task\"),\n },\n directive: {\n available: this.directiveStore !== null,\n error: this.storeInitErrors.get(\"directive\"),\n },\n decision: {\n available: this.decisionStore !== null,\n },\n };\n }\n\n /**\n * Get or create the HeartbeatErrorBoundary instance.\n * Lazily initialized to ensure sessionId is available.\n */\n private getErrorBoundary(): HeartbeatErrorBoundary {\n if (!this.errorBoundary) {\n this.errorBoundary = new HeartbeatErrorBoundary(\n this.activityLog,\n {\n maxConsecutiveFailures: this.config.supervisor.maxConsecutiveFailures,\n baseBackoffMs: this.config.supervisor.eventTimeoutMs,\n maxBackoffMs: 15 * 60 * 1000, // 15 minutes max\n },\n this.sessionId,\n this.onWebhookEvent,\n );\n }\n return this.errorBoundary;\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 // Scan for and recover ghost runs from crashed supervisors\n await this.recoverGhostRuns();\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 {\n // Error was already handled via handleHeartbeatError() in runHeartbeat()\n // We just need to track consecutive failures and evaluate circuit breaker\n this.consecutiveFailures++;\n const boundary = this.getErrorBoundary();\n\n // Circuit breaker: exponential backoff after consecutive failures\n const circuitResult = boundary.evaluateCircuitBreaker(this.consecutiveFailures);\n if (circuitResult.shouldBackoff) {\n await boundary.logCircuitBreaker(this.consecutiveFailures, circuitResult.backoffMs);\n await this.sleep(circuitResult.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 // Stop all child supervisors\n this.childRegistry?.stopAll();\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 this.getErrorBoundary()?.handleSilentError(\"handleConfigChange\", 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\n try {\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 tasks: eventCtx.tasks,\n recentActions: eventCtx.recentActions,\n mcpServerNames: eventCtx.mcpServerNames,\n activeDirectives: eventCtx.activeDirectives,\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 isCompaction: modeResult.isCompaction,\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 } catch (error) {\n // Global error boundary: emit heartbeat:failure event and re-throw\n // This ensures the daemon's outer catch handles circuit-breaker logic\n // while also providing visibility via webhook events\n const boundary = this.getErrorBoundary();\n\n // Handle error via boundary (emits webhook event and logs)\n await boundary.handleHeartbeatError({\n heartbeatId,\n consecutiveFailures: this.consecutiveFailures + 1,\n error,\n source: \"runHeartbeat\",\n });\n\n throw error;\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 await this.processChildCommands(rawEvents);\n await this.processChildSpawnCommands(rawEvents);\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, tasks, recent actions, and active directives.\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\n const mcpServerNames = this.config.mcpServers ? Object.keys(this.config.mcpServers) : [];\n\n // Synchronous store reads (better-sqlite3 is sync)\n const memoryStore = this.getMemoryStore();\n const memories: MemoryEntry[] = memoryStore\n ? memoryStore.query({ limit: 40, sortBy: \"relevance\" })\n : [];\n const taskStore = this.getTaskStore();\n const tasks: TaskEntry[] = taskStore ? taskStore.getTasks() : [];\n\n // Parallel async reads to reduce latency\n const directiveStore = this.getDirectiveStore();\n const [activeRuns, recentActions, activeDirectives] = await Promise.all([\n this.getActiveRuns(),\n this.activityLog.tail(20),\n directiveStore ? directiveStore.active(\"idle\") : Promise.resolve([] as Directive[]),\n ]);\n\n return {\n grouped,\n rawEvents,\n totalEventCount,\n activeRuns,\n memories,\n tasks,\n recentActions,\n mcpServerNames,\n activeDirectives,\n };\n }\n\n /**\n * Handle post-SDK processing: mark events as processed, consolidate log buffer, clean up old directives.\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 // Clean up old expired directives during compaction\n if (input.isCompaction) {\n const directiveStore = this.getDirectiveStore();\n if (directiveStore) {\n const expired = await directiveStore.expireOld();\n if (expired.length > 0) {\n await this.activityLog.log(\"event\", `Cleaned up ${expired.length} expired directive(s)`, {\n expiredIds: expired,\n });\n }\n }\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 attemptCount: runData?.attemptCount ?? 1,\n };\n if (runData?.output !== undefined) {\n emitOpts.output = runData.output;\n }\n if (runData?.task !== undefined) {\n emitOpts.task = runData.task;\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 tasks: TaskEntry[];\n recentActions: ActivityEntry[];\n mcpServerNames: string[];\n activeDirectives: Directive[];\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 tasks: opts.tasks,\n recentActions: opts.recentActions,\n pendingDecisions: opts.pendingDecisions,\n answeredDecisions: opts.answeredDecisions,\n hasPendingDecisions: opts.hasPendingDecisions,\n autoDecide: this.config.supervisor.autoDecide,\n activeDirectives: opts.activeDirectives,\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 const parsed = JSON.parse(raw);\n const result = supervisorDaemonStateSchema.safeParse(parsed);\n return result.success ? result.data : null;\n } catch (error) {\n this.getErrorBoundary()?.handleSilentError(\"readState\", error);\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 parsed = JSON.parse(raw);\n const result = supervisorDaemonStateSchema.safeParse(parsed);\n if (!result.success) return;\n const state = result.data;\n Object.assign(state, updates);\n await writeFile(this.statePath, JSON.stringify(state, null, 2), \"utf-8\");\n } catch (error) {\n // Non-critical\n this.getErrorBoundary()?.handleSilentError(\"updateState\", error);\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 (error) {\n // Corrupted or partial file — skip\n this.getErrorBoundary()?.handleSilentError(\"getActiveRuns:parseRunFile\", error);\n }\n }\n }\n\n return active;\n } catch (error) {\n this.getErrorBoundary()?.handleSilentError(\"getActiveRuns\", error);\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 (error) {\n // File not found — try next candidate (silent, expected for fallback resolution)\n this.getErrorBoundary()?.handleSilentError(\"loadInstructions\", error);\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 * Uses an in-memory deduplication cache to prevent re-answering decisions\n * that have already been processed, avoiding the \"already answered\" error spam.\n */\n private async processDecisionAnswers(\n rawEvents: QueuedEvent[],\n store: DecisionStore,\n ): Promise<void> {\n for (const event of rawEvents) {\n const parsed = parseDecisionAnswerEvent(event);\n if (!parsed) continue;\n await this.applyDecisionAnswer(parsed.decisionId, parsed.answer, store);\n }\n }\n\n /**\n * Process child:* commands from inbox messages.\n * Routes inject/unblock/stop to the ChildRegistry via IPC.\n * These messages are consumed here and not forwarded to the AI prompt.\n */\n private async processChildCommands(rawEvents: QueuedEvent[]): Promise<void> {\n if (!this.childRegistry) return;\n for (const event of rawEvents) {\n if (event.kind !== \"message\") continue;\n const command = parseChildCommand(event.data.text ?? \"\");\n if (!command) continue;\n switch (command.type) {\n case \"inject\":\n this.childRegistry.send(command.supervisorId, {\n type: \"inject\",\n context: command.context,\n });\n break;\n case \"unblock\":\n this.childRegistry.send(command.supervisorId, {\n type: \"unblock\",\n answer: command.answer,\n });\n break;\n case \"stop\":\n this.childRegistry.send(command.supervisorId, { type: \"stop\" });\n break;\n }\n }\n }\n\n /**\n * Process child:spawn commands from inbox messages.\n * These come from `neo supervise --parent=X` CLI invocations.\n */\n private async processChildSpawnCommands(rawEvents: QueuedEvent[]): Promise<void> {\n if (!this.childRegistry || !this.workerPath || !this.supervisorName) return;\n\n for (const event of rawEvents) {\n if (event.kind !== \"message\") continue;\n const text = event.data.text ?? \"\";\n const parsed = parseChildSpawnCommand(text);\n if (!parsed) continue;\n\n try {\n const spawnOptions: Parameters<typeof spawnChildSupervisor>[0] = {\n objective: parsed.objective,\n acceptanceCriteria: parsed.acceptanceCriteria,\n registry: this.childRegistry,\n workerPath: this.workerPath,\n parentName: this.supervisorName,\n depth: 0,\n };\n if (parsed.maxCostUsd !== undefined) {\n spawnOptions.maxCostUsd = parsed.maxCostUsd;\n }\n const result = await spawnChildSupervisor(spawnOptions);\n\n await this.activityLog.log(\n \"dispatch\",\n `Child supervisor spawned from CLI: ${result.supervisorId}`,\n {\n supervisorId: result.supervisorId,\n objective: parsed.objective,\n },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n await this.activityLog.log(\"error\", `Failed to spawn child supervisor: ${msg}`);\n }\n }\n }\n\n private async applyDecisionAnswer(\n decisionId: string,\n answer: string,\n store: DecisionStore,\n ): Promise<void> {\n if (this.answeredDecisionIds.has(decisionId)) return;\n\n const alreadyAnswered = await store.isAnswered(decisionId);\n if (alreadyAnswered) {\n this.answeredDecisionIds.add(decisionId);\n return;\n }\n\n try {\n await store.answer(decisionId, answer);\n this.answeredDecisionIds.add(decisionId);\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 if (msg.includes(\"already answered\")) {\n this.answeredDecisionIds.add(decisionId);\n } else {\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 task: string | undefined;\n attemptCount: number;\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 // Extract task from run prompt or use fallback\n const task = run.prompt?.slice(0, 200) ?? \"Unknown task\";\n\n return {\n status: run.status,\n totalCostUsd,\n durationMs,\n output,\n task,\n attemptCount: Object.keys(run.steps).length,\n };\n }\n }\n } catch (error) {\n // Non-critical — return null if we can't read run data\n this.getErrorBoundary()?.handleSilentError(\"readPersistedRun\", error);\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 \"heartbeat_failure\":\n heartbeatFailureEventSchema.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 \"ghost_run_recovered\":\n ghostRunRecoveredEventSchema.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 task?: string;\n attemptCount?: 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 // Write structured failure report for failed runs\n if (opts.status === \"failed\") {\n try {\n const report = createFailureReport({\n runId: opts.runId,\n task: opts.task ?? \"Unknown task\",\n reason: opts.output ?? \"Unknown error\",\n attemptCount: opts.attemptCount ?? 1,\n costUsd: opts.costUsd,\n });\n await writeFailureReport(this.supervisorDir, report);\n } catch (error) {\n // Best-effort: failure report errors should never crash daemon\n this.getErrorBoundary()?.handleSilentError(\"writeFailureReport\", error);\n }\n }\n }\n\n /** Emit GhostRunRecoveredEvent when a ghost run is detected and marked failed */\n private async emitGhostRunRecovered(opts: {\n runId: string;\n agent: string;\n repo: string;\n }): Promise<void> {\n const event: GhostRunRecoveredEvent = {\n type: \"ghost_run_recovered\",\n supervisorId: this.sessionId,\n runId: opts.runId,\n agent: opts.agent,\n repo: opts.repo,\n timestamp: new Date().toISOString(),\n reason: \"supervisor crashed\",\n };\n await this.emitWebhookEvent(event);\n }\n\n /**\n * Scan for ghost runs from crashed supervisors on startup.\n * Marks them as failed and emits events for logging/debugging.\n */\n private async recoverGhostRuns(): Promise<void> {\n try {\n const runStore = new RunStore();\n const ghostRuns = await runStore.scanForStaleRuns();\n\n if (ghostRuns.length === 0) return;\n\n await this.activityLog.log(\n \"event\",\n `Recovered ${ghostRuns.length} ghost run(s) from crashed supervisor`,\n { runIds: ghostRuns.map((r) => r.runId) },\n );\n\n // Emit events for each recovered ghost run\n for (const run of ghostRuns) {\n await this.emitGhostRunRecovered({\n runId: run.runId,\n agent: run.agent,\n repo: run.repo,\n });\n }\n } catch (error) {\n // Non-critical — best effort recovery\n const msg = error instanceof Error ? error.message : String(error);\n await this.activityLog.log(\"error\", `Ghost run recovery failed: ${msg}`);\n }\n }\n}\n\n/**\n * Parse a queued event into a decision answer if it matches the expected format.\n * Expected message format: \"decision:answer <decisionId> <answer>\"\n */\nfunction parseDecisionAnswerEvent(\n event: QueuedEvent,\n): { decisionId: string; answer: string } | null {\n if (event.kind !== \"message\") return null;\n if (!event.data.text) return null;\n const text = event.data.text.trim();\n const match = /^decision:answer\\s+(\\S+)\\s+(.+)$/i.exec(text);\n if (!match) return null;\n const decisionId = match[1];\n const answer = match[2];\n if (!decisionId || !answer) return null;\n return { decisionId, answer };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nconst esmRequire = createRequire(import.meta.url);\n\n// ─── Task schemas ────────────────────────────────────────\n\nexport const taskStatusSchema = z.enum([\"pending\", \"in_progress\", \"done\", \"blocked\", \"abandoned\"]);\n\nexport type TaskStatus = z.infer<typeof taskStatusSchema>;\n\nexport const taskPrioritySchema = z.enum([\"critical\", \"high\", \"medium\", \"low\"]);\n\nexport type TaskPriority = z.infer<typeof taskPrioritySchema>;\n\nexport const taskEntrySchema = z.object({\n id: z.string(),\n title: z.string(),\n scope: z.string(),\n status: taskStatusSchema,\n priority: taskPrioritySchema.optional(),\n initiative: z.string().optional(),\n dependsOn: z.string().optional(),\n context: z.string().optional(), // retrieval command\n runId: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nexport type TaskEntry = z.infer<typeof taskEntrySchema>;\n\nexport interface TaskCreateInput {\n title: string;\n scope: string;\n status: TaskStatus;\n priority?: TaskPriority;\n initiative?: string;\n dependsOn?: string;\n context?: string;\n runId?: string;\n}\n\nexport interface TaskQuery {\n initiative?: string;\n status?: TaskStatus[];\n scope?: string;\n}\n\n// ─── TaskStore ───────────────────────────────────────────\n\nexport class TaskStore {\n private db: import(\"better-sqlite3\").Database;\n\n constructor(dbPath: string) {\n const dir = path.dirname(dbPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\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.initSchema();\n }\n\n // ─── Schema initialization ───────────────────────────\n\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS tasks (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n scope TEXT NOT NULL,\n status TEXT NOT NULL CHECK(status IN ('pending','in_progress','done','blocked','abandoned')),\n priority TEXT CHECK(priority IN ('critical','high','medium','low')),\n initiative TEXT,\n depends_on TEXT,\n context TEXT,\n run_id TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);\n CREATE INDEX IF NOT EXISTS idx_tasks_initiative ON tasks(initiative);\n CREATE INDEX IF NOT EXISTS idx_tasks_scope ON tasks(scope);\n `);\n\n // Migrate task entries from memories table if it exists\n this.migrateFromMemories();\n }\n\n /**\n * Migrate existing task-type memory entries to the tasks table.\n * One-time migration on first open.\n */\n private migrateFromMemories(): void {\n try {\n // Check if memories table exists\n const tableExists = this.db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='memories'\")\n .get() as { name: string } | undefined;\n if (!tableExists) return;\n\n // Check if there are task entries to migrate\n const taskCount = this.db\n .prepare(\"SELECT COUNT(*) as count FROM memories WHERE type = 'task'\")\n .get() as { count: number };\n if (taskCount.count === 0) return;\n\n // Migrate task entries\n this.db.exec(`\n INSERT OR IGNORE INTO tasks (id, title, scope, status, priority, initiative, depends_on, context, run_id, created_at, updated_at)\n SELECT\n id,\n content,\n scope,\n COALESCE(outcome, 'pending'),\n severity,\n NULL,\n NULL,\n category,\n run_id,\n created_at,\n last_accessed_at\n FROM memories\n WHERE type = 'task';\n\n DELETE FROM memories WHERE type = 'task';\n `);\n } catch (err) {\n // Migration failed — memories table may not have task type yet\n // biome-ignore lint/suspicious/noConsole: Log migration failures for debugging\n console.debug(\"[neo] Task migration from memories table failed:\", err);\n }\n }\n\n // ─── CRUD operations ─────────────────────────────────\n\n createTask(input: TaskCreateInput): string {\n const id = `mem_${randomUUID().slice(0, 12)}`;\n const now = new Date().toISOString();\n\n this.db\n .prepare(\n `INSERT INTO tasks (id, title, scope, status, priority, initiative, depends_on, context, run_id, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n input.title,\n input.scope,\n input.status,\n input.priority ?? null,\n input.initiative ?? null,\n input.dependsOn ?? null,\n input.context ?? null,\n input.runId ?? null,\n now,\n now,\n );\n\n return id;\n }\n\n getTask(id: string): TaskEntry | undefined {\n const row = this.db.prepare(\"SELECT * FROM tasks WHERE id = ?\").get(id) as\n | RawTaskRow\n | undefined;\n return row ? rowToEntry(row) : undefined;\n }\n\n updateStatus(id: string, status: TaskStatus, runId?: string): void {\n const now = new Date().toISOString();\n if (runId !== undefined) {\n this.db\n .prepare(\"UPDATE tasks SET status = ?, run_id = ?, updated_at = ? WHERE id = ?\")\n .run(status, runId, now, id);\n } else {\n this.db\n .prepare(\"UPDATE tasks SET status = ?, updated_at = ? WHERE id = ?\")\n .run(status, now, id);\n }\n }\n\n getTasks(query: TaskQuery = {}): TaskEntry[] {\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n if (query.initiative) {\n conditions.push(\"initiative = ?\");\n params.push(query.initiative);\n }\n\n if (query.status && query.status.length > 0) {\n const placeholders = query.status.map(() => \"?\").join(\",\");\n conditions.push(`status IN (${placeholders})`);\n params.push(...query.status);\n }\n\n if (query.scope) {\n conditions.push(\"scope = ?\");\n params.push(query.scope);\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(\" AND \")}` : \"\";\n const rows = this.db\n .prepare(`SELECT * FROM tasks ${where} ORDER BY created_at DESC`)\n .all(...params) as RawTaskRow[];\n\n return rows.map(rowToEntry);\n }\n\n deleteTask(id: string): void {\n this.db.prepare(\"DELETE FROM tasks WHERE id = ?\").run(id);\n }\n\n close(): void {\n this.db.close();\n }\n}\n\n// ─── Internal helpers ────────────────────────────────────\n\ninterface RawTaskRow {\n id: string;\n title: string;\n scope: string;\n status: string;\n priority: string | null;\n initiative: string | null;\n depends_on: string | null;\n context: string | null;\n run_id: string | null;\n created_at: string;\n updated_at: string;\n}\n\nfunction rowToEntry(row: RawTaskRow): TaskEntry {\n return {\n id: row.id,\n title: row.title,\n scope: row.scope,\n status: row.status as TaskStatus,\n priority: row.priority as TaskPriority | undefined,\n initiative: row.initiative ?? undefined,\n dependsOn: row.depends_on ?? undefined,\n context: row.context ?? undefined,\n runId: row.run_id ?? undefined,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { appendFile, readFile, rename, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\n// ─── Schemas ─────────────────────────────────────────────\n\nexport const directiveTriggerSchema = z.enum([\"idle\", \"startup\", \"shutdown\"]);\n\nexport type DirectiveTrigger = z.infer<typeof directiveTriggerSchema>;\n\nexport const directiveSchema = z.object({\n id: z.string(),\n trigger: directiveTriggerSchema,\n action: z.string(),\n description: z.string().optional(),\n priority: z.number().default(0),\n enabled: z.boolean().default(true),\n createdAt: z.coerce.string(),\n expiresAt: z.coerce.string().optional(),\n lastTriggeredAt: z.coerce.string().optional(),\n});\n\nexport type Directive = z.infer<typeof directiveSchema>;\n\nexport interface DirectiveCreateInput {\n trigger: DirectiveTrigger;\n action: string;\n description?: string;\n priority?: number;\n expiresAt?: string;\n}\n\n// ─── Time Parsing ────────────────────────────────────────\n\n/**\n * Parse a human-readable duration string into an ISO timestamp.\n *\n * Supported formats:\n * - \"for X hours\" / \"for X minutes\" / \"for X days\"\n * - \"until midnight\"\n * - \"until HH:MM\"\n * - \"2h\" / \"30m\" / \"7d\" (shorthand)\n * - \"indefinitely\" / \"\" → returns undefined (no expiry)\n *\n * @returns ISO timestamp string or undefined for indefinite\n */\nexport function parseDirectiveDuration(input: string): string | undefined {\n const trimmed = input.trim().toLowerCase();\n\n // Indefinite\n if (!trimmed || trimmed === \"indefinitely\" || trimmed === \"forever\") {\n return undefined;\n }\n\n const now = new Date();\n\n // Shorthand: 2h, 30m, 7d\n const shorthandMatch = trimmed.match(/^(\\d+)(h|m|d)$/);\n if (shorthandMatch) {\n const value = Number(shorthandMatch[1]);\n const unit = shorthandMatch[2];\n let ms = 0;\n switch (unit) {\n case \"h\":\n ms = value * 60 * 60 * 1000;\n break;\n case \"m\":\n ms = value * 60 * 1000;\n break;\n case \"d\":\n ms = value * 24 * 60 * 60 * 1000;\n break;\n }\n return new Date(now.getTime() + ms).toISOString();\n }\n\n // \"for X hours/minutes/days\"\n const forMatch = trimmed.match(/^for\\s+(\\d+)\\s+(hour|minute|day|hr|min)s?$/);\n if (forMatch) {\n const value = Number(forMatch[1]);\n const unit = forMatch[2];\n let ms = 0;\n switch (unit) {\n case \"hour\":\n case \"hr\":\n ms = value * 60 * 60 * 1000;\n break;\n case \"minute\":\n case \"min\":\n ms = value * 60 * 1000;\n break;\n case \"day\":\n ms = value * 24 * 60 * 60 * 1000;\n break;\n }\n return new Date(now.getTime() + ms).toISOString();\n }\n\n // \"until midnight\"\n if (trimmed === \"until midnight\") {\n const midnight = new Date(now);\n midnight.setHours(23, 59, 59, 999);\n return midnight.toISOString();\n }\n\n // \"until HH:MM\"\n const untilTimeMatch = trimmed.match(/^until\\s+(\\d{1,2}):(\\d{2})$/);\n if (untilTimeMatch) {\n const hours = Number(untilTimeMatch[1]);\n const minutes = Number(untilTimeMatch[2]);\n const target = new Date(now);\n target.setHours(hours, minutes, 0, 0);\n\n // If the time has already passed today, set for tomorrow\n if (target.getTime() <= now.getTime()) {\n target.setDate(target.getDate() + 1);\n }\n\n return target.toISOString();\n }\n\n // Unrecognized format\n return undefined;\n}\n\n// ─── DirectiveStore ──────────────────────────────────────\n\n/**\n * JSONL-based store for persistent directives.\n * Each line is a complete directive record (append-only with periodic compaction).\n * Uses an in-memory mutex to serialize write operations.\n */\nexport class DirectiveStore {\n private readonly filePath: 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 const dir = path.dirname(filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\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 // ─── Create ────────────────────────────────────────────\n\n /**\n * Create a new directive and persist it.\n * Uses a mutex to serialize concurrent calls and prevent race conditions.\n */\n async create(input: DirectiveCreateInput): Promise<string> {\n const id = `dir_${randomUUID().slice(0, 12)}`;\n const now = new Date().toISOString();\n\n const directive: Directive = {\n id,\n trigger: input.trigger,\n action: input.action,\n description: input.description,\n priority: input.priority ?? 0,\n enabled: true,\n createdAt: now,\n expiresAt: input.expiresAt,\n };\n\n await this.withWriteLock(async () => {\n await this.append(directive);\n });\n return id;\n }\n\n // ─── Read ──────────────────────────────────────────────\n\n async get(id: string): Promise<Directive | undefined> {\n const all = await this.readAll();\n return all.get(id);\n }\n\n async list(): Promise<Directive[]> {\n const all = await this.readAll();\n return Array.from(all.values()).sort(\n (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),\n );\n }\n\n /**\n * Get active directives (enabled, not expired).\n * Optionally filter by trigger type.\n * Sorted by priority descending.\n */\n async active(trigger?: DirectiveTrigger): Promise<Directive[]> {\n const now = new Date().toISOString();\n const all = await this.readAll();\n\n return Array.from(all.values())\n .filter((d) => {\n if (!d.enabled) return false;\n if (d.expiresAt && d.expiresAt < now) return false;\n if (trigger && d.trigger !== trigger) return false;\n return true;\n })\n .sort((a, b) => b.priority - a.priority);\n }\n\n // ─── Update ────────────────────────────────────────────\n\n async toggle(id: string, enabled: boolean): Promise<void> {\n await this.withWriteLock(async () => {\n const all = await this.readAll();\n const directive = all.get(id);\n if (!directive) {\n throw new Error(`Directive not found: ${id}`);\n }\n\n directive.enabled = enabled;\n all.set(id, directive);\n await this.writeAll(all);\n });\n }\n\n async markTriggered(id: string): Promise<void> {\n await this.withWriteLock(async () => {\n const all = await this.readAll();\n const directive = all.get(id);\n if (!directive) {\n throw new Error(`Directive not found: ${id}`);\n }\n\n directive.lastTriggeredAt = new Date().toISOString();\n all.set(id, directive);\n await this.writeAll(all);\n });\n }\n\n // ─── Delete ────────────────────────────────────────────\n\n async delete(id: string): Promise<void> {\n await this.withWriteLock(async () => {\n const all = await this.readAll();\n if (!all.has(id)) {\n throw new Error(`Directive not found: ${id}`);\n }\n\n all.delete(id);\n await this.writeAll(all);\n });\n }\n\n /**\n * Remove directives that expired more than 24 hours ago.\n * Returns IDs of removed directives.\n */\n async expireOld(): Promise<string[]> {\n return this.withWriteLock(async () => {\n const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();\n const all = await this.readAll();\n const removed: string[] = [];\n\n for (const [id, directive] of all) {\n if (directive.expiresAt && directive.expiresAt < cutoff) {\n all.delete(id);\n removed.push(id);\n }\n }\n\n if (removed.length > 0) {\n await this.writeAll(all);\n }\n\n return removed;\n });\n }\n\n // ─── Internal ──────────────────────────────────────────\n\n private async readAll(): Promise<Map<string, Directive>> {\n const map = new Map<string, Directive>();\n\n if (!existsSync(this.filePath)) {\n return map;\n }\n\n try {\n const content = await readFile(this.filePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n\n for (const line of lines) {\n try {\n const raw = JSON.parse(line);\n const directive = directiveSchema.parse(raw);\n map.set(directive.id, directive);\n } catch {\n // Skip malformed lines\n }\n }\n } catch {\n // File doesn't exist or can't be read\n }\n\n return map;\n }\n\n private async writeAll(map: Map<string, Directive>): Promise<void> {\n const lines = Array.from(map.values())\n .map((d) => JSON.stringify(d))\n .join(\"\\n\");\n const content = lines ? `${lines}\\n` : \"\";\n\n // Write atomically: temp file then rename to prevent corruption on crash\n const tempPath = `${this.filePath}.${process.pid}.tmp`;\n await writeFile(tempPath, content, \"utf-8\");\n await rename(tempPath, this.filePath);\n }\n\n private async append(directive: Directive): Promise<void> {\n const line = `${JSON.stringify(directive)}\\n`;\n await appendFile(this.filePath, line, \"utf-8\");\n }\n}\n","import { appendFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { FailureReport } from \"./schemas.js\";\n\ntype ErrorType = FailureReport[\"lastErrorType\"];\n\n/**\n * Build a suggested action based on the error type and reason.\n */\nexport function buildSuggestedAction(errorType: ErrorType, _reason: string): string {\n switch (errorType) {\n case \"spawn_error\":\n return \"Check that all dependencies are installed. Run: pnpm install\";\n\n case \"timeout\":\n return \"Consider increasing the timeout limit or breaking the task into smaller steps.\";\n\n case \"budget\":\n return \"Review budget allocation. Consider increasing limits or optimizing token usage.\";\n\n case \"recovery_exhausted\":\n return \"All recovery attempts failed. Try a fresh session with simplified instructions.\";\n\n default:\n return \"Review the error details and consider manual intervention.\";\n }\n}\n\n/**\n * Classify an error message into an error type.\n */\nexport function classifyError(reason: string): ErrorType {\n const lower = reason.toLowerCase();\n\n if (lower.includes(\"timeout\") || lower.includes(\"timed out\")) {\n return \"timeout\";\n }\n // Check recovery_exhausted before budget to avoid \"exceeded\" matching budget\n if (\n lower.includes(\"recovery\") ||\n lower.includes(\"max retries\") ||\n lower.includes(\"retries exceeded\")\n ) {\n return \"recovery_exhausted\";\n }\n if (\n lower.includes(\"budget\") ||\n lower.includes(\"cost exceeded\") ||\n lower.includes(\"budget exceeded\")\n ) {\n return \"budget\";\n }\n if (lower.includes(\"spawn\") || lower.includes(\"module\") || lower.includes(\"not found\")) {\n return \"spawn_error\";\n }\n\n return \"unknown\";\n}\n\n/**\n * Write a structured failure report to inbox.jsonl.\n * This surfaces the failure as an actionable item in the supervisor prompt.\n */\nexport async function writeFailureReport(\n supervisorDir: string,\n report: Omit<FailureReport, \"timestamp\">,\n): Promise<void> {\n const entry: FailureReport = {\n ...report,\n timestamp: new Date().toISOString(),\n };\n\n const inboxPath = path.join(supervisorDir, \"inbox.jsonl\");\n\n try {\n await appendFile(inboxPath, `${JSON.stringify(entry)}\\n`, \"utf-8\");\n } catch (error) {\n // Best-effort: log but don't throw\n console.debug(\n `[failure-report] Failed to write: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Create a failure report from run completion data.\n */\nexport function createFailureReport(opts: {\n runId: string;\n task: string;\n reason: string;\n attemptCount: number;\n costUsd: number;\n}): Omit<FailureReport, \"timestamp\"> {\n const errorType = classifyError(opts.reason);\n const suggestedAction = buildSuggestedAction(errorType, opts.reason);\n\n return {\n type: \"failure-report\",\n runId: opts.runId,\n task: opts.task,\n reason: opts.reason.slice(0, 500),\n attemptCount: opts.attemptCount,\n lastErrorType: errorType,\n suggestedAction,\n costUsd: opts.costUsd,\n };\n}\n","/**\n * HeartbeatErrorBoundary consolidates the 3 levels of error handling in HeartbeatLoop:\n *\n * 1. Global error boundary (runHeartbeat try/catch) - emits heartbeat:failure event\n * 2. Circuit breaker (start() loop) - exponential backoff after consecutive failures\n * 3. Helper error handling - silent catches for non-critical operations\n *\n * This class provides a unified interface for emit/log/escalate operations\n * while preserving the existing error recovery behavior (ADR-020 compliant).\n */\n\nimport type { ActivityLog } from \"./activity-log.js\";\nimport type { HeartbeatFailureEvent, SupervisorWebhookEvent } from \"./webhookEvents.js\";\n\n/** Error severity levels for categorizing failures */\nexport type ErrorSeverity = \"critical\" | \"recoverable\" | \"silent\";\n\n/** Context for error handling decisions */\nexport interface ErrorContext {\n heartbeatId: string;\n consecutiveFailures: number;\n error: unknown;\n source: string;\n}\n\n/** Result of circuit breaker evaluation */\nexport interface CircuitBreakerResult {\n shouldBackoff: boolean;\n backoffMs: number;\n}\n\n/** Configuration for the error boundary */\nexport interface ErrorBoundaryConfig {\n maxConsecutiveFailures: number;\n baseBackoffMs: number;\n maxBackoffMs: number;\n}\n\n/** Callback for emitting webhook events */\nexport type WebhookEmitter = (event: SupervisorWebhookEvent) => void | Promise<void>;\n\n/**\n * HeartbeatErrorBoundary provides centralized error handling for the HeartbeatLoop.\n *\n * It consolidates three levels of error handling:\n * - emit(): Emits webhook events for external visibility\n * - log(): Logs errors to activity log for observability\n * - escalate(): Determines circuit breaker behavior for recovery\n *\n * Usage:\n * ```ts\n * const boundary = new HeartbeatErrorBoundary(activityLog, config, onWebhookEvent);\n *\n * // In runHeartbeat catch block:\n * await boundary.handleHeartbeatError(context);\n *\n * // In start() loop for circuit breaker:\n * const result = boundary.evaluateCircuitBreaker(consecutiveFailures);\n *\n * // For silent helper errors:\n * boundary.handleSilentError('readState', error);\n * ```\n */\nexport class HeartbeatErrorBoundary {\n private readonly activityLog: ActivityLog;\n private readonly config: ErrorBoundaryConfig;\n private readonly onWebhookEvent: WebhookEmitter | undefined;\n private readonly supervisorId: string;\n\n constructor(\n activityLog: ActivityLog,\n config: ErrorBoundaryConfig,\n supervisorId: string,\n onWebhookEvent?: WebhookEmitter,\n ) {\n this.activityLog = activityLog;\n this.config = config;\n this.supervisorId = supervisorId;\n this.onWebhookEvent = onWebhookEvent;\n }\n\n /**\n * Handle a critical heartbeat error (Level 1 - Global error boundary).\n *\n * This is called when runHeartbeat() throws an error. It:\n * 1. Emits a heartbeat:failure webhook event for external visibility\n * 2. Logs the error to the activity log\n *\n * The error is NOT suppressed - it is re-thrown to allow the circuit\n * breaker in start() to handle recovery.\n */\n async handleHeartbeatError(context: ErrorContext): Promise<void> {\n const errorMsg = this.normalizeError(context.error);\n\n // Emit failure event for external visibility (best-effort)\n await this.emit({\n type: \"heartbeat_failure\",\n supervisorId: this.supervisorId,\n heartbeatId: context.heartbeatId,\n timestamp: new Date().toISOString(),\n error: errorMsg.slice(0, 1000), // Truncate to schema max\n consecutiveFailures: context.consecutiveFailures,\n });\n\n // Log to activity log\n await this.log(\"error\", `Heartbeat failed: ${errorMsg}`, {\n heartbeatId: context.heartbeatId,\n source: context.source,\n consecutiveFailures: context.consecutiveFailures,\n });\n }\n\n /**\n * Evaluate circuit breaker state (Level 2 - Circuit breaker).\n *\n * Returns whether to back off and for how long based on consecutive failures.\n * Uses exponential backoff with a max cap.\n */\n evaluateCircuitBreaker(consecutiveFailures: number): CircuitBreakerResult {\n if (consecutiveFailures < this.config.maxConsecutiveFailures) {\n return { shouldBackoff: false, backoffMs: 0 };\n }\n\n const exponent = consecutiveFailures - this.config.maxConsecutiveFailures;\n const backoffMs = Math.min(this.config.baseBackoffMs * 2 ** exponent, this.config.maxBackoffMs);\n\n return { shouldBackoff: true, backoffMs };\n }\n\n /**\n * Log circuit breaker activation.\n */\n async logCircuitBreaker(consecutiveFailures: number, backoffMs: number): Promise<void> {\n await this.log(\n \"error\",\n `Circuit breaker: backing off ${Math.round(backoffMs / 1000)}s after ${consecutiveFailures} failures`,\n );\n }\n\n /**\n * Handle a silent/recoverable error from helpers (Level 3 - Silent catches).\n *\n * These errors are logged at debug level and don't affect the heartbeat flow.\n * Examples: memory store initialization, state file read/write, etc.\n */\n handleSilentError(source: string, error: unknown): void {\n const errorMsg = this.normalizeError(error);\n // Silent errors are logged to console.debug only - they don't propagate\n // biome-ignore lint/suspicious/noConsole: Debug logging for silent errors\n console.debug(`[neo] Silent error in ${source}: ${errorMsg}`);\n }\n\n /**\n * Handle a recoverable error that should be logged but not fail the heartbeat.\n *\n * These errors are logged to the activity log for visibility but don't\n * interrupt the heartbeat flow.\n */\n async handleRecoverableError(\n source: string,\n error: unknown,\n detail?: Record<string, unknown>,\n ): Promise<void> {\n const errorMsg = this.normalizeError(error);\n await this.log(\"error\", `${source} failed: ${errorMsg}`, detail);\n }\n\n /**\n * Emit a webhook event (best-effort, never throws).\n */\n private async emit(event: HeartbeatFailureEvent): Promise<void> {\n if (!this.onWebhookEvent) return;\n\n try {\n await this.onWebhookEvent(event);\n } catch {\n // Emission failed - log to console.debug and continue\n // biome-ignore lint/suspicious/noConsole: Debug logging for emission failure\n console.debug(`[neo] Webhook event emission failed for ${event.type}`);\n }\n }\n\n /**\n * Log to the activity log (best-effort, never throws).\n */\n private async log(\n level: \"error\" | \"warning\",\n message: string,\n detail?: Record<string, unknown>,\n ): Promise<void> {\n try {\n await this.activityLog.log(level, message, detail);\n } catch {\n // Log failed - fallback to console.debug\n // biome-ignore lint/suspicious/noConsole: Debug fallback for log failure\n console.debug(`[neo] Activity log failed: ${message}`);\n }\n }\n\n /**\n * Normalize an error to a string message.\n */\n private normalizeError(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === \"string\") return error;\n return String(error);\n }\n\n /**\n * Classify error severity based on the error type and source.\n *\n * This is used to determine the appropriate handling strategy:\n * - critical: Fails the heartbeat, triggers circuit breaker\n * - recoverable: Logged but heartbeat continues\n * - silent: Only debug logged, no interruption\n */\n classifyError(source: string, error: unknown): ErrorSeverity {\n const errorMsg = this.normalizeError(error);\n\n // SDK errors are critical - they prevent the heartbeat from completing\n if (source === \"sdk\" || source === \"runHeartbeat\") {\n return \"critical\";\n }\n\n // State/store errors are recoverable - heartbeat can continue with defaults\n if (\n source === \"readState\" ||\n source === \"updateState\" ||\n source === \"getMemoryStore\" ||\n source === \"getTaskStore\" ||\n source === \"getDirectiveStore\"\n ) {\n return \"silent\";\n }\n\n // File system errors might be transient\n if (errorMsg.includes(\"ENOENT\") || errorMsg.includes(\"EACCES\")) {\n return \"recoverable\";\n }\n\n // Default to recoverable for unknown errors\n return \"recoverable\";\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, rename, 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// ─── Module-level write lock ─────────────────────────────\n// Keyed by directory path to allow concurrent operations on different buffers\n\nconst writeLocks = new Map<string, Promise<void>>();\n\n/**\n * Acquire the write lock for a directory and execute a callback.\n * Serializes write operations per-directory to prevent race conditions.\n */\nasync function withWriteLock<T>(dir: string, fn: () => Promise<T>): Promise<T> {\n // Chain onto the existing lock for this directory\n const release = writeLocks.get(dir) ?? Promise.resolve();\n let releaseLock: () => void = () => {};\n const newLock = new Promise<void>((r) => {\n releaseLock = r;\n });\n writeLocks.set(dir, newLock);\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 // Clean up if this was the last lock in the chain\n if (writeLocks.get(dir) === newLock) {\n writeLocks.delete(dir);\n }\n }\n}\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 * Uses a mutex to serialize concurrent calls and prevent race conditions.\n */\nexport async function markConsolidated(dir: string, ids: string[]): Promise<void> {\n return withWriteLock(dir, async () => {\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 // Write atomically: temp file then rename to prevent data loss\n const tempPath = `${filePath}.${process.pid}.tmp`;\n await writeFile(tempPath, `${updated.join(\"\\n\")}\\n`, \"utf-8\");\n await rename(tempPath, filePath);\n });\n}\n\n/**\n * Remove entries with consolidatedAt older than 24h. Cap file at 1MB.\n * Uses a mutex to serialize concurrent calls and prevent race conditions.\n */\nexport async function compactLogBuffer(dir: string): Promise<void> {\n return withWriteLock(dir, async () => {\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 // Write atomically: temp file then rename to prevent data loss\n const tempPath = `${filePath}.${process.pid}.tmp`;\n await writeFile(tempPath, result, \"utf-8\");\n await rename(tempPath, filePath);\n });\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 * Uses a mutex to serialize concurrent calls and prevent race conditions.\n */\nexport async function appendLogBuffer(dir: string, entry: LogBufferEntry): Promise<void> {\n return withWriteLock(dir, async () => {\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/**\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 { TaskEntry } from \"@/supervisor/task-store\";\nimport type { Decision } from \"./decisions.js\";\nimport type { Directive } from \"./directive-store.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 tasks: TaskEntry[];\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 /** Active directives for idle time (sorted by priority) */\n activeDirectives?: Directive[] | undefined;\n}\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- You are fully responsible for any unassigned queued task — ensure end-to-end delivery.\n- Act as a decisive engineering lead: give clear context, dispatch deliberately, validate outcomes, and resolve blockers fast.\n- On completion, always review \\`neo runs <runId>\\`: check if criteria are met, then choose to mark done, follow up, re-dispatch, or escalate.\n- On run failure: identify the root cause (prompt quality, repo, conflict, known issue, environment/tooling) before retrying. Fix cause before proceeding.\n- Proactively monitor for blocked or stalled work; never let issues persist silently.\n- Output only via \\`neo log\\`. Prefer concise tool calls, not explanations. No wasted tokens.\n- Launch agents read-only from repos via \\`neo repos\\`.\n- Update every task outcome on every heartbeat; never leave status unknown.\n- Never dispatch duplicate runs.\n- For decisions: answer pending questions in 1–2 heartbeats. If strategic/scope/priority → answer directly. For code context, dispatch scout. Wait for human only if autoDecide is disabled or ambiguity remains. Blocking agents wastes budget.\n- If human input is required (ambiguous scope, conflict, unknown repo, task failed ≥3×): use \\`neo decision create \"<question>\" --options ... --expires-in 24h --context \"<reason>\"\\`. Never proceed by guessing or remaining silent. Always ask if uncertain.\n- Every \\`neo run\\` MUST have an \\`in_progress\\` task:\n 1. Check for task: \\`neo task list --status pending,in_progress\\`\n 2. If missing, create: \\`neo task create --scope <repo> --priority <p> --initiative <name> \"<description>\"\\`\n 3. After dispatch, update: \\`neo task update <id> --status in_progress --context \"neo runs <runId>\"\\`\n Runs without tasks are not allowed.\n- Always review agent outputs (\\`neo runs <runId>\\`) before follow-up, according to SUPERVISOR.md agent contracts.\n- **Child supervisors**: for self-contained objectives requiring 3+ agent dispatches with intermediate decisions, use \\`spawn_child_supervisor\\` instead of direct dispatch. Every child MUST have a \\`maxCostUsd\\` cap and a corresponding task. React to child IPC events: \\`progress\\` → log, \\`complete\\` → verify evidence + mark done, \\`blocked\\` → answer or escalate, \\`failed\\` → re-spawn max 2×, then escalate.\n`;\n\n// ─── Instruction blocks ─────────────────────────────────\n\n// ─── Child supervisor rules ──────────────────────────────\nconst CHILD_SUPERVISOR_RULES = `### Child supervisors\n\nA child supervisor is a subordinate autonomous instance you can spawn for a **self-contained objective** that would otherwise require many sequential heartbeats and complex state-tracking. The child runs its own heartbeat loop and reports back via IPC events.\n\n<when-to-spawn>\nSpawn a child when ALL three conditions hold:\n1. The work is **isolated** — no shared branches or PRs with other active initiatives.\n2. It requires **3+ developer dispatches** with intermediate decisions (too complex to track in focus).\n3. It has **clear acceptance criteria** you can express as a checklist.\n\nDo NOT spawn a child for: simple one-agent tasks, work that shares a branch, or tasks where you need tight control over each step. Children cannot spawn children (depth limit = 1).\n</when-to-spawn>\n\n<spawn-tool>\n\\`\\`\\`json\n{\n \"name\": \"spawn_child_supervisor\",\n \"input\": {\n \"objective\": \"Implement the CSV export feature per .neo/specs/csv-export.md\",\n \"acceptanceCriteria\": [\n \"PR is open and CI passes\",\n \"Reviewer approved with no CRITICAL issues\",\n \".neo/specs/csv-export.md acceptance criteria are met\"\n ],\n \"maxCostUsd\": 5.00\n }\n}\n\\`\\`\\`\nAlways set \\`maxCostUsd\\` — budget-uncapped children are a safety risk.\nAfter spawning: create a task, mark it \\`in_progress\\`, log the supervisorId.\n</spawn-tool>\n\n<child-event-contracts>\nReact to each IPC message type:\n\n| type | Meaning | Your action |\n|------|---------|-------------|\n| \\`progress\\` | Child is alive and working | Log summary, update task outcome with latest summary. No dispatch needed. |\n| \\`complete\\` | All acceptance criteria met | Read \\`evidence[]\\` to verify. Mark task \\`done\\`. If a PR was created, dispatch \\`reviewer\\`. |\n| \\`blocked\\` | Child needs a decision | Read \\`question\\` + \\`urgency\\`. If you can answer → \\`neo decision answer\\` or send \\`inject\\` with context. Urgency \\`high\\` = answer within 1 heartbeat. |\n| \\`failed\\` | Child crashed or hit max retries | Read \\`error\\`. If recoverable → re-spawn with same criteria. On 3rd failure → mark task \\`blocked\\`, create a decision for human. |\n| \\`session\\` | Child started a new SDK session | Note sessionId for debugging. No action needed. |\n\nAfter \\`complete\\`: always verify \\`evidence[]\\` — a child may self-report completion without fully meeting criteria.\nAfter \\`failed\\` 2× on the same child: do NOT re-spawn automatically. Create a \\`blocked\\` task and escalate.\n</child-event-contracts>\n\n<child-budget-guard>\n- Always set \\`maxCostUsd\\` — a child without a budget cap is a runaway risk.\n- Factor child cost into your \\`neo cost --short\\` check before spawning.\n- If a child hits its cap it will \\`failed\\` with \"budget exceeded\". Evaluate whether to re-spawn with a higher cap or restructure as direct agent dispatches.\n</child-budget-guard>`;\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. Read agent output and route per SUPERVISOR.md contracts.\n5. CI AUDIT — for every open PR across all repos, run:\n \\`gh pr list --repo <repo> --json number,headRefName,title,statusCheckRollup --state open\\`\n Then for each PR:\n - CI **failed** + no active developer run on that branch → re-dispatch developer with CI error context\n - CI **passed** + no active reviewer run + no reviewer dispatched this cycle → dispatch reviewer\n - CI **pending** → log and skip (check next heartbeat)\n - PR has \\`CHANGES_REQUESTED\\` verdict + no active developer run → re-dispatch developer with review feedback (check anti-loop guard first)\n Never leave a PR orphaned: every open PR must have either an active run or a clear status.\n5b. DECISIONS — check \\`neo decision list\\` for pending decisions. **Prioritize above dispatch.** Agents are BLOCKED waiting — stale decisions waste budget. Route each: answer directly if scope/strategy, dispatch scout if needs codebase context, escalate to human if genuinely uncertain.\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. 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. Architect produces a plan; developer executes all tasks on that branch. Independent initiatives CAN run in parallel on different branches.\n\n**Dispatch quality:** when dispatching developer with a plan, include the plan path and any context from completed prior work (PR numbers, APIs added). For direct tasks (no plan), write a detailed \\`--prompt\\` with acceptance criteria.\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(): string {\n return `### Memory\n\n<memory-types>\n| Type | Subtype | Store when | TTL |\n|------|---------|-----------|-----|\n| \\`knowledge\\` | \\`fact\\` | Stable truth affecting dispatch decisions | Permanent (decays) |\n| \\`knowledge\\` | \\`procedure\\` | Same failure 3+ times | Permanent |\n| \\`warning\\` | — | Same review complaint 3+ times | Permanent |\n| \\`focus\\` | — | After every dispatch/deferral | --expires required |\n</memory-types>\n\n<tasks>\nTasks are managed separately via \\`neo task\\` commands:\n\\`\\`\\`bash\nneo task create --scope /path --priority high --context \"neo runs <id>\" \"Task description\"\nneo task update <id> --status in_progress|done|blocked|abandoned\nneo task list [--initiative <name>] [--status pending,in_progress]\n\\`\\`\\`\n</tasks>\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 → write a \\`procedure\\` (knowledge subtype).\n- Every memory that references external context MUST include a retrieval command in the content. You are stateless — if you can't retrieve it later, don't store it.\n</memory-rules>\n\n<task-workflow>\nTasks are separate from memory. Use \\`neo task\\` commands:\n- \\`neo task create --scope /path --priority high --initiative <name> \"Description\"\\`\n- \\`neo task update <id> --status in_progress|done|blocked|abandoned\\`\n\nQueue markers: ○ pending · [ACTIVE] in_progress · [BLOCKED] blocked.\nCreate tasks for: incoming tickets, architect decompositions, sub-tickets, follow-ups, CI fixes.\n- \\`--initiative <name>\\` — groups related tasks\n- \\`--depends <task_id>\\` — blocks until dependency is done\n- \\`--context\\` — retrieval command (MANDATORY). Example: \\`\"neo runs <runId>\"\\`\n\n**Update frequency:** task status MUST be updated in the same heartbeat as the triggering event. Never defer to \"next heartbeat\" — by then you will have forgotten.\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\nfunction buildMemoryRulesExamples(): string {\n return `<memory-examples>\nneo memory write --type focus --expires 2h \"ACTIVE: 5900a64a developer 'T1' branch:feat/x | T2 pending, waiting on CI\"\nneo memory write --type knowledge --subtype fact --scope /repo \"main branch uses protected merges — agents must create PRs, never push directly\"\nneo memory write --type knowledge --subtype fact --scope /repo \"pnpm build must pass before push — CI does not rebuild, run 2g589f34a5a failed without it\"\nneo memory write --type knowledge --subtype procedure --scope /repo \"After architect run: read plan path from output, dispatch developer with plan per SUPERVISOR.md routing\"\nneo memory write --type knowledge --subtype procedure --scope /repo \"When developer run fails with ENOSPC: the repo has large fixtures — use --branch with shallow clone flag\"\nneo memory write --type warning --scope /repo \"User wants PR descriptions in French even though code is in English\"\nneo task create --scope /repo --priority high --context \"neo runs 2g589f34a5a\" --initiative auth-v2 --depends mem_xyz \"T1: Auth middleware\"\nneo task update <id> --status 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\n// ─── Commands reference (inline, single source of truth: see GUIDE.md) ──\n// Compact form used after first 3 heartbeats to save tokens.\n\nconst COMMANDS_FULL = `### Commands\n\n\\`\\`\\`bash\nneo run <agent> --prompt \"...\" --repo <path> --branch <name> --meta '{\"label\":\"T1-auth\",...}'\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.\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**.\n\n### Memory\n\\`\\`\\`bash\nneo memory write --type knowledge --subtype fact --scope /path \"Stable fact about repo\"\nneo memory write --type knowledge --subtype procedure --scope /path \"How to do X\"\nneo memory write --type warning --scope /path \"Recurring issue to watch for\"\nneo memory write --type focus --expires 2h \"Current working context\"\nneo task create --scope /path --priority high --context \"neo runs <id>\" \"Task description\"\nneo task update <id> --status in_progress|done|blocked|abandoned\nneo memory forget <id>\nneo memory search \"keyword\"\nneo memory list --type fact\n\\`\\`\\`\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\\`\\`\\`\n\n### Config\n\\`\\`\\`bash\nneo config get <key>\nneo config set <key> <value> --global\nneo config list\n\\`\\`\\`\n\n### Child Supervisors\n\\`\\`\\`bash\nneo child spawn --objective \"...\" --criteria \"...\" [--budget <usd>] [--supervisor <name>]\n\\`\\`\\`\n\n### Directives\nStanding instructions (always active, not only during idle):\n\\`\\`\\`bash\nneo directive create \"<action>\" [--duration \"2h\" | \"until midnight\"] [--priority 5]\nneo directive list # list all directives\nneo directive toggle <id> # enable/disable a directive\nneo directive delete <id> # delete a directive\n\\`\\`\\`\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>]\\` · \\`neo runs --short --status running\\` · \\`neo cost --short\\`\n\\`neo memory write|update|forget|search|list\\` · \\`neo log <type> \"<msg>\"\\`\n\\`neo config get <key>\\` · \\`neo config set <key> <value> --global\\` · \\`neo config list\\`\n\\`neo decision create \"<question>\" --options \"...\"\\` · \\`neo decision list\\`\n\\`neo child spawn --objective \"...\" --criteria \"...\" [--budget <usd>]\\`\n\\`neo directive create \"<action>\" [--duration \"2h\"]\\` · \\`neo directive list\\``;\n\nfunction getCommandsSection(heartbeatCount: number): string {\n return heartbeatCount <= 3 ? COMMANDS_FULL : 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.tasks);\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. Directives — standing instructions (always active)\n const directives = buildDirectivesSection(opts.activeDirectives);\n if (directives) {\n parts.push(directives);\n }\n\n // 4. Knowledge — accumulated memory (facts, procedures, feedback)\n parts.push(buildKnowledgeSection(opts.memories));\n\n // 5. Environment — stable infra (repos, MCP, budget)\n parts.push(...buildEnvironmentSections(opts));\n\n // 6. 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.tasks);\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(CHILD_SUPERVISOR_RULES);\n parts.push(HEARTBEAT_RULES);\n parts.push(REPORTING_RULES);\n parts.push(buildMemoryRulesCore());\n\n if (options.includeExamples) {\n parts.push(buildMemoryRulesExamples());\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 (from knowledge type), and warnings.\n * Focus is excluded — it's rendered separately at context top level.\n */\nfunction buildKnowledgeSection(memories: MemoryEntry[]): string {\n const knowledgeEntries = memories.filter((m) => m.type === \"knowledge\");\n const warningEntries = memories.filter((m) => m.type === \"warning\");\n\n const factEntries = knowledgeEntries.filter((m) => m.subtype === \"fact\" || !m.subtype);\n const procedureEntries = knowledgeEntries.filter((m) => m.subtype === \"procedure\");\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 // Warnings (replaces feedback)\n if (warningEntries.length > 0) {\n const lines = warningEntries\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_STATUSES = new Set([\"done\", \"abandoned\"]);\nconst MAX_TASKS = 15;\n\ninterface TaskGroup {\n initiative: string | null;\n tasks: TaskEntry[];\n}\n\nexport function buildWorkQueueSection(tasks: TaskEntry[]): string {\n const activeTasks = tasks.filter((t) => !DONE_STATUSES.has(t.status));\n const doneCount = tasks.filter((t) => DONE_STATUSES.has(t.status)).length;\n\n if (activeTasks.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(activeTasks);\n const lines = renderTaskGroups(groups);\n\n if (activeTasks.length > MAX_TASKS) {\n lines.push(` ... and ${activeTasks.length - MAX_TASKS} more pending`);\n }\n\n const header = `Work queue (${activeTasks.length} remaining, ${doneCount} done) \\u2014 dispatch the next eligible task:`;\n return `${header}\\n${lines.join(\"\\n\")}`;\n}\n\nfunction groupTasksByInitiative(tasks: TaskEntry[]): TaskGroup[] {\n const initiativeMap = new Map<string, TaskEntry[]>();\n const noInitiative: TaskEntry[] = [];\n\n for (const task of tasks) {\n if (task.initiative) {\n const group = initiativeMap.get(task.initiative) ?? [];\n group.push(task);\n initiativeMap.set(task.initiative, 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 PRIORITY_ORDER: Record<string, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n};\n\nfunction byPriority(a: TaskEntry, b: TaskEntry): number {\n const aOrder = PRIORITY_ORDER[a.priority ?? \"medium\"] ?? 2;\n const bOrder = PRIORITY_ORDER[b.priority ?? \"medium\"] ?? 2;\n return aOrder - bOrder;\n}\n\nfunction partitionTasks(tasks: TaskEntry[]): {\n active: TaskEntry[];\n blocked: TaskEntry[];\n pending: TaskEntry[];\n} {\n const active: TaskEntry[] = [];\n const blocked: TaskEntry[] = [];\n const pending: TaskEntry[] = [];\n for (const t of tasks) {\n if (t.status === \"in_progress\") active.push(t);\n else if (t.status === \"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(byPriority)[0];\n const ctx = nextEligible?.context ? ` -> ${nextEligible.context}` : \"\";\n const nextLabel = nextEligible\n ? ` (next: ${nextEligible.title.slice(0, 30)}${nextEligible.title.length > 30 ? \"...\" : \"\"} [${nextEligible.priority ?? \"medium\"}])`\n : \"\";\n return `[${group.initiative}] ${active.length} active, ${pending.length} pending${nextLabel}${ctx}`;\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(byPriority)[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: TaskEntry): string {\n const marker = formatTaskMarker(task.status);\n const priority = task.priority ? `[${task.priority}] ` : \"\";\n const scope = task.scope !== \"global\" ? ` (${getBasename(task.scope)})` : \"\";\n const run = task.runId ? ` [run ${task.runId.slice(0, 8)}]` : \"\";\n const ctx = task.context ? ` \\u2192 ${task.context}` : \"\";\n return `${marker} ${priority}${task.title}${scope}${run}${ctx}`;\n}\n\nfunction formatTaskMarker(status: string): string {\n switch (status) {\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 case \"child_supervisor\": {\n const msg = event.message;\n switch (msg.type) {\n case \"progress\":\n return `Child [${msg.supervisorId}] progress: ${msg.summary}`;\n case \"complete\":\n return `Child [${msg.supervisorId}] COMPLETE: ${msg.summary}\\nEvidence:\\n${msg.evidence.map((e) => ` - ${e}`).join(\"\\n\")}`;\n case \"blocked\":\n return `Child [${msg.supervisorId}] BLOCKED [${msg.urgency}]: ${msg.reason}\\nQuestion: ${msg.question}`;\n case \"failed\":\n return `Child [${msg.supervisorId}] FAILED: ${msg.error}`;\n case \"session\":\n return `Child [${msg.supervisorId}] session started: ${msg.sessionId}`;\n }\n }\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// ─── Directives ─────────────────────────────────────────\n\n/**\n * Build the active directives section.\n * Directives are standing instructions that apply continuously, not only during idle.\n */\nfunction buildDirectivesSection(directives: Directive[] | undefined): string {\n if (!directives || directives.length === 0) {\n return \"\";\n }\n\n const lines = directives.map((d) => {\n const priority = d.priority > 0 ? ` [priority: ${d.priority}]` : \"\";\n const expiry = d.expiresAt\n ? ` (expires: ${new Date(d.expiresAt).toLocaleString()})`\n : \" (indefinite)\";\n const desc = d.description ? ` — ${d.description}` : \"\";\n return `- **${d.action}**${priority}${expiry}${desc}`;\n });\n\n return `Active directives (${directives.length}):\n${lines.join(\"\\n\")}\n\nThese are standing instructions. Apply them continuously — respecting priority and current budget.`;\n}\n\n/**\n * Check if this heartbeat has nothing to do.\n */\nexport function isIdleHeartbeat(opts: PromptOptions): boolean {\n const hasWork = buildWorkQueueSection(opts.tasks) !== \"\";\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: PromptOptions): 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 // Check for active directives\n const directivesSection = buildDirectivesSection(opts.activeDirectives);\n if (directivesSection) {\n return `${buildRoleSection(opts.heartbeatCount)}\n\n<context>\nNo events. No active runs. No pending tasks.\n${budgetLine}\n\n${directivesSection}\n\nRepositories:\n${repoList}\n</context>\n\n<reference>\n${getCommandsSection(opts.heartbeatCount)}\n</reference>\n\n<directive>\nNo active runs. You have standing directives — execute the highest-priority one that is feasible, then yield. Log your action with \\`neo log action\\`.\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 directives \\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: PromptOptions): 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 // Only include verbose examples in the first 3 heartbeats to reduce token waste\n const instructionParts = buildBaseInstructions(opts, {\n includeExamples: opts.heartbeatCount <= 3,\n });\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 // Only include verbose examples in the first 3 heartbeats to reduce token waste\n const instructionParts = buildBaseInstructions(opts, {\n includeExamples: opts.heartbeatCount <= 3,\n });\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. **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\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 | { kind: \"child_supervisor\"; message: ChildToParentMessage; timestamp: string };\n\n// ─── Failure report (written to inbox.jsonl on run failure) ──\n\nexport const failureReportSchema = z.object({\n type: z.literal(\"failure-report\"),\n runId: z.string(),\n task: z.string(),\n reason: z.string(),\n attemptCount: z.number().int().min(1),\n lastErrorType: z.enum([\"spawn_error\", \"timeout\", \"budget\", \"recovery_exhausted\", \"unknown\"]),\n suggestedAction: z.string(),\n costUsd: z.number(),\n timestamp: z.string(),\n});\n\nexport type FailureReport = z.infer<typeof failureReportSchema>;\n\n// ─── Focused supervisor child handle ─────────────────────\n\nexport const childHandleStatusSchema = z.enum([\n \"running\",\n \"blocked\",\n \"complete\",\n \"failed\",\n \"stalled\",\n]);\n\nexport const childHandleSchema = z.object({\n supervisorId: z.string(),\n objective: z.string(),\n depth: z.number().int().min(0).max(1),\n startedAt: z.string(),\n lastProgressAt: z.string(),\n costUsd: z.number().default(0),\n maxCostUsd: z.number().optional(),\n sessionId: z.string().optional(),\n status: childHandleStatusSchema,\n});\n\nexport type ChildHandle = z.infer<typeof childHandleSchema>;\n\n// ─── IPC protocol (child → parent) ───────────────────────\n\nexport const childToParentMessageSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"progress\"),\n supervisorId: z.string(),\n summary: z.string(),\n costDelta: z.number(),\n }),\n z.object({\n type: z.literal(\"complete\"),\n supervisorId: z.string(),\n summary: z.string(),\n evidence: z.array(z.string()),\n }),\n z.object({\n type: z.literal(\"blocked\"),\n supervisorId: z.string(),\n reason: z.string(),\n question: z.string(),\n urgency: z.enum([\"low\", \"high\"]),\n }),\n z.object({\n type: z.literal(\"failed\"),\n supervisorId: z.string(),\n error: z.string(),\n }),\n z.object({\n type: z.literal(\"session\"),\n supervisorId: z.string(),\n sessionId: z.string(),\n }),\n]);\n\nexport type ChildToParentMessage = z.infer<typeof childToParentMessageSchema>;\n\n// ─── IPC protocol (parent → child) ───────────────────────\n\nexport const parentToChildMessageSchema = z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"unblock\"), answer: z.string() }),\n z.object({ type: z.literal(\"stop\") }),\n z.object({ type: z.literal(\"inject\"), context: z.string() }),\n]);\n\nexport type ParentToChildMessage = z.infer<typeof parentToChildMessageSchema>;\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// ─── Heartbeat failure event ─────────────────────────────\n\nexport const heartbeatFailureEventSchema = z.object({\n type: z.literal(\"heartbeat_failure\"),\n supervisorId: z.string(),\n heartbeatId: z.string(),\n timestamp: z.string().datetime(),\n error: z.string().max(1000),\n consecutiveFailures: z.number().int().min(1),\n});\n\nexport type HeartbeatFailureEvent = z.infer<typeof heartbeatFailureEventSchema>;\n\n// ─── Ghost run recovered event ────────────────────────────\n\nexport const ghostRunRecoveredEventSchema = z.object({\n type: z.literal(\"ghost_run_recovered\"),\n supervisorId: z.string(),\n runId: z.string(),\n agent: z.string(),\n repo: z.string(),\n timestamp: z.string().datetime(),\n reason: z.literal(\"supervisor crashed\"),\n});\n\nexport type GhostRunRecoveredEvent = z.infer<typeof ghostRunRecoveredEventSchema>;\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 heartbeatFailureEventSchema,\n runDispatchedEventSchema,\n runCompletedEventSchema,\n ghostRunRecoveredEventSchema,\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 /** Promise-based mutex to serialize write operations */\n private writeLock: Promise<void> = Promise.resolve();\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 // Use write lock to prevent race conditions with concurrent webhook requests\n await this.withWriteLock(async () => {\n await appendFile(this.eventsPath, `${JSON.stringify(event)}\\n`, \"utf-8\");\n });\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 /**\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","import { randomUUID } from \"node:crypto\";\nimport { sleep } from \"@/shared/time\";\nimport type { AIAdapter } from \"./ai-adapter.js\";\nimport type { SupervisorStore } from \"./store.js\";\nimport {\n SUPERVISOR_BLOCKED_TOOL,\n SUPERVISOR_COMPLETE_TOOL,\n type SupervisorBlockedInput,\n type SupervisorCompleteInput,\n supervisorBlockedSchema,\n supervisorCompleteSchema,\n} from \"./supervisor-tools.js\";\n\nexport interface FocusedLoopOptions {\n supervisorId: string;\n objective: string;\n acceptanceCriteria: string[];\n adapter: AIAdapter;\n store: SupervisorStore;\n onComplete: (result: SupervisorCompleteInput) => void | Promise<void>;\n onBlocked: (blocked: SupervisorBlockedInput) => void | Promise<void>;\n onProgress: (summary: string, costDelta: number) => void | Promise<void>;\n tickIntervalMs?: number;\n systemPrompt?: string;\n}\n\n/**\n * Runs a persistent SDK conversation focused on a single objective.\n * Loops via runOnce() until supervisor_complete or supervisor_blocked is called,\n * or until stop() is called.\n */\nexport class FocusedLoop {\n private readonly options: FocusedLoopOptions;\n private stopping = false;\n private injectedContext: string[] = [];\n\n constructor(options: FocusedLoopOptions) {\n this.options = options;\n }\n\n /** Inject context from parent supervisor (via IPC inject message). */\n injectContext(context: string): void {\n this.injectedContext.push(context);\n }\n\n /** Signal the loop to stop after the current turn. */\n stop(): void {\n this.stopping = true;\n }\n\n /**\n * Execute one turn of the focused loop.\n * Returns true if the loop should continue, false if it should stop.\n */\n async runOnce(): Promise<boolean> {\n if (this.stopping) return false;\n\n const { supervisorId, objective, acceptanceCriteria, adapter, store } = this.options;\n\n const existingSessionId = await store.getSessionId(supervisorId);\n if (existingSessionId) {\n adapter.restoreSession({ provider: \"claude\", sessionId: existingSessionId });\n }\n\n const recentActivity = await store.getRecentActivity(supervisorId, 20);\n const injected = this.injectedContext.splice(0);\n\n const prompt = buildFocusedPrompt({\n objective,\n acceptanceCriteria,\n recentActivity: recentActivity.map((e) => e.summary),\n injectedContext: injected,\n });\n\n const queryOptions = {\n prompt,\n tools: [SUPERVISOR_COMPLETE_TOOL, SUPERVISOR_BLOCKED_TOOL],\n ...(this.options.systemPrompt !== undefined && { systemPrompt: this.options.systemPrompt }),\n };\n\n for await (const message of adapter.query(queryOptions)) {\n const handle = adapter.getSessionHandle();\n if (handle?.provider === \"claude\") {\n await store.saveSessionId(supervisorId, handle.sessionId);\n }\n\n if (message.kind === \"tool_use\") {\n const terminal = await this.handleToolUse(message.toolName, message.toolInput);\n if (terminal) return false;\n } else if (message.kind === \"text\" && message.text) {\n await store.appendActivity(supervisorId, {\n id: randomUUID(),\n type: \"thinking\",\n summary: message.text.slice(0, 200),\n timestamp: new Date().toISOString(),\n });\n }\n }\n\n await this.options.onProgress(\"Turn complete\", 0);\n return !this.stopping;\n }\n\n /**\n * Run the full loop until complete, blocked, or stopped.\n */\n async run(): Promise<void> {\n const tickMs = this.options.tickIntervalMs ?? 30_000;\n\n while (!this.stopping) {\n const shouldContinue = await this.runOnce();\n if (!shouldContinue) break;\n if (tickMs > 0) await sleep(tickMs);\n }\n }\n\n // ─── Private helpers ──────────────────────────────────────\n\n /** Returns true if the tool call is terminal (complete or blocked). */\n private async handleToolUse(toolName: string | undefined, toolInput: unknown): Promise<boolean> {\n const { supervisorId, store } = this.options;\n\n if (toolName === \"supervisor_complete\") {\n const parsed = supervisorCompleteSchema.safeParse(toolInput);\n if (parsed.success) {\n await store.appendActivity(supervisorId, {\n id: randomUUID(),\n type: \"action\",\n summary: `supervisor_complete: ${parsed.data.summary}`,\n timestamp: new Date().toISOString(),\n });\n await this.options.onComplete(parsed.data);\n return true;\n }\n }\n\n if (toolName === \"supervisor_blocked\") {\n const parsed = supervisorBlockedSchema.safeParse(toolInput);\n if (parsed.success) {\n await store.appendActivity(supervisorId, {\n id: randomUUID(),\n type: \"decision\",\n summary: `supervisor_blocked: ${parsed.data.reason}`,\n timestamp: new Date().toISOString(),\n });\n await this.options.onBlocked(parsed.data);\n return true;\n }\n }\n\n return false;\n }\n}\n\n// ─── Prompt builder ───────────────────────────────────────\n\nfunction buildFocusedPrompt(opts: {\n objective: string;\n acceptanceCriteria: string[];\n recentActivity: string[];\n injectedContext: string[];\n}): string {\n const criteria =\n opts.acceptanceCriteria.length > 0\n ? opts.acceptanceCriteria.map((c) => `- ${c}`).join(\"\\n\")\n : \"- No specific criteria — use your judgment\";\n\n const activity =\n opts.recentActivity.length > 0\n ? opts.recentActivity.slice(-10).join(\"\\n\")\n : \"No previous activity\";\n\n const injected =\n opts.injectedContext.length > 0\n ? `\\n### Context from parent supervisor\\n${opts.injectedContext.join(\"\\n\")}\\n`\n : \"\";\n\n return `## Your objective\n${opts.objective}\n\n## Acceptance criteria (defined at dispatch — you must meet ALL of these)\n${criteria}\n\n## Recent activity\n${activity}\n${injected}\n## Instructions\nAssess current progress toward the objective. Dispatch agents as needed.\nWhen ALL acceptance criteria are verifiably met, call \\`supervisor_complete\\` with evidence.\nIf you cannot proceed without a decision, call \\`supervisor_blocked\\`.\nDo NOT call \\`supervisor_complete\\` unless you have objective evidence.`;\n}\n","import { z } from \"zod\";\n\n// ─── Schemas ─────────────────────────────────────────────\n\nexport const criteriaResultSchema = z.object({\n criterion: z.string(),\n met: z.boolean(),\n evidence: z.string(),\n});\n\nexport const supervisorCompleteSchema = z.object({\n summary: z.string(),\n evidence: z.array(z.string()).min(1, \"At least one piece of evidence required\"),\n branch: z.string().optional(),\n criteriaResults: z.array(criteriaResultSchema),\n});\n\nexport const supervisorBlockedSchema = z.object({\n reason: z.string(),\n question: z.string(),\n context: z.string(),\n urgency: z.enum([\"low\", \"high\"]),\n});\n\n// ─── Types ───────────────────────────────────────────────\n\nexport type SupervisorCompleteInput = z.infer<typeof supervisorCompleteSchema>;\nexport type SupervisorBlockedInput = z.infer<typeof supervisorBlockedSchema>;\nexport type CriteriaResult = z.infer<typeof criteriaResultSchema>;\n\n// ─── Tool definitions (passed to AIAdapter) ──────────────\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\nexport const SUPERVISOR_COMPLETE_TOOL: ToolDefinition = {\n name: \"supervisor_complete\",\n description:\n \"Call this when ALL acceptance criteria are met and you have objective evidence. \" +\n \"Do NOT call this speculatively — provide real evidence (PR URL, CI status, test output).\",\n inputSchema: {\n type: \"object\",\n properties: {\n summary: { type: \"string\", description: \"What was accomplished\" },\n evidence: {\n type: \"array\",\n items: { type: \"string\" },\n minItems: 1,\n description: \"PR URLs, CI links, test output snippets\",\n },\n branch: { type: \"string\", description: \"Branch name if applicable\" },\n criteriaResults: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n criterion: { type: \"string\" },\n met: { type: \"boolean\" },\n evidence: { type: \"string\" },\n },\n required: [\"criterion\", \"met\", \"evidence\"],\n },\n description: \"Result for each acceptance criterion\",\n },\n },\n required: [\"summary\", \"evidence\", \"criteriaResults\"],\n },\n};\n\nexport const SUPERVISOR_BLOCKED_TOOL: ToolDefinition = {\n name: \"supervisor_blocked\",\n description:\n \"Call this when you cannot proceed without a decision from the parent supervisor. \" +\n \"Only call when genuinely blocked — not when uncertain.\",\n inputSchema: {\n type: \"object\",\n properties: {\n reason: { type: \"string\", description: \"Why you cannot proceed\" },\n question: { type: \"string\", description: \"The specific decision needed\" },\n context: { type: \"string\", description: \"Relevant context for the decision\" },\n urgency: { type: \"string\", enum: [\"low\", \"high\"] },\n },\n required: [\"reason\", \"question\", \"context\", \"urgency\"],\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 {\n // Non-critical — best effort cleanup, silently ignore\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 // Mark as failed if:\n // 1. Run has no PID (legacy run or race condition)\n // 2. Run belongs to current process\n // 3. Run belongs to a dead process (ghost run from crashed supervisor)\n if (run.pid && run.pid !== process.pid) {\n // Check if the other process is still alive\n const isAlive = this.isProcessAlive(run.pid);\n if (isAlive) return; // Skip runs owned by other alive processes\n }\n\n run.status = \"failed\";\n run.blockedReason = run.pid === process.pid ? undefined : \"supervisor crashed\";\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, silently ignore\n }\n }\n\n /**\n * Check if a process is alive. Extracted for testability.\n */\n private isProcessAlive(pid: number): boolean {\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 return false;\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 { z } from \"zod\";\nimport type { ToolDefinition } from \"./supervisor-tools.js\";\n\n// ─── Schema ──────────────────────────────────────────────\n\nexport const spawnChildSupervisorInputSchema = z.object({\n objective: z.string().min(1, \"Objective is required\"),\n acceptanceCriteria: z.array(z.string()).min(1, \"At least one acceptance criterion required\"),\n maxCostUsd: z.number().positive().optional(),\n});\n\nexport type SpawnChildSupervisorInput = z.infer<typeof spawnChildSupervisorInputSchema>;\n\n// ─── Tool Definition ─────────────────────────────────────\n\nexport const SPAWN_CHILD_SUPERVISOR_TOOL: ToolDefinition = {\n name: \"spawn_child_supervisor\",\n description:\n \"Spawn a focused child supervisor to handle a specific objective autonomously. \" +\n \"Use this when a task is complex enough to warrant independent orchestration. \" +\n \"The child runs until all acceptance criteria are met or it gets blocked.\",\n inputSchema: {\n type: \"object\",\n properties: {\n objective: {\n type: \"string\",\n description: \"The specific goal for the child supervisor to achieve\",\n },\n acceptanceCriteria: {\n type: \"array\",\n items: { type: \"string\" },\n minItems: 1,\n description: \"Measurable criteria that define completion\",\n },\n maxCostUsd: {\n type: \"number\",\n description: \"Optional budget cap in USD. Child is stopped if exceeded.\",\n },\n },\n required: [\"objective\", \"acceptanceCriteria\"],\n },\n};\n","import { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ActivityEntry } from \"../schemas.js\";\nimport type { FocusedSupervisorState, SupervisorStore } from \"../store.js\";\n\n/**\n * JSONL-backed SupervisorStore implementation.\n * Zero dependencies beyond Node.js built-ins.\n * Default implementation for CLI usage (zero-infra).\n *\n * Layout per supervisor:\n * <baseDir>/<supervisorId>/session.json — SDK session ID\n * <baseDir>/<supervisorId>/activity.jsonl — activity log\n * <baseDir>/<supervisorId>/state.json — current state\n * <baseDir>/<supervisorId>/cost.json — accumulated cost\n */\nexport class JsonlSupervisorStore implements SupervisorStore {\n private readonly baseDir: string;\n /** Promise-based mutex to serialize write operations */\n private writeLock: Promise<void> = Promise.resolve();\n\n constructor(baseDir: string) {\n this.baseDir = baseDir;\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 private supervisorDir(supervisorId: string): string {\n return path.join(this.baseDir, supervisorId);\n }\n\n private async ensureDir(supervisorId: string): Promise<string> {\n const dir = this.supervisorDir(supervisorId);\n await mkdir(dir, { recursive: true });\n return dir;\n }\n\n // ─── Session ───────────────────────────────────────────\n\n async getSessionId(supervisorId: string): Promise<string | undefined> {\n const sessionPath = path.join(this.supervisorDir(supervisorId), \"session.json\");\n try {\n const raw = await readFile(sessionPath, \"utf-8\");\n const parsed = JSON.parse(raw) as { sessionId: string };\n return parsed.sessionId;\n } catch {\n return undefined;\n }\n }\n\n async saveSessionId(supervisorId: string, sessionId: string): Promise<void> {\n const dir = await this.ensureDir(supervisorId);\n await writeFile(path.join(dir, \"session.json\"), JSON.stringify({ sessionId }), \"utf-8\");\n }\n\n // ─── Activity ──────────────────────────────────────────\n\n async appendActivity(supervisorId: string, entry: ActivityEntry): Promise<void> {\n const dir = await this.ensureDir(supervisorId);\n await this.withWriteLock(async () => {\n await appendFile(path.join(dir, \"activity.jsonl\"), `${JSON.stringify(entry)}\\n`, \"utf-8\");\n });\n }\n\n async getRecentActivity(supervisorId: string, limit = 50): Promise<ActivityEntry[]> {\n const activityPath = path.join(this.supervisorDir(supervisorId), \"activity.jsonl\");\n try {\n const raw = await readFile(activityPath, \"utf-8\");\n const lines = raw.trim().split(\"\\n\").filter(Boolean);\n const last = lines.slice(-limit);\n return last.flatMap((line) => {\n try {\n return [JSON.parse(line) as ActivityEntry];\n } catch {\n return [];\n }\n });\n } catch {\n return [];\n }\n }\n\n // ─── State ─────────────────────────────────────────────\n\n async getState(supervisorId: string): Promise<FocusedSupervisorState | null> {\n const statePath = path.join(this.supervisorDir(supervisorId), \"state.json\");\n try {\n const raw = await readFile(statePath, \"utf-8\");\n return JSON.parse(raw) as FocusedSupervisorState;\n } catch {\n return null;\n }\n }\n\n async saveState(supervisorId: string, state: FocusedSupervisorState): Promise<void> {\n const dir = await this.ensureDir(supervisorId);\n await writeFile(path.join(dir, \"state.json\"), JSON.stringify(state, null, 2), \"utf-8\");\n }\n\n // ─── Cost ──────────────────────────────────────────────\n\n async recordCost(supervisorId: string, costUsd: number): Promise<void> {\n await this.withWriteLock(async () => {\n const current = await this.getTotalCost(supervisorId);\n const dir = await this.ensureDir(supervisorId);\n await writeFile(\n path.join(dir, \"cost.json\"),\n JSON.stringify({ totalCostUsd: current + costUsd }),\n \"utf-8\",\n );\n });\n }\n\n async getTotalCost(supervisorId: string): Promise<number> {\n const costPath = path.join(this.supervisorDir(supervisorId), \"cost.json\");\n try {\n const raw = await readFile(costPath, \"utf-8\");\n const parsed = JSON.parse(raw) as { totalCostUsd: number };\n return parsed.totalCostUsd;\n } catch {\n return 0;\n }\n }\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 getFocusedSupervisorDir,\n getJournalsDir,\n getRepoRunsDir,\n getRunDispatchPath,\n getRunLogPath,\n getRunsDir,\n getSupervisorActivityPath,\n getSupervisorChildrenPath,\n getSupervisorDecisionsPath,\n getSupervisorDir,\n getSupervisorEventsPath,\n getSupervisorInboxPath,\n getSupervisorLockPath,\n getSupervisorStatePath,\n getSupervisorsDir,\n getWorkerStartedPath,\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\";\n// ─── Decisions ─────────────────────────────────────────\n// ─── Supervisor children ───────────────────────────────\n// ─── Child supervisor ──────────────────────────────\nexport type {\n ActivityEntry,\n ActivityQueryOptions,\n AIAdapter,\n AIQueryOptions,\n ChildHandle,\n ChildSpawnCommand,\n Decision,\n DecisionInput,\n DecisionOption,\n Directive,\n DirectiveCreateInput,\n DirectiveTrigger,\n FocusedLoopOptions,\n HeartbeatLoopOptions,\n InboxMessage,\n LogBufferEntry,\n ParentToChildMessage,\n QueuedEvent,\n SessionHandle,\n SpawnChildOptions,\n SpawnChildResult,\n SpawnChildSupervisorInput,\n SupervisorDaemonOptions,\n SupervisorDaemonState,\n SupervisorMessage,\n SupervisorStatus,\n WebhookIncomingEvent,\n} from \"@/supervisor/index\";\n// ─── Supervisor (daemon) ──────────────────────────────\nexport {\n ActivityLog,\n activityEntrySchema,\n appendLogBuffer,\n ClaudeAdapter,\n DecisionStore,\n DirectiveStore,\n decisionOptionSchema,\n decisionSchema,\n EventQueue,\n FocusedLoop,\n HeartbeatLoop,\n inboxMessageSchema,\n JsonlSupervisorStore,\n parseChildSpawnCommand,\n parseDirectiveDuration,\n readChildrenFile,\n readLogBuffer,\n SPAWN_CHILD_SUPERVISOR_TOOL,\n StatusReader,\n SupervisorDaemon,\n spawnChildSupervisor,\n spawnChildSupervisorInputSchema,\n supervisorDaemonStateSchema,\n supervisorStatusSchema,\n WebhookServer,\n webhookIncomingEventSchema,\n} from \"@/supervisor/index\";\nexport type {\n Embedder,\n KnowledgeSubtype,\n MemoryEntry,\n MemoryQuery,\n MemoryStats,\n MemoryType,\n MemoryWriteInput,\n} from \"@/supervisor/memory/index\";\n// ─── Memory ───────────────────────────────────────────\nexport { knowledgeSubtypeSchema, MemoryStore } from \"@/supervisor/memory/index\";\n// ─── Task Store ──────────────────────────────────────\nexport type {\n TaskCreateInput,\n TaskEntry,\n TaskPriority,\n TaskQuery,\n TaskStatus,\n} from \"@/supervisor/task-store\";\nexport {\n TaskStore,\n taskEntrySchema,\n taskPrioritySchema,\n taskStatusSchema,\n} from \"@/supervisor/task-store\";\n// ─── Types (explicit public exports) ──────────────────────\nexport type {\n ActiveSession,\n AgentDefinition,\n AgentMessageEvent,\n AgentToolUseEvent,\n BudgetAlertEvent,\n CostEntry,\n CostUpdateEvent,\n DispatchInput,\n GateWaitingEvent,\n HookEvent,\n Middleware,\n MiddlewareContext,\n MiddlewareContextMap,\n MiddlewareEvent,\n MiddlewareHandler,\n MiddlewareResult,\n NeoEvent,\n OrchestratorShutdownEvent,\n OrchestratorStatus,\n PersistedRun,\n Priority,\n QueueDequeueEvent,\n QueueEnqueueEvent,\n ResolvedAgent,\n RunContext,\n SessionCompleteEvent,\n SessionFailEvent,\n SessionStartEvent,\n StepCompleteEvent,\n StepResult,\n StepStartEvent,\n SubagentDefinition,\n TaskResult,\n} 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":";AAAA,SAAS,gBAAgB;AACzB,OAAO,UAAU;AACjB,SAAS,SAAS,iBAAiB;;;ACFnC,SAAS,SAAS;AAIX,IAAM,mBAAmB,EAAE,KAAK,CAAC,QAAQ,UAAU,OAAO,CAAC;AAI3D,IAAM,kBAAkB,EAAE,KAAK;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAIM,IAAM,uBAAuB,EAAE,MAAM,CAAC,iBAAiB,EAAE,QAAQ,YAAY,CAAC,CAAC;AAI/E,IAAM,qBAAqB,EAAE,KAAK,CAAC,YAAY,UAAU,CAAC;AAI1D,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,aAAa,EAAE,OAAO;AAAA,EACtB,QAAQ,EAAE,OAAO;AAAA,EACjB,OAAO,EAAE,MAAM,eAAe,EAAE,SAAS;AAAA,EACzC,OAAO,iBAAiB,SAAS;AACnC,CAAC;AAIM,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,MAAM,EAAE,OAAO;AAAA,EACf,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,iBAAiB,SAAS;AAAA,EACjC,OAAO,EAAE,MAAM,oBAAoB,EAAE,SAAS;AAAA,EAC9C,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,SAAS,mBAAmB,SAAS;AAAA,EACrC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACpC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACzC,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,wBAAwB,EAAE,SAAS;AAClE,CAAC;;;ADjDD,eAAsB,cAAc,UAAwC;AAC1E,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,SAAS,UAAU,OAAO;AAAA,EACxC,QAAQ;AACN,UAAM,IAAI,MAAM,yBAAyB,QAAQ,EAAE;AAAA,EACrD;AAEA,MAAI;AACJ,MAAI;AACF,aAAS,UAAU,GAAG;AAAA,EACxB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,8BAA8B,QAAQ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC7F;AAAA,EACF;AAEA,QAAM,SAAS,kBAAkB,UAAU,MAAM;AACjD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,SAAS,OAAO,MAAM,OACzB,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAClD,KAAK,IAAI;AACZ,UAAM,IAAI,MAAM,2BAA2B,QAAQ;AAAA,EAAM,MAAM,EAAE;AAAA,EACnE;AAEA,QAAM,SAAS,OAAO;AAGtB,MAAI,OAAO,QAAQ,SAAS,KAAK,GAAG;AAClC,UAAM,aAAa,KAAK,QAAQ,KAAK,QAAQ,QAAQ,GAAG,OAAO,MAAM;AACrE,QAAI;AACF,aAAO,SAAS,MAAM,SAAS,YAAY,OAAO;AAAA,IACpD,SAAS,KAAK;AAEZ,YAAM,IAAI;AAAA,QACR,0BAA0B,UAAU,mBAAmB,QAAQ,aAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC9H;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,QAAQ;AACjB,eAAW,CAAC,MAAM,QAAQ,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC5D,UAAI,SAAS,OAAO,SAAS,KAAK,GAAG;AACnC,cAAM,qBAAqB,KAAK,QAAQ,KAAK,QAAQ,QAAQ,GAAG,SAAS,MAAM;AAC/E,YAAI;AACF,mBAAS,SAAS,MAAM,SAAS,oBAAoB,OAAO;AAAA,QAC9D,SAAS,KAAK;AACZ,gBAAM,IAAI;AAAA,YACR,aAAa,IAAI,4BAA4B,kBAAkB,mBAAmB,QAAQ,aAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UACzJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AEpEA,SAAS,eAAe;AACxB,OAAOA,WAAU;;;ACUV,SAAS,aACd,QACA,UACe;AACf,QAAM,cACJ,OAAO,YACN,SAAS,IAAI,OAAO,IAAI,KAAK,OAAO,YAAY,SAAY,OAAO,OAAO;AAE7E,MAAI,gBAAgB,QAAW;AAC7B,WAAO,qBAAqB,QAAQ,aAAa,QAAQ;AAAA,EAC3D;AAEA,SAAO,mBAAmB,MAAM;AAClC;AAIA,SAAS,qBACP,QACA,aACA,UACe;AACf,QAAM,OAAO,SAAS,IAAI,WAAW;AAErC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,IAAI,cAAc,WAAW;AAAA,IAChD;AAAA,EACF;AAEA,QAAM,QAAQ,WAAW,OAAO,OAAO,KAAK,KAAK;AACjD,QAAM,SAAS,YAAY,OAAO,QAAQ,OAAO,cAAc,KAAK,MAAM;AAC1E,QAAM,aAAa,oBAAoB,KAAK,YAAY,OAAO,UAAU;AACzE,QAAM,SAAS;AAAA,IACb,KAAK;AAAA,IACL,OAAO;AAAA,EACT;AAEA,QAAM,aAA8B;AAAA,IAClC,aAAa,OAAO,eAAe,KAAK,eAAe;AAAA,IACvD;AAAA,IACA;AAAA,IACA,OAAO,OAAO,SAAS,KAAK,SAAS;AAAA,IACrC,GAAI,WAAW,SAAS,IAAI,EAAE,WAAW,IAAI,CAAC;AAAA,IAC9C,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb;AAAA,IACA,SAAS,OAAO,WAAW,KAAK,WAAW;AAAA,IAC3C,GAAI,OAAO,aAAa,SACpB,EAAE,UAAU,OAAO,SAAS,IAC5B,KAAK,aAAa,SAChB,EAAE,UAAU,KAAK,SAAS,IAC1B,CAAC;AAAA,IACP,GAAI,OAAO,YAAY,SACnB,EAAE,SAAS,OAAO,QAAQ,IAC1B,KAAK,YAAY,SACf,EAAE,SAAS,KAAK,QAAQ,IACxB,CAAC;AAAA,IACP,GAAI,OAAO,YAAY,SACnB,EAAE,SAAS,OAAO,QAAQ,IAC1B,KAAK,YAAY,SACf,EAAE,SAAS,KAAK,QAAQ,IACxB,CAAC;AAAA,IACP,QAAQ,OAAO,SAAS,eAAe,CAAC,OAAO,UAAU,aAAa;AAAA,EACxE;AACF;AAIA,SAAS,mBAAmB,QAAoC;AAC9D,MAAI,CAAC,OAAO,aAAa;AACvB,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,IAAI;AAAA,IACvB;AAAA,EACF;AACA,MAAI,CAAC,OAAO,OAAO;AACjB,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,IAAI;AAAA,IACvB;AAAA,EACF;AACA,MAAI,CAAC,OAAO,OAAO;AACjB,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,IAAI;AAAA,IACvB;AAAA,EACF;AACA,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,IAAI;AAAA,IACvB;AAAA,EACF;AACA,MAAI,CAAC,OAAO,QAAQ;AAClB,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,IAAI;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,QAAQ,OAAO,MAAM,OAAO,CAAC,MAAsB,MAAM,YAAY;AAE3E,MAAI,SAAS,OAAO;AACpB,MAAI,OAAO,cAAc;AACvB,aAAS,GAAG,MAAM;AAAA;AAAA,EAAO,OAAO,YAAY;AAAA,EAC9C;AAEA,QAAM,aAA8B;AAAA,IAClC,aAAa,OAAO;AAAA,IACpB;AAAA,IACA;AAAA,IACA,OAAO,OAAO;AAAA,IACd,GAAI,OAAO,YAAY,SAAS,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;AAAA,IACrE,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAA6C,IAAI,CAAC;AAAA,EACzF;AAEA,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,GAAI,OAAO,aAAa,SAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;AAAA,IACrE,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IAClE,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IAClE,QAAQ;AAAA,EACV;AACF;AAIA,SAAS,WAAW,aAAmC,WAA2C;AAChG,MAAI,CAAC,YAAa,QAAQ,aAAa,CAAC;AACxC,MAAI,YAAY,SAAS,YAAY,GAAG;AACtC,UAAM,WAAW,YAAY,OAAO,CAAC,MAAM,MAAM,YAAY;AAC7D,WAAO,CAAC,GAAI,aAAa,CAAC,GAAI,GAAG,QAAQ;AAAA,EAC3C;AACA,SAAO;AACT;AAEA,SAAS,YACP,cACA,cACA,YACQ;AACR,MAAI,SAAS,gBAAgB,cAAc;AAC3C,MAAI,cAAc;AAChB,aAAS,GAAG,MAAM;AAAA;AAAA,EAAO,YAAY;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,MAA4B,UAA0C;AACjG,MAAI,CAAC,MAAM,UAAU,CAAC,UAAU,OAAQ,QAAO,CAAC;AAChD,SAAO,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAI,QAAQ,CAAC,GAAI,GAAI,YAAY,CAAC,CAAE,CAAC,CAAC;AAC5D;AAEA,SAAS,YACP,MACA,UACgD;AAChD,MAAI,CAAC,QAAQ,CAAC,SAAU,QAAO;AAC/B,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,EAAE,GAAG,MAAM,GAAG,SAAS;AAChC;;;ADvKO,IAAM,gBAAN,MAAoB;AAAA,EACR;AAAA,EACA;AAAA,EACT,SAAS,oBAAI,IAA2B;AAAA,EAEhD,YAAY,YAAoB,WAAoB;AAClD,SAAK,aAAa;AAClB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,OAAO,MAAM;AAGlB,UAAM,iBAAiB,MAAM,kBAAkB,KAAK,UAAU;AAC9D,UAAM,aAAa,oBAAI,IAAyB;AAChD,eAAW,UAAU,gBAAgB;AACnC,iBAAW,IAAI,OAAO,MAAM,MAAM;AAAA,IACpC;AAGA,eAAW,UAAU,gBAAgB;AACnC,YAAM,WAAW,aAAa,QAAQ,UAAU;AAEhD,WAAK,OAAO,IAAI,OAAO,MAAM,EAAE,GAAG,UAAU,QAAQ,WAAW,CAAC;AAAA,IAClE;AAGA,QAAI,KAAK,WAAW;AAClB,UAAI;AACJ,UAAI;AACF,wBAAgB,MAAM,kBAAkB,KAAK,SAAS;AAAA,MACxD,SAAS,KAAK;AAGZ,gBAAQ;AAAA,UACN,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC7F;AACA,wBAAgB,CAAC;AAAA,MACnB;AAEA,iBAAW,UAAU,eAAe;AAClC,cAAM,WAAW,aAAa,QAAQ,UAAU;AAChD,aAAK,OAAO,IAAI,OAAO,MAAM,QAAQ;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IAAI,MAAyC;AAC3C,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,OAAwB;AACtB,WAAO,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC;AAAA,EACjC;AAAA,EAEA,IAAI,MAAuB;AACzB,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AACF;AAEA,eAAe,kBAAkB,KAAqC;AACpE,QAAM,UAAU,MAAM,QAAQ,GAAG;AACjC,QAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,KAAK,EAAE,SAAS,OAAO,CAAC;AAEhF,QAAM,UAAyB,CAAC;AAChC,aAAW,QAAQ,UAAU;AAC3B,UAAM,SAAS,MAAM,cAAcC,MAAK,KAAK,KAAK,IAAI,CAAC;AACvD,YAAQ,KAAK,MAAM;AAAA,EACrB;AACA,SAAO;AACT;;;AE5EA,IAAM,iBAA2C;AAAA,EAC/C,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACP;AAYO,IAAM,gBAAN,MAAuB;AAAA,EACX,QAAwB,CAAC;AAAA,EACzB;AAAA,EACT,mBAAmB;AAAA,EAE3B,YAAY,SAAiB;AAC3B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,QAAQ,OAAU,UAA0B;AAE1C,QAAI,KAAK,MAAM,WAAW,GAAG;AAC3B,WAAK,mBAAmB;AAAA,IAC1B;AAEA,QAAI,KAAK,MAAM,UAAU,KAAK,SAAS;AACrC,YAAM,IAAI,MAAM,eAAe,KAAK,OAAO,0BAA0B;AAAA,IACvE;AAEA,UAAM,OAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA,gBAAgB,KAAK;AAAA,IACvB;AAGA,QAAI,WAAW;AACf,aAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,YAAM,WAAW,KAAK,MAAM,CAAC;AAC7B,UAAI,YAAY,KAAK,gBAAgB,MAAM,QAAQ,IAAI,GAAG;AACxD,aAAK,MAAM,OAAO,GAAG,GAAG,IAAI;AAC5B,mBAAW;AACX;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,UAAU;AACb,WAAK,MAAM,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,UAAyB;AACvB,UAAM,OAAO,KAAK,MAAM,MAAM;AAC9B,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,OAAsB;AACpB,WAAO,KAAK,MAAM,CAAC,GAAG;AAAA,EACxB;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,UAAmB;AACrB,WAAO,KAAK,MAAM,WAAW;AAAA,EAC/B;AAAA,EAEA,OAAO,WAA0C;AAC/C,UAAM,QAAQ,KAAK,MAAM,UAAU,CAAC,UAAU,UAAU,MAAM,KAAK,CAAC;AACpE,QAAI,UAAU,GAAI,QAAO;AACzB,SAAK,MAAM,OAAO,OAAO,CAAC;AAC1B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAa,WAAgD;AAC3D,UAAM,QAAQ,KAAK,MAAM,UAAU,CAAC,UAAU,UAAU,MAAM,KAAK,CAAC;AACpE,QAAI,UAAU,GAAI,QAAO;AACzB,UAAM,UAAU,KAAK,MAAM,OAAO,OAAO,CAAC,EAAE,CAAC;AAC7C,QAAI,CAAC,QAAS,QAAO;AACrB,WAAO,QAAQ;AAAA,EACjB;AAAA;AAAA,EAGQ,gBAAgB,GAAiB,GAAyB;AAChE,UAAM,eAAe,eAAe,EAAE,QAAQ,IAAI,eAAe,EAAE,QAAQ;AAC3E,QAAI,iBAAiB,EAAG,QAAO;AAC/B,WAAO,EAAE,iBAAiB,EAAE;AAAA,EAC9B;AACF;;;ACvEO,IAAM,YAAN,MAAgB;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA,iBAAiB,oBAAI,IAAoB;AAAA;AAAA,EAEzC,aAAa,oBAAI,IAAoB;AAAA,EAEtD,YAAY,QAAyB,YAAgC,CAAC,GAAG;AACvE,SAAK,cAAc,OAAO;AAC1B,SAAK,aAAa,OAAO;AACzB,SAAK,QAAQ,IAAI,cAA4B,OAAO,YAAY,EAAE;AAClE,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QACJ,MACA,WACA,WAAqB,UACrB,QACe;AACf,QAAI,QAAQ,SAAS;AACnB,YAAM,OAAO,UAAU,IAAI,aAAa,8BAA8B,YAAY;AAAA,IACpF;AAEA,QAAI,KAAK,WAAW,IAAI,GAAG;AACzB,WAAK,SAAS,MAAM,SAAS;AAC7B;AAAA,IACF;AAEA,WAAO,IAAI,QAAc,CAACC,UAAS,WAAW;AAC5C,YAAM,QAAsB;AAAA,QAC1B;AAAA,QACA;AAAA,QACA,SAAAA;AAAA,QACA;AAAA,QACA,YAAY,KAAK,IAAI;AAAA,MACvB;AAEA,WAAK,MAAM,QAAQ,OAAO,QAAQ;AAClC,WAAK,UAAU,YAAY,WAAW,MAAM,KAAK,MAAM,IAAI;AAE3D,UAAI,QAAQ;AACV,cAAM,UAAU,MAAM;AACpB,eAAK,MAAM,OAAO,CAAC,MAAM,MAAM,KAAK;AACpC,iBAAO,OAAO,UAAU,IAAI,aAAa,8BAA8B,YAAY,CAAC;AAAA,QACtF;AACA,eAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAGxD,cAAM,gBAAgB,MAAM,OAAO,oBAAoB,SAAS,OAAO;AAAA,MACzE;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,QAAQ,WAAyB;AAC/B,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM;AAEX,SAAK,eAAe,OAAO,SAAS;AACpC,UAAM,QAAQ,KAAK,WAAW,IAAI,IAAI,KAAK;AAC3C,QAAI,SAAS,GAAG;AACd,WAAK,WAAW,OAAO,IAAI;AAAA,IAC7B,OAAO;AACL,WAAK,WAAW,IAAI,MAAM,QAAQ,CAAC;AAAA,IACrC;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGA,WAAW,MAAc,WAA4B;AACnD,QAAI,CAAC,KAAK,WAAW,IAAI,EAAG,QAAO;AACnC,SAAK,SAAS,MAAM,SAAS;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,cAAsB;AACpB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA;AAAA,EAGA,mBAAmB,MAAsB;AACvC,WAAO,KAAK,WAAW,IAAI,IAAI,KAAK;AAAA,EACtC;AAAA;AAAA,EAGA,YAAY,MAAuB;AACjC,WAAO,KAAK,WAAW,IAAI;AAAA,EAC7B;AAAA;AAAA,EAGA,aAAqB;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEQ,WAAW,MAAuB;AACxC,QAAI,KAAK,eAAe,QAAQ,KAAK,YAAa,QAAO;AACzD,UAAM,YAAY,KAAK,WAAW,IAAI,IAAI,KAAK;AAC/C,WAAO,YAAY,KAAK;AAAA,EAC1B;AAAA,EAEQ,SAAS,MAAc,WAAyB;AACtD,SAAK,eAAe,IAAI,WAAW,IAAI;AACvC,SAAK,WAAW,IAAI,OAAO,KAAK,WAAW,IAAI,IAAI,KAAK,KAAK,CAAC;AAAA,EAChE;AAAA,EAEQ,eAAqB;AAE3B,UAAM,QAAQ,KAAK,MAAM,aAAa,CAAC,MAAM,KAAK,WAAW,EAAE,IAAI,CAAC;AACpE,QAAI,CAAC,MAAO;AAEZ,SAAK,SAAS,MAAM,MAAM,MAAM,SAAS;AACzC,UAAM,gBAAgB;AACtB,UAAM,WAAW,KAAK,IAAI,IAAI,MAAM;AACpC,SAAK,UAAU,YAAY,MAAM,WAAW,MAAM,MAAM,QAAQ;AAChE,UAAM,QAAQ;AAAA,EAChB;AACF;;;AC1JA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,OAAO,YAAAC,WAAU,iBAAiB;AAC3C,OAAOC,WAAU;AACjB,SAAS,SAASC,YAAW,aAAa,qBAAqB;;;ACH/D,SAAS,eAAe;AACxB,OAAOC,WAAU;AAMV,SAAS,aAAqB;AACnC,SAAOA,MAAK,KAAK,QAAQ,GAAG,MAAM;AACpC;AAEO,SAAS,iBAAyB;AACvC,SAAOA,MAAK,KAAK,WAAW,GAAG,UAAU;AAC3C;AAEO,SAAS,aAAqB;AACnC,SAAOA,MAAK,KAAK,WAAW,GAAG,MAAM;AACvC;AAMO,SAAS,WAAW,MAA2D;AACpF,QAAM,MAAM,KAAK,QAAQA,MAAK,SAAS,KAAK,IAAI;AAChD,SAAO,IACJ,YAAY,EACZ,QAAQ,iBAAiB,GAAG,EAC5B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE;AACzB;AAKO,SAAS,eAAe,UAA0B;AACvD,SAAOA,MAAK,KAAK,WAAW,GAAG,QAAQ;AACzC;AAKO,SAAS,mBAAmB,UAAkB,OAAuB;AAC1E,SAAOA,MAAK,KAAK,eAAe,QAAQ,GAAG,GAAG,KAAK,gBAAgB;AACrE;AAKO,SAAS,cAAc,UAAkB,OAAuB;AACrE,SAAOA,MAAK,KAAK,eAAe,QAAQ,GAAG,GAAG,KAAK,MAAM;AAC3D;AAQO,SAAS,qBAAqB,UAAkB,OAAuB;AAC5E,SAAOA,MAAK,KAAK,eAAe,QAAQ,GAAG,GAAG,KAAK,UAAU;AAC/D;AAKO,SAAS,oBAA4B;AAC1C,SAAOA,MAAK,KAAK,WAAW,GAAG,aAAa;AAC9C;AAKO,SAAS,iBAAiB,MAAsB;AACrD,SAAOA,MAAK,KAAK,kBAAkB,GAAG,IAAI;AAC5C;AAKO,SAAS,uBAAuB,MAAsB;AAC3D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,YAAY;AACvD;AAEO,SAAS,0BAA0B,MAAsB;AAC9D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,gBAAgB;AAC3D;AAEO,SAAS,uBAAuB,MAAsB;AAC3D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,aAAa;AACxD;AAEO,SAAS,wBAAwB,MAAsB;AAC5D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,cAAc;AACzD;AAEO,SAAS,sBAAsB,MAAsB;AAC1D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,aAAa;AACxD;AAEO,SAAS,2BAA2B,MAAsB;AAC/D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,iBAAiB;AAC5D;AAMO,SAAS,0BAA0B,MAAsB;AAC9D,SAAOA,MAAK,KAAK,iBAAiB,IAAI,GAAG,eAAe;AAC1D;AAKO,SAAS,2BAAmC;AACjD,SAAOA,MAAK,KAAK,kBAAkB,GAAG,SAAS;AACjD;AAKO,SAAS,wBAAwB,cAA8B;AACpE,SAAOA,MAAK,KAAK,yBAAyB,GAAG,YAAY;AAC3D;;;AC5HA,SAAS,KAAAC,UAAS;AAIlB,IAAM,sBAAsBA,GAAE,OAAO;AAAA,EACnC,MAAMA,GAAE,QAAQ,MAAM;AAAA,EACtB,KAAKA,GAAE,OAAO;AAAA,EACd,SAASA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,OAAO,CAAC,EAAE,SAAS;AACrD,CAAC;AAED,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EACpC,MAAMA,GAAE,QAAQ,OAAO;AAAA,EACvB,SAASA,GAAE,OAAO;AAAA,EAClB,MAAMA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACnC,KAAKA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,OAAO,CAAC,EAAE,SAAS;AACjD,CAAC;AAEM,IAAM,wBAAwBA,GAAE,mBAAmB,QAAQ;AAAA,EAChE;AAAA,EACA;AACF,CAAC;AAIM,IAAM,oBAAoBA,GAAE,KAAK,CAAC,MAAM,QAAQ,CAAC,EAAE,QAAQ,QAAQ;AAInE,IAAM,mBAAmBA,GAAE,OAAO;AAAA,EACvC,MAAMA,GAAE,OAAO;AAAA,EACf,MAAMA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,eAAeA,GAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,EACxC,cAAcA,GAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,EACvC,YAAYA,GAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,EACvC,aAAa;AACf,CAAC;AAIM,IAAM,0BAA0BA,GACpC,OAAO;AAAA,EACN,aAAaA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACjC,YAAYA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAChC,UAAUA,GAAE,OAAO,EAAE,QAAQ,EAAE;AACjC,CAAC,EACA,QAAQ,EAAE,aAAa,GAAG,YAAY,GAAG,UAAU,GAAG,CAAC;AAInD,IAAM,qBAAqBA,GAC/B,OAAO;AAAA,EACN,aAAaA,GAAE,OAAO,EAAE,QAAQ,GAAG;AAAA,EACnC,mBAAmBA,GAAE,OAAO,EAAE,QAAQ,EAAE;AAC1C,CAAC,EACA,QAAQ,EAAE,aAAa,KAAK,mBAAmB,GAAG,CAAC;AAI/C,IAAM,uBAAuBA,GACjC,OAAO;AAAA,EACN,YAAYA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAChC,eAAeA,GAAE,OAAO,EAAE,QAAQ,GAAM;AAC1C,CAAC,EACA,QAAQ,EAAE,YAAY,GAAG,eAAe,IAAO,CAAC;AAI5C,IAAM,uBAAuBA,GACjC,OAAO;AAAA,EACN,eAAeA,GAAE,OAAO,EAAE,QAAQ,IAAO;AAAA,EACzC,eAAeA,GAAE,OAAO,EAAE,QAAQ,IAAS;AAAA,EAC3C,KAAKA,GAAE,OAAO,EAAE,QAAQ,mBAAmB;AAC7C,CAAC,EACA,QAAQ,EAAE,eAAe,MAAS,eAAe,MAAW,KAAK,oBAAoB,CAAC;AAIlF,IAAM,sBAAsBA,GAChC,OAAO;AAAA,EACN,yBAAyBA,GAAE,OAAO,EAAE,QAAQ,MAAM,OAAO,IAAI;AAAA;AAAA,EAC7D,0BAA0BA,GAAE,OAAO,EAAE,QAAQ,MAAM,OAAO,IAAI;AAAA;AAChE,CAAC,EACA,QAAQ;AAAA,EACP,yBAAyB,MAAM,OAAO;AAAA,EACtC,0BAA0B,MAAM,OAAO;AACzC,CAAC;AAII,IAAM,yBAAyBA,GACnC,OAAO;AAAA,EACN,MAAMA,GAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,EAC7B,QAAQA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,oBAAoBA,GAAE,OAAO,EAAE,QAAQ,GAAO;AAAA,EAC9C,wBAAwBA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAC5C,iBAAiBA,GAAE,OAAO,EAAE,QAAQ,EAAE;AAAA,EACtC,aAAaA,GAAE,OAAO,EAAE,QAAQ,EAAE;AAAA;AAAA,EAElC,yBAAyBA,GAAE,OAAO,EAAE,QAAQ,GAAO;AAAA;AAAA,EAEnD,sBAAsBA,GAAE,OAAO,EAAE,QAAQ,IAAS;AAAA;AAAA,EAElD,gBAAgBA,GAAE,OAAO,EAAE,QAAQ,GAAO;AAAA,EAC1C,cAAcA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAElC,aAAaA,GAAE,OAAO,EAAE,QAAQ,EAAE;AAAA;AAAA,EAElC,mBAAmBA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA;AAAA,EAEvC,YAAYA,GAAE,QAAQ,EAAE,QAAQ,KAAK;AACvC,CAAC,EACA,QAAQ;AAAA,EACP,MAAM;AAAA,EACN,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,YAAY;AACd,CAAC;AAKI,IAAM,qBAAqBA,GAAE,OAAO;AAAA,EACzC,OAAOA,GAAE,MAAM,gBAAgB,EAAE,QAAQ,CAAC,CAAC;AAAA,EAE3C,aAAa;AAAA,EAEb,QAAQ;AAAA,EAER,UAAU;AAAA,EAEV,UAAU;AAAA,EAEV,SAAS,oBAAoB,SAAS;AAAA,EAEtC,UAAUA,GACP;AAAA,IACCA,GAAE,OAAO;AAAA,MACP,KAAKA,GAAE,OAAO,EAAE,IAAI;AAAA,MACpB,QAAQA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,SAAS;AAAA,MACrC,QAAQA,GAAE,OAAO,EAAE,SAAS;AAAA,MAC5B,WAAWA,GAAE,OAAO,EAAE,QAAQ,GAAI;AAAA,IACpC,CAAC;AAAA,EACH,EACC,QAAQ,CAAC,CAAC;AAAA,EAEb,YAAY;AAAA,EAEZ,QAAQA,GACL,OAAO;AAAA,IACN,YAAYA,GAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACtC,CAAC,EACA,QAAQ,EAAE,YAAY,KAAK,CAAC;AAAA,EAE/B,YAAYA,GAAE,OAAOA,GAAE,OAAO,GAAG,qBAAqB,EAAE,SAAS;AAAA,EACjE,gBAAgBA,GAAE,OAAO,EAAE,SAAS;AAAA,EAEpC,aAAaA,GACV,OAAO;AAAA,IACN,SAASA,GAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACjC,KAAKA,GAAE,KAAK,CAAC,YAAY,QAAQ,CAAC,EAAE,QAAQ,UAAU;AAAA,IACtD,OAAOA,GAAE,OAAO,EAAE,QAAQ,IAAS;AAAA,EACrC,CAAC,EACA,SAAS;AACd,CAAC;AAIM,IAAM,kBAAkB;AAMxB,IAAM,2BAA2BA,GACrC,OAAO;AAAA,EACN,aAAa,wBAAwB,OAAO,EAAE,QAAQ,EAAE,SAAS;AAAA,EACjE,QAAQ,mBAAmB,OAAO,EAAE,QAAQ,EAAE,SAAS;AAAA,EACvD,UAAU,qBAAqB,OAAO,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC3D,UAAU,qBAAqB,OAAO,EAAE,QAAQ,EAAE,SAAS;AAC7D,CAAC,EACA,QAAQ;;;AC9KJ,SAAS,eAAe,QAAmBC,QAAuB;AACvE,MAAIA,WAAS,IAAI;AACf,WAAO;AAAA,EACT;AAEA,QAAM,OAAOA,OAAK,MAAM,GAAG;AAC3B,MAAI,UAAmB;AAEvB,aAAW,OAAO,MAAM;AACtB,QAAI,YAAY,QAAQ,YAAY,QAAW;AAC7C,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO;AAAA,IACT;AAEA,cAAW,QAAoC,GAAG;AAAA,EACpD;AAEA,SAAO;AACT;;;ACnBO,IAAM,gBAA2B;AAAA,EACtC,OAAO,CAAC;AAAA,EACR,aAAa,wBAAwB,MAAM,MAAS;AAAA,EACpD,QAAQ,mBAAmB,MAAM,MAAS;AAAA,EAC1C,UAAU,qBAAqB,MAAM,MAAS;AAAA,EAC9C,UAAU,qBAAqB,MAAM,MAAS;AAAA,EAC9C,SAAS,oBAAoB,MAAM,MAAS;AAAA,EAC5C,UAAU,CAAC;AAAA,EACX,YAAY;AAAA,IACV,MAAM;AAAA,IACN,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,YAAY;AAAA,EACd;AAAA,EACA,QAAQ,EAAE,YAAY,KAAK;AAC7B;AAQA,SAAS,UAA6C,QAAW,QAAuB;AACtF,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,OAAO,KAAK,MAAM,GAAqB;AACvD,UAAM,cAAc,OAAO,GAAG;AAC9B,UAAM,cAAc,OAAO,GAAG;AAE9B,QAAI,gBAAgB,QAAW;AAC7B;AAAA,IACF;AAEA,QACE,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,KAC1B,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,CAAC,MAAM,QAAQ,WAAW,GAC1B;AAEA,aAAO,GAAG,IAAI;AAAA,QACZ;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AAEL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAOA,SAAS,WAAc,KAAqB;AAC1C,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,WAAO;AAAA,EACT;AAGA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,eAAW,QAAQ,KAAK;AACtB,iBAAW,IAAI;AAAA,IACjB;AACA,WAAO,OAAO,OAAO,GAAG;AAAA,EAC1B;AAGA,aAAW,SAAS,OAAO,OAAO,GAAG,GAAG;AACtC,eAAW,KAAK;AAAA,EAClB;AAEA,SAAO,OAAO,OAAO,GAAG;AAC1B;AAeO,SAAS,aACd,UACA,cACA,YACqB;AAErB,MAAI,SAAS,EAAE,GAAG,SAAS;AAG3B,MAAI,cAAc;AAChB,aAAS,UAAU,QAAQ,YAAY;AAAA,EACzC;AAGA,MAAI,YAAY;AACd,aAAS,UAAU,QAAQ,UAAgC;AAAA,EAC7D;AAEA,SAAO,WAAW,MAAM;AAC1B;;;ACxIA,SAAS,YAAY,oBAAoB;AACzC,SAAS,WAAAC,gBAAe;AACxB,SAAS,YAAY;AACrB,SAAS,SAASC,kBAAiB;AAqB5B,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA,SAA2B;AAAA,EAEnC,YAAY,UAAmB;AAC7B,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAsB;AAC1B,UAAM,eAAe,MAAM,KAAK,iBAAiB;AACjD,UAAM,aAAa,MAAM,KAAK,eAAe;AAE7C,SAAK,SAAS,aAAa,eAAe,cAAc,UAAU;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,IAAO,KAAgB;AACrB,QAAI,KAAK,WAAW,MAAM;AACxB,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,WAAO,eAAe,KAAK,QAAQ,GAAG;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAoB;AAClB,QAAI,KAAK,WAAW,MAAM;AACxB,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,mBAA8C;AAC1D,UAAM,aAAa,KAAKC,SAAQ,GAAG,QAAQ,YAAY;AACvD,UAAM,MAAM,MAAM,KAAK,SAAS,UAAU;AAE1C,QAAI,QAAQ,MAAM;AAChB,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,gBAAgB,UAAU,GAAG;AAC5C,QAAI,CAAC,OAAO,SAAS;AAEnB,cAAQ,KAAK,mCAAmC,UAAU,KAAK,OAAO,MAAM,OAAO;AACnF,aAAO;AAAA,IACT;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAqD;AACjE,QAAI,CAAC,KAAK,UAAU;AAClB,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,KAAK,KAAK,UAAU,QAAQ,YAAY;AAC/D,UAAM,MAAM,MAAM,KAAK,SAAS,cAAc;AAE9C,QAAI,QAAQ,MAAM;AAChB,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,yBAAyB,UAAU,GAAG;AACrD,QAAI,CAAC,OAAO,SAAS;AAEnB,cAAQ,KAAK,mCAAmC,cAAc,KAAK,OAAO,MAAM,OAAO;AACvF,aAAO;AAAA,IACT;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,SAAS,UAA2D;AAChF,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,UAAU,aAAa,UAAU,OAAO;AAC9C,YAAM,SAASC,WAAU,OAAO;AAEhC,UAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AAEN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AChKA,SAAS,oBAAoB;AAC7B,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AACrB,SAAyB,aAAa;AAsB/B,IAAM,gBAAN,cAA4B,aAAa;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACT,UAA4B;AAAA,EAC5B,gBAAsD;AAAA,EAE9D,YAAY,OAAoB,SAAmC;AACjE,UAAM;AACN,SAAK,QAAQ;AACb,SAAK,aAAa,SAAS,cAAc;AACzC,SAAK,WAAW,MAAM,YAAY;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AACZ,QAAI,KAAK,SAAS;AAChB;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,eAAe;AAElC,SAAK,UAAU,MAAM,OAAO;AAAA,MAC1B,eAAe;AAAA;AAAA,MAEf,wBAAwB;AAAA,IAC1B,CAAC;AAED,SAAK,QAAQ,GAAG,UAAU,MAAM,KAAK,aAAa,CAAC;AACnD,SAAK,QAAQ,GAAG,OAAO,MAAM,KAAK,aAAa,CAAC;AAChD,SAAK,QAAQ,GAAG,UAAU,MAAM,KAAK,aAAa,CAAC;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAC/B,WAAK,gBAAgB;AAAA,IACvB;AAEA,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,MAAM;AACnB,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,iBAA2B;AACjC,UAAM,aAAaA,MAAKD,SAAQ,GAAG,QAAQ,YAAY;AACvD,UAAM,QAAQ,CAAC,UAAU;AAEzB,QAAI,KAAK,UAAU;AACjB,YAAM,iBAAiBC,MAAK,KAAK,UAAU,QAAQ,YAAY;AAC/D,YAAM,KAAK,cAAc;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAqB;AAE3B,QAAI,KAAK,eAAe;AACtB,mBAAa,KAAK,aAAa;AAAA,IACjC;AAEA,SAAK,gBAAgB,WAAW,MAAM;AACpC,WAAK,gBAAgB;AACrB,WAAK,aAAa;AAAA,IACpB,GAAG,KAAK,UAAU;AAGlB,QAAI,OAAO,KAAK,kBAAkB,YAAY,WAAW,KAAK,eAAe;AAC3E,WAAK,cAAc,MAAM;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAA8B;AAC1C,QAAI;AACF,YAAM,KAAK,MAAM,KAAK;AACtB,WAAK,KAAK,QAAQ;AAAA,IACpB,QAAQ;AAAA,IAGR;AAAA,EACF;AACF;;;AC5FA,IAAM,kBAAgC;AAAA,EACpC,IAAI,oBAAI,IAAI;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,aAAa,oBAAI,IAAI,CAAC,eAAe,cAAc,UAAU,CAAC;AAAA,EAC9D,QAAQ,oBAAI,IAAI,CAAC,eAAe,mBAAmB,CAAC;AAAA,EACpD,UAAU,oBAAI,IAAI,CAAC,cAAc,eAAe,CAAC;AAAA,EACjD,UAAU,oBAAI,IAAI,CAAC,iBAAiB,iBAAiB,KAAK,CAAC;AAAA,EAC3D,YAAY,oBAAI,IAAI;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,QAAQ,oBAAI,IAAI,CAAC,YAAY,CAAC;AAAA,EAC9B,aAAa,oBAAI,IAAI,CAAC,WAAW,OAAO,OAAO,CAAC;AAClD;AAEA,IAAM,qBAAmC;AAAA,EACvC,IAAI,oBAAI,IAAI,CAAC,eAAe,UAAU,YAAY,UAAU,CAAC;AAAA,EAC7D,aAAa,gBAAgB;AAAA,EAC7B,QAAQ,gBAAgB;AAAA,EACxB,UAAU,gBAAgB;AAAA,EAC1B,UAAU,gBAAgB;AAC5B;;;APlCA,IAAM,wBAAwB;AAAA,EAC5B,OAAO,CAAC;AAAA,EACR,aAAa;AAAA,IACX,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,IACN,aAAa;AAAA,IACb,mBAAmB;AAAA,EACrB;AACF;AAIA,SAAS,cAAc,KAAa,UAA2B;AAC7D,MAAI;AACF,WAAOC,WAAU,GAAG;AAAA,EACtB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,mBAAmB,QAAQ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAClF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,QAAsB,UAA0B;AACvE,QAAM,YAAY,OAAO,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI;AACtF,SAAO,qBAAqB,QAAQ;AAAA,EAAM,SAAS;AACrD;AAOA,eAAsB,WAAW,YAAwC;AACvE,MAAI;AACJ,MAAI;AACF,UAAM,MAAMC,UAAS,YAAY,OAAO;AAAA,EAC1C,SAAS,KAAK;AAEZ,UAAM,IAAI;AAAA,MACR,0BAA0B,UAAU,qCAAqC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3H;AAAA,EACF;AAEA,QAAM,SAAS,cAAc,KAAK,UAAU;AAE5C,QAAM,SAAS,gBAAgB,UAAU,MAAM;AAC/C,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,gBAAgB,OAAO,MAAM,QAAQ,UAAU,CAAC;AAAA,EAClE;AAEA,SAAO,OAAO;AAChB;AAMA,eAAsB,mBAAuC;AAC3D,QAAM,aAAaC,MAAK,KAAK,WAAW,GAAG,YAAY;AAEvD,MAAI,CAACC,YAAW,UAAU,GAAG;AAC3B,UAAM,MAAM,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAC7C,UAAM,UAAU,YAAY,cAAc,qBAAqB,GAAG,OAAO;AACzE,WAAO,mBAAmB,MAAM,qBAAqB;AAAA,EACvD;AAEA,QAAM,MAAM,MAAMF,UAAS,YAAY,OAAO;AAC9C,QAAM,SAAS,cAAc,KAAK,UAAU;AAE5C,QAAM,SAAS,mBAAmB,UAAU,MAAM;AAClD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,IAAI,MAAM,gBAAgB,OAAO,MAAM,QAAQ,UAAU,CAAC;AAAA,EAClE;AAEA,SAAO,OAAO;AAChB;AAOA,eAAsB,sBAAsB,MAAsC;AAChF,QAAM,SAAS,MAAM,iBAAiB;AACtC,QAAM,eAAeC,MAAK,QAAQ,KAAK,IAAI;AAC3C,QAAM,SAAS,iBAAiB,MAAM,EAAE,GAAG,MAAM,MAAM,aAAa,CAAC;AAErE,QAAM,WAAW,OAAO,MAAM,UAAU,CAAC,MAAMA,MAAK,QAAQ,EAAE,IAAI,MAAM,YAAY;AACpF,MAAI,YAAY,GAAG;AACjB,WAAO,MAAM,QAAQ,IAAI;AAAA,EAC3B,OAAO;AACL,WAAO,MAAM,KAAK,MAAM;AAAA,EAC1B;AAEA,QAAM,aAAaA,MAAK,KAAK,WAAW,GAAG,YAAY;AACvD,QAAM,UAAU,YAAY,cAAc,MAAM,GAAG,OAAO;AAC5D;AAKA,eAAsB,2BAA2B,YAAsC;AACrF,QAAM,SAAS,MAAM,iBAAiB;AACtC,QAAM,eAAeA,MAAK,QAAQ,UAAU;AAC5C,QAAM,gBAAgB,OAAO,MAAM;AAEnC,SAAO,QAAQ,OAAO,MAAM;AAAA,IAC1B,CAAC,MACCA,MAAK,QAAQ,EAAE,IAAI,MAAM,gBACzB,EAAE,SAAS,cACX,WAAW,CAAC,MAAM;AAAA,EACtB;AAEA,MAAI,OAAO,MAAM,WAAW,cAAe,QAAO;AAElD,QAAM,aAAaA,MAAK,KAAK,WAAW,GAAG,YAAY;AACvD,QAAM,UAAU,YAAY,cAAc,MAAM,GAAG,OAAO;AAC1D,SAAO;AACT;AAKA,eAAsB,4BAAmD;AACvE,QAAM,SAAS,MAAM,iBAAiB;AACtC,SAAO,OAAO;AAChB;;;AQ3KA,SAAS,wBAAwB;AACjC,SAAS,YAAY,YAAY;AACjC,SAAS,uBAAuB;;;ACFhC,OAAOE,WAAU;AAoBV,SAAS,UAAU,MAAoB;AAC5C,SAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AACvC;AAwBO,SAAS,YAAY,MAAY,QAAgB,KAAqB;AAC3E,QAAM,OAAO,KAAK,eAAe;AACjC,QAAM,KAAK,OAAO,KAAK,YAAY,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACzD,SAAOA,MAAK,KAAK,KAAK,GAAG,MAAM,IAAI,IAAI,IAAI,EAAE,QAAQ;AACvD;;;AClDA,SAAS,SAAAC,cAAa;AA2BtB,eAAsB,UAAU,SAAiB,OAAoC;AACnF,MAAI,OAAO,IAAI,OAAO,GAAG;AACvB;AAAA,EACF;AAEA,QAAMA,OAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAExC,SAAO,IAAI,OAAO;AACpB;;;AFzBO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC9C,YACkB,UACA,eACA,cAChB;AACA;AAAA,MACE,sCAAsC,QAAQ,MAAM,gBAAgB,OAAO,MAAM,QAAQ,CAAC,CAAC,SAAS,eAAe,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC5I;AANgB;AACA;AACA;AAKhB,SAAK,OAAO;AAAA,EACd;AACF;AAMO,IAAM,cAAN,MAAkB;AAAA,EACN;AAAA,EACA,WAAW,oBAAI,IAAY;AAAA,EACpC,WAAkD;AAAA,EACzC;AAAA,EAEjB,YAAY,SAAqD;AAC/D,SAAK,MAAM,QAAQ;AACnB,SAAK,mBAAmB,QAAQ,oBAAoB,MAAM,OAAO;AAAA,EACnE;AAAA,EAEA,MAAM,OAAO,OAAiC;AAC5C,UAAM,UAAU,KAAK,KAAK,KAAK,QAAQ;AACvC,UAAM,OAAO,YAAY,IAAI,KAAK,MAAM,SAAS,GAAG,QAAQ,KAAK,GAAG;AACpE,UAAM,WAAW,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM,OAAO;AAE5D,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,YAAY,MAA8B;AAC9C,UAAM,IAAI,QAAQ,oBAAI,KAAK;AAC3B,UAAM,SAAS,UAAU,CAAC;AAE1B,QAAI,KAAK,UAAU,QAAQ,QAAQ;AACjC,aAAO,KAAK,SAAS;AAAA,IACvB;AAEA,UAAM,OAAO,YAAY,GAAG,QAAQ,KAAK,GAAG;AAC5C,QAAI,QAAQ;AAEZ,QAAI;AAEF,YAAM,QAAQ,MAAM,KAAK,IAAI;AAC7B,UAAI,MAAM,OAAO,KAAK,kBAAkB;AACtC,cAAM,IAAI,qBAAqB,MAAM,MAAM,MAAM,KAAK,gBAAgB;AAAA,MACxE;AAEA,YAAM,SAAS,iBAAiB,MAAM,EAAE,UAAU,QAAQ,CAAC;AAC3D,YAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,WAAW,OAAO,kBAAkB,CAAC;AAEjF,uBAAiB,QAAQ,IAAI;AAC3B,YAAI,CAAC,KAAK,KAAK,EAAG;AAClB,cAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,YAAI,UAAU,IAAI,KAAK,MAAM,SAAS,CAAC,MAAM,QAAQ;AACnD,mBAAS,MAAM;AAAA,QACjB;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,IAEhE;AAEA,SAAK,WAAW,EAAE,KAAK,QAAQ,MAAM;AACrC,WAAO;AAAA,EACT;AACF;;;AGlFA,SAAS,gBAAAC,qBAAoB;AAUtB,IAAM,kBAAN,MAAsB;AAAA,EACV,UAAU,IAAIA,cAAa;AAAA,EAE5C,KAAK,OAAuB;AAC1B,SAAK,SAAS,MAAM,MAAM,KAAK;AAC/B,SAAK,SAAS,KAAK,KAAK;AAAA,EAC1B;AAAA,EAEA,GAAG,WAAmB,UAA2C;AAC/D,SAAK,QAAQ,GAAG,WAAW,QAAQ;AACnC,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,WAAmB,UAA2C;AAChE,SAAK,QAAQ,IAAI,WAAW,QAAQ;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,WAAmB,UAA2C;AACjE,SAAK,QAAQ,KAAK,WAAW,QAAQ;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,mBAAmB,WAA0B;AAC3C,SAAK,QAAQ,mBAAmB,SAAS;AACzC,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,WAAmB,OAAuB;AACzD,QAAI;AACF,WAAK,QAAQ,KAAK,WAAW,KAAK;AAAA,IACpC,SAAS,OAAO;AACd,UAAI,cAAc,SAAS;AACzB,YAAI;AACF,eAAK,QAAQ,KAAK,SAAS,KAAK;AAAA,QAClC,SAAS,WAAW;AAIlB,kBAAQ;AAAA,YACN;AAAA,YACA,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS;AAAA,UACnE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACzDA,SAAS,cAAAC,aAAY,QAAAC,aAAY;AAS1B,IAAMC,wBAAN,cAAmC,MAAM;AAAA,EAC9C,YACkB,UACA,eACA,cAChB;AACA;AAAA,MACE,sCAAsC,QAAQ,MAAM,gBAAgB,OAAO,MAAM,QAAQ,CAAC,CAAC,SAAS,eAAe,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC5I;AANgB;AACA;AACA;AAKhB,SAAK,OAAO;AAAA,EACd;AACF;AAOO,IAAM,eAAN,MAAmB;AAAA,EACP;AAAA,EACA,WAAW,oBAAI,IAAY;AAAA,EAC3B;AAAA,EAEjB,YAAY,SAAqD;AAC/D,SAAK,MAAM,QAAQ;AACnB,SAAK,mBAAmB,QAAQ,oBAAoB,MAAM,OAAO;AAAA,EACnE;AAAA,EAEA,MAAM,OAAO,OAAgC;AAC3C,UAAM,UAAU,KAAK,KAAK,KAAK,QAAQ;AACvC,UAAM,OAAO,YAAY,IAAI,KAAK,MAAM,SAAS,GAAG,UAAU,KAAK,GAAG;AAGtE,QAAI;AACF,YAAM,QAAQ,MAAMC,MAAK,IAAI;AAC7B,UAAI,MAAM,OAAO,KAAK,kBAAkB;AACtC,cAAM,IAAID,sBAAqB,MAAM,MAAM,MAAM,KAAK,gBAAgB;AAAA,MACxE;AAAA,IACF,SAAS,OAAO;AAEd,UAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,IAChE;AAEA,UAAME,YAAW,MAAM,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM,OAAO;AAAA,EAC9D;AACF;;;ACtDA,SAAS,YAAY,kBAAkB;AAgBvC,IAAM,oBAAoB,oBAAI,IAAI,CAAC,oBAAoB,gBAAgB,cAAc,CAAC;AAEtF,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAYrB,IAAM,oBAAN,MAAwB;AAAA,EACZ;AAAA,EACA,UAA8B,oBAAI,IAAI;AAAA,EAEvD,YAAY,UAA2B;AACrC,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,SAAS,OAAuB;AAE9B,QAAI,MAAM,SAAS,eAAgB;AAEnC,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI,CAAC,cAAc,MAAM,MAAM,QAAQ,MAAM,EAAG;AAEhD,YAAM,UAA0B;AAAA,QAC9B,IAAI,WAAW;AAAA,QACf,SAAS;AAAA,QACT,OAAO,MAAM;AAAA,QACb,SAAS,eAAe,KAAK;AAAA,QAC7B,QAAQ;AAAA,QACR,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC;AAEA,YAAM,OAAO,KAAK,UAAU,OAAO;AACnC,YAAM,UAAkC;AAAA,QACtC,gBAAgB;AAAA,MAClB;AAEA,UAAI,QAAQ,QAAQ;AAClB,gBAAQ,iBAAiB,IAAI,KAAK,MAAM,QAAQ,MAAM;AAAA,MACxD;AAEA,UAAI,kBAAkB,IAAI,MAAM,IAAI,GAAG;AAErC,cAAM,IAAI,cAAc,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,EAClE,MAAM,CAAC,QAAQ;AAEd,kBAAQ;AAAA,YACN,qCAAqC,MAAM,IAAI,OAAO,QAAQ,GAAG;AAAA,YACjE;AAAA,UACF;AAAA,QACF,CAAC,EACA,QAAQ,MAAM,KAAK,QAAQ,OAAO,CAAC,CAAC;AACvC,aAAK,QAAQ,IAAI,CAAC;AAAA,MACpB,OAAO;AAEL,cAAM,QAAQ,KAAK;AAAA,UACjB,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,UACA,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AAAA,QAC/C,CAAC,EAAE,MAAM,CAAC,QAAQ;AAEhB,kBAAQ,MAAM,qCAAqC,MAAM,IAAI,OAAO,QAAQ,GAAG,KAAK,GAAG;AAAA,QACzF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAQ,SAAS,EAAG;AAC7B,UAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,OAAO,CAAC;AAAA,EAC5C;AACF;AAMA,eAAe,cACb,KACA,SACA,MACA,WACe;AACf,WAAS,UAAU,GAAG,WAAW,oBAAoB,WAAW;AAC9D,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK;AAAA,QAC3B,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,QAAQ,YAAY,QAAQ,SAAS;AAAA,MACvC,CAAC;AACD,UAAI,IAAI,GAAI;AAAA,IAEd,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,sCAAsC,OAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACpG;AAAA,IACF;AAEA,QAAI,UAAU,oBAAoB;AAChC,YAAM,QAAQ,sBAAsB,MAAM,UAAU;AACpD,YAAM,IAAI,QAAQ,CAACC,aAAY,WAAWA,UAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AACF;AAOO,SAAS,cAAc,WAAmB,SAA6B;AAC5E,MAAI,CAAC,WAAW,QAAQ,WAAW,EAAG,QAAO;AAC7C,SAAO,QAAQ,KAAK,CAAC,MAAM;AACzB,QAAI,EAAE,SAAS,IAAI,EAAG,QAAO,UAAU,WAAW,EAAE,MAAM,GAAG,EAAE,CAAC;AAChE,WAAO,MAAM;AAAA,EACf,CAAC;AACH;AAEA,SAAS,KAAK,MAAc,QAAwB;AAClD,SAAO,WAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;AAC/D;AAEA,SAAS,eAAe,OAA0C;AAChE,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,OAAO,UAAU,YAAY;AAC/B,UAAI,GAAG,IAAI;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;;;AC7JA,SAAS,gBAAgB;AACzB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,SAAAC,QAAO,WAAAC,UAAS,UAAU;AACnC,SAAS,SAAS,eAAe;AACjC,SAAS,iBAAiB;;;ACDnB,SAAS,MAAM,IAA2B;AAC/C,SAAO,IAAI,QAAQ,CAACC,aAAY,WAAWA,UAAS,EAAE,CAAC;AACzD;;;ADEA,IAAM,gBAAgB,UAAU,QAAQ;AACxC,IAAM,cAAc;AAGpB,IAAM,oBAAoB;AAC1B,IAAM,wBAAwB;AAUvB,SAAS,eAAe,SAAiB,WAAyB;AACvE,MAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,UAAM,IAAI,MAAM,GAAG,SAAS,6BAA6B;AAAA,EAC3D;AAGA,MAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,UAAM,IAAI,MAAM,GAAG,SAAS,sDAAsD;AAAA,EACpF;AAGA,MAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,UAAM,IAAI,MAAM,GAAG,SAAS,2CAA2C;AAAA,EACzE;AAIA,QAAM,kBAAkB;AACxB,MAAI,CAAC,gBAAgB,KAAK,OAAO,GAAG;AAClC,UAAM,IAAI;AAAA,MACR,GAAG,SAAS,6GAA6G,OAAO;AAAA,IAClI;AAAA,EACF;AACF;AAaA,eAAsB,mBAAmB,SAKX;AAG5B,iBAAe,QAAQ,QAAQ,QAAQ;AACvC,iBAAe,QAAQ,YAAY,YAAY;AAE/C,QAAM,WAAW,QAAQ,QAAQ,QAAQ;AACzC,QAAM,aAAa,QAAQ,QAAQ,UAAU;AAE7C,QAAMC,OAAM,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAKpD,QAAM,YAAY,MAAM,cAAc,OAAO,CAAC,UAAU,SAAS,mBAAmB,GAAG;AAAA,IACrF,KAAK;AAAA,IACL,SAAS;AAAA,EACX,CAAC,EACE,KAAK,CAAC,EAAE,OAAO,MAAM,OAAO,KAAK,CAAC,EAClC,MAAM,CAAC,QAAQ;AAEd,YAAQ;AAAA,MACN,kCAAkC,QAAQ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACjG;AACA,WAAO;AAAA,EACT,CAAC;AAKH,QAAM,cAAc,aAAa;AAGjC,MAAI;AACJ,WAAS,UAAU,GAAG,WAAW,mBAAmB,WAAW;AAC7D,QAAI;AACF,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,SAAS,YAAY,QAAQ,YAAY,aAAa,UAAU;AAAA,QACjE,EAAE,SAAS,YAAY;AAAA,MACzB;AACA,kBAAY;AACZ;AAAA,IACF,SAAS,KAAK;AACZ,kBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAC9D,cAAQ;AAAA,QACN,uBAAuB,OAAO,IAAI,iBAAiB,YAAY,UAAU,OAAO;AAAA,MAClF;AAGA,UAAIC,YAAW,UAAU,GAAG;AAC1B,cAAM,GAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,CAAC,UAAU;AACtE,kBAAQ;AAAA,YACN,2CAA2C,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,UACnG;AAAA,QACF,CAAC;AAAA,MACH;AAEA,UAAI,UAAU,mBAAmB;AAC/B,cAAM,YAAY,wBAAwB,MAAM,UAAU;AAC1D,gBAAQ,MAAM,2BAA2B,SAAS,OAAO;AACzD,cAAM,MAAM,SAAS;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,MAAI,WAAW;AACb,UAAM,IAAI;AAAA,MACR,sBAAsB,iBAAiB,0BAA0B,UAAU,OAAO;AAAA,MAClF,EAAE,OAAO,UAAU;AAAA,IACrB;AAAA,EACF;AAGA,MAAI,QAAQ,WAAW,QAAQ,YAAY;AAEzC,UAAM,eAAe,MAAM;AAAA,MACzB;AAAA,MACA,CAAC,aAAa,WAAW,UAAU,QAAQ,MAAM;AAAA,MACjD,EAAE,KAAK,YAAY,SAAS,YAAY;AAAA,IAC1C,EACG,KAAK,CAAC,EAAE,OAAO,MAAM,OAAO,KAAK,EAAE,SAAS,CAAC,EAC7C,MAAM,CAAC,QAAQ;AAEd,cAAQ;AAAA,QACN,qCAAqC,QAAQ,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC1G;AACA,aAAO;AAAA,IACT,CAAC;AAEH,QAAI,cAAc;AAEhB,YAAM,cAAc,OAAO,CAAC,SAAS,UAAU,QAAQ,MAAM,GAAG;AAAA,QAC9D,KAAK;AAAA,QACL,SAAS;AAAA,MACX,CAAC;AACD,YAAM,cAAc,OAAO,CAAC,YAAY,MAAM,QAAQ,QAAQ,UAAU,QAAQ,MAAM,EAAE,GAAG;AAAA,QACzF,KAAK;AAAA,QACL,SAAS;AAAA,MACX,CAAC;AAAA,IACH,OAAO;AAEL,YAAM,cAAc,OAAO,CAAC,YAAY,MAAM,QAAQ,MAAM,GAAG;AAAA,QAC7D,KAAK;AAAA,QACL,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,YAAY,QAAQ,QAAQ,QAAQ,SAAS;AAC9D;AAMA,eAAsB,mBAAmB,aAAoC;AAC3E,QAAM,UAAU,QAAQ,WAAW;AAEnC,MAAI,CAACA,YAAW,OAAO,GAAG;AACxB;AAAA,EACF;AAEA,QAAM,GAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpD;AAKA,eAAsB,kBAAkB,iBAAsD;AAC5F,QAAM,UAAU,QAAQ,eAAe;AAEvC,MAAI,CAACA,YAAW,OAAO,GAAG;AACxB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,UAAU,MAAMC,SAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,QAAM,SAA6B,CAAC;AAEpC,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,UAAM,YAAY,QAAQ,SAAS,MAAM,IAAI;AAE7C,QAAI;AACF,YAAM,EAAE,QAAQ,UAAU,IAAI,MAAM;AAAA,QAClC;AAAA,QACA,CAAC,aAAa,gBAAgB,MAAM;AAAA,QACpC;AAAA,UACE,KAAK;AAAA,UACL,SAAS;AAAA,QACX;AAAA,MACF;AACA,UAAI,WAAW;AACf,UAAI;AACF,cAAM,EAAE,QAAQ,UAAU,IAAI,MAAM;AAAA,UAClC;AAAA,UACA,CAAC,UAAU,SAAS,mBAAmB;AAAA,UACvC,EAAE,KAAK,WAAW,SAAS,YAAY;AAAA,QACzC;AACA,cAAM,MAAM,UAAU,KAAK;AAC3B,YAAI,IAAK,YAAW,QAAQ,WAAW,GAAG;AAAA,MAC5C,SAAS,KAAK;AAEZ,gBAAQ;AAAA,UACN,sCAAsC,SAAS,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACtG;AAAA,MACF;AACA,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,QAAQ,UAAU,KAAK;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,kBAAkB,SAAS,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACxG;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AEpPA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,WAAAC,gBAAe;AACxB,SAAS,aAAAC,kBAAiB;AAI1B,IAAMC,iBAAgBC,WAAUC,SAAQ;AACxC,IAAMC,eAAc;AAKpB,eAAe,IAAI,UAAkB,MAAiC;AACpE,QAAM,EAAE,OAAO,IAAI,MAAMH,eAAc,OAAO,MAAM;AAAA,IAClD,KAAKI,SAAQ,QAAQ;AAAA,IACrB,SAASD;AAAA,EACX,CAAC;AACD,SAAO,OAAO,KAAK;AACrB;AAEA,eAAsB,aACpB,UACA,QACA,YACe;AAEf,iBAAe,QAAQ,QAAQ;AAC/B,iBAAe,YAAY,YAAY;AAEvC,QAAM,IAAI,UAAU,CAAC,UAAU,QAAQ,UAAU,CAAC;AACpD;AAEA,eAAsB,WAAW,UAAkB,QAAgB,QAA+B;AAEhG,iBAAe,QAAQ,QAAQ;AAC/B,iBAAe,QAAQ,QAAQ;AAE/B,QAAM,IAAI,UAAU,CAAC,QAAQ,QAAQ,MAAM,CAAC;AAC9C;AAEA,eAAsB,YAAY,UAAkB,QAA+B;AAEjF,iBAAe,QAAQ,QAAQ;AAE/B,QAAM,IAAI,UAAU,CAAC,SAAS,MAAM,CAAC;AACvC;AAEA,eAAsB,aAAa,UAAkB,QAA+B;AAElF,iBAAe,QAAQ,QAAQ;AAE/B,QAAM,IAAI,UAAU,CAAC,UAAU,MAAM,MAAM,CAAC;AAC9C;AAEA,eAAsB,iBAAiB,UAAmC;AACxE,SAAO,IAAI,UAAU,CAAC,aAAa,gBAAgB,MAAM,CAAC;AAC5D;AAOO,SAAS,cAAc,QAAoB,OAAe,QAAyB;AACxF,MAAI,OAAQ,QAAO;AACnB,QAAM,SAAS,OAAO,gBAAgB;AACtC,QAAM,YAAY,MAAM,YAAY,EAAE,QAAQ,eAAe,GAAG;AAChE,SAAO,GAAG,MAAM,QAAQ,SAAS;AACnC;AAgCA,eAAsB,kBACpB,aACA,QACA,QACe;AAEf,iBAAe,QAAQ,QAAQ;AAC/B,iBAAe,QAAQ,QAAQ;AAE/B,QAAM,IAAI,aAAa,CAAC,QAAQ,MAAM,QAAQ,MAAM,CAAC;AACvD;;;AC9GA,SAAS,WAAAE,gBAAe;AAmBxB,IAAM,cAAc,oBAAI,IAAI,CAAC,SAAS,QAAQ,cAAc,CAAC;AAQtD,SAAS,mBAAmB,OAAsB,aAAqC;AAC5F,QAAM,aAAa,MAAM,YAAY;AACrC,QAAM,aAAa,cAAcA,SAAQ,WAAW,IAAI;AAExD,QAAM,eAAe,aACjB,MAAM,WAAW,QACjB,MAAM,WAAW,MAAM,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;AAE5D,QAAM,gBAAgB,aAAa,CAAC,UAAU,IAAI,CAAC;AACnD,QAAM,gBAAgB,cAAc,aAAa,CAAC,UAAU,IAAI,CAAC;AAEjE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;AAAA,EACZ;AACF;;;AC5CA,SAAS,cAAAC,aAAY,SAAAC,cAAa;AAClC,OAAOC,WAAU;AAGjB,IAAM,4BAA4B;AAClC,IAAM,qBAAqB;AAiBpB,SAAS,SAAS,SAMF;AACrB,QAAM;AAAA,IACJ;AAAA,IACA,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,YAAY;AAAA,EACd,IAAI;AAEJ,MAAI,aAAa;AAEjB,QAAM,UAAU,oBAAI,IAAsB;AAC1C,MAAI;AAEJ,iBAAeC,aAA2B;AACxC,QAAI,CAAC,YAAY;AACf,YAAMF,OAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,iBAAe,WAA0B;AACvC,QAAI,QAAQ,SAAS,EAAG;AACxB,UAAME,WAAU;AAEhB,UAAM,SAA0B,CAAC;AACjC,eAAW,CAAC,WAAW,KAAK,KAAK,SAAS;AACxC,YAAM,WAAWD,MAAK,KAAK,KAAK,GAAG,SAAS,QAAQ;AACpD,aAAO,KAAKF,YAAW,UAAU,MAAM,KAAK,EAAE,GAAG,OAAO,CAAC;AAAA,IAC3D;AACA,YAAQ,MAAM;AACd,UAAM,QAAQ,IAAI,MAAM;AAAA,EAC1B;AAEA,iBAAe,aAAa,WAAkC;AAC5D,UAAM,QAAQ,QAAQ,IAAI,SAAS;AACnC,QAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,UAAMG,WAAU;AAEhB,UAAM,WAAWD,MAAK,KAAK,KAAK,GAAG,SAAS,QAAQ;AACpD,UAAMF,YAAW,UAAU,MAAM,KAAK,EAAE,GAAG,OAAO;AAClD,YAAQ,OAAO,SAAS;AAAA,EAC1B;AAEA,WAAS,YAAkB;AACzB,QAAI,eAAe,QAAW;AAC5B,oBAAc,UAAU;AACxB,mBAAa;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM,QAAQ;AACZ,gBAAU;AACV,YAAM,SAAS;AAAA,IACjB;AAAA,IACA,UAAU;AACR,gBAAU;AAAA,IACZ;AAAA,IACA,MAAM,QAAQ,OAAO,SAAS;AAC5B,YAAM,QAAiC;AAAA,QACrC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,WAAW,MAAM;AAAA,QACjB,OAAO,QAAQ;AAAA,QACf,UAAU,MAAM;AAAA,MAClB;AAEA,UAAI,gBAAgB,MAAM,UAAU,QAAW;AAC7C,cAAM,QAAQ,MAAM;AAAA,MACtB;AAEA,UAAI,iBAAiB,MAAM,WAAW,QAAW;AAC/C,cAAM,SAAS,MAAM;AAAA,MACvB;AAEA,YAAM,YAAY,MAAM;AACxB,UAAI,QAAQ,QAAQ,IAAI,SAAS;AACjC,UAAI,CAAC,OAAO;AACV,gBAAQ,CAAC;AACT,gBAAQ,IAAI,WAAW,KAAK;AAAA,MAC9B;AACA,YAAM,KAAK,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,CAAI;AAGvC,UAAI,MAAM,UAAU,WAAW;AAC7B,cAAM,aAAa,SAAS;AAAA,MAC9B;AAGA,UAAI,eAAe,UAAa,kBAAkB,GAAG;AACnD,qBAAa,YAAY,MAAM;AAC7B,eAAK,SAAS;AAAA,QAChB,GAAG,eAAe;AAElB,YAAI,OAAO,eAAe,YAAY,WAAW,YAAY;AAC3D,qBAAW,MAAM;AAAA,QACnB;AAAA,MACF;AAEA,aAAO,EAAE,UAAU,SAAS,cAAc,IAAM;AAAA,IAClD;AAAA,EACF;AACF;;;AC3HO,SAAS,cAA0B;AACxC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM,QAAQ,QAAQ,SAAS;AAC7B,YAAM,YAAY,QAAQ,IAAI,WAAW;AACzC,YAAM,eAAe,QAAQ,IAAI,cAAc;AAE/C,UAAI,cAAc,UAAa,iBAAiB,UAAa,aAAa,cAAc;AACtF,eAAO;AAAA,UACL,UAAU;AAAA,UACV,QAAQ;AAAA,QACV;AAAA,MACF;AAEA,aAAO,EAAE,UAAU,OAAO;AAAA,IAC5B;AAAA,EACF;AACF;;;ACRA,SAAS,YAAY,OAAsC,UAAuC;AAChG,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,aAAa,OAAW,QAAO;AACnC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,SAAS,QAAQ;AACxD,SAAO,UAAU;AACnB;AAEO,SAAS,qBAAqB,YAA2C;AAC9E,SAAO;AAAA,IACL,MAAM,QAAQ,OAAwB,SAAuD;AAC3F,UAAI;AAEJ,iBAAW,MAAM,YAAY;AAE3B,YAAI,GAAG,OAAO,MAAM,UAAW;AAG/B,YAAI,CAAC,YAAY,GAAG,OAAO,MAAM,QAAQ,EAAG;AAE5C,cAAM,SAAS,MAAM,GAAG,QAAQ,OAAO,OAAO;AAE9C,gBAAQ,OAAO,UAAU;AAAA,UACvB,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,wBAAY;AACZ;AAAA,UACF,KAAK;AACH;AAAA,QACJ;AAAA,MACF;AAEA,aAAO,aAAa,EAAE,UAAU,OAAO;AAAA,IACzC;AAAA,EACF;AACF;AAcO,SAAS,cACd,OACA,SACA,aAA2B,CAAC,GAClB;AACV,WAAS,aAAa,WAAoC;AACxD,WAAO,OAAO,UAA8C;AAC1D,YAAM,QAAyB;AAAA,QAC7B;AAAA,QACA,WAAW,MAAM;AAAA,QACjB,UAAU,eAAe,QAAS,MAAM,YAAuB;AAAA,QAC/D,OAAO,gBAAgB,QAAS,MAAM,aAAyC;AAAA,QAC/E,QAAQ,mBAAmB,QAAQ,OAAO,MAAM,aAAa,IAAI;AAAA,QACjE,SAAS,aAAa,QAAS,MAAM,UAAqB;AAAA,MAC5D;AAEA,YAAM,SAAS,MAAM,MAAM,QAAQ,OAAO,OAAO;AAEjD,cAAQ,OAAO,UAAU;AAAA,QACvB,KAAK;AACH,iBAAO,EAAE,UAAU,SAAS,QAAQ,OAAO,OAAO;AAAA,QACpD,KAAK;AACH,iBAAO,EAAE,OAAO,MAAM,cAAc,OAAO,aAAa;AAAA,QAC1D,KAAK;AACH,iBAAO,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,IAAI,IAAI,WAAW,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;AACxD,QAAM,YAAyB,CAAC,cAAc,eAAe,cAAc;AAE3E,QAAM,QAAkB,CAAC;AACzB,aAAW,aAAa,WAAW;AAEjC,QAAI,WAAW,WAAW,KAAK,WAAW,IAAI,SAAS,GAAG;AACxD,YAAM,SAAS,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,SAAS,CAAC,EAAE,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO;AACT;;;AChGO,SAAS,cAAc,SAGF;AAC1B,QAAM,EAAE,UAAU,IAAI;AACtB,QAAM,iBAAiB,oBAAI,IAAiC;AAE5D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ,WAAmB;AACzB,qBAAe,OAAO,SAAS;AAAA,IACjC;AAAA,IACA,MAAM,QAAQ,OAAO;AACnB,YAAM,YAAY,MAAM;AACxB,YAAM,UACJ,MAAM,SAAS,OAAO,MAAM,UAAU,YAAY,aAAa,MAAM,QACjE,OAAO,MAAM,MAAM,OAAO,IAC1B;AAEN,UAAI,CAAC,QAAS,QAAO,EAAE,UAAU,OAAO;AAExC,UAAI,CAAC,eAAe,IAAI,SAAS,GAAG;AAClC,uBAAe,IAAI,WAAW,oBAAI,IAAI,CAAC;AAAA,MACzC;AAEA,YAAM,iBAAiB,eAAe,IAAI,SAAS,KAAK,oBAAI,IAAoB;AAChF,YAAM,SAAS,eAAe,IAAI,OAAO,KAAK,KAAK;AACnD,qBAAe,IAAI,SAAS,KAAK;AAEjC,UAAI,SAAS,WAAW;AACtB,eAAO;AAAA,UACL,UAAU;AAAA,UACV,QAAQ,kDAAkD,OAAO,KAAK,CAAC;AAAA,QACzE;AAAA,MACF;AAEA,aAAO,EAAE,UAAU,OAAO;AAAA,IAC5B;AAAA,EACF;AACF;;;ACvDA,SAAS,cAAAI,mBAAkB;AAC3B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,SAAAC,QAAO,YAAAC,iBAAgB;AAChC,OAAOC,YAAU;;;ACHjB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,SAAAC,QAAO,WAAAC,UAAS,YAAAC,WAAU,aAAAC,kBAAiB;AACpD,OAAOC,WAAU;;;ACoBV,SAAS,eAAe,KAAsB;AACnD,MAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,GAAG;AACtC,WAAO;AAAA,EACT;AAEA,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,SAAS,OAAgB;AAEvB,QAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,SAAS;AACvE,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;;;AD9BA,IAAM,kBAAkB,oBAAI,IAAI,CAAC,UAAU,UAAU,SAAS,QAAQ,CAAC;AAGvE,SAAS,eAAe,KAAuB;AAC7C,SACE,eAAe,SACf,UAAU,OACV,OAAO,IAAI,SAAS,YACpB,gBAAgB,IAAI,IAAI,IAAI;AAEhC;AAOA,IAAM,yBAAyB;AAQxB,IAAM,WAAN,MAAe;AAAA,EACH;AAAA,EACA,cAAc,oBAAI,IAAY;AAAA;AAAA,EAEvC,aAAyC;AAAA,EAEjD,YAAY,UAA2B,CAAC,GAAG;AACzC,SAAK,UAAU,QAAQ,WAAW,WAAW;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAW,KAAkC;AACjD,QAAI;AACF,YAAM,OAAO,WAAW,EAAE,MAAM,IAAI,KAAK,CAAC;AAE1C,YAAM,UAAUC,MAAK,KAAK,KAAK,SAAS,IAAI;AAC5C,UAAI,CAAC,KAAK,YAAY,IAAI,OAAO,GAAG;AAClC,cAAMC,OAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AACxC,aAAK,YAAY,IAAI,OAAO;AAAA,MAC9B;AACA,YAAM,WAAWD,MAAK,KAAK,SAAS,GAAG,IAAI,KAAK,OAAO;AACvD,YAAME,WAAU,UAAU,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,OAAO;AAE/D,WAAK,aAAa;AAAA,IACpB,SAAS,KAAK;AACZ,cAAQ,MAAM,+BAA+B,IAAI,KAAK,KAAK,GAAG;AAE9D,UAAI,eAAe,GAAG,GAAG;AACvB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,sBAA+C;AACnD,QAAI,CAACC,YAAW,KAAK,OAAO,EAAG,QAAO,CAAC;AAEvC,UAAM,WAA2B,CAAC;AAElC,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,gBAAgB;AAC7C,iBAAW,YAAY,WAAW;AAChC,cAAM,MAAM,MAAM,KAAK,qBAAqB,QAAQ;AACpD,YAAI,IAAK,UAAS,KAAK,GAAG;AAAA,MAC5B;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,qCAAqC,GAAG;AAAA,IACxD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBAAqC;AACzC,UAAM,UAAU,MAAMC,SAAQ,KAAK,SAAS,EAAE,eAAe,KAAK,CAAC;AACnE,UAAM,YAAsB,CAAC;AAC7B,UAAM,QAAQ,oBAAI,IAAoB;AAEtC,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,SAASJ,MAAK,KAAK,KAAK,SAAS,MAAM,IAAI;AACjD,cAAM,WAAW,MAAMI,SAAQ,MAAM;AACrC,mBAAW,KAAK,UAAU;AACxB,cAAI,EAAE,SAAS,OAAO,GAAG;AACvB,kBAAM,WAAWJ,MAAK,KAAK,QAAQ,CAAC;AACpC,sBAAU,KAAK,QAAQ;AAEvB,kBAAM,IAAIA,MAAK,SAAS,GAAG,OAAO,GAAG,QAAQ;AAAA,UAC/C;AAAA,QACF;AAAA,MACF,WAAW,MAAM,KAAK,SAAS,OAAO,GAAG;AACvC,cAAM,WAAWA,MAAK,KAAK,KAAK,SAAS,MAAM,IAAI;AACnD,kBAAU,KAAK,QAAQ;AACvB,cAAM,IAAIA,MAAK,SAAS,MAAM,MAAM,OAAO,GAAG,QAAQ;AAAA,MACxD;AAAA,IACF;AAEA,SAAK,aAAa;AAClB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAsC;AAC1C,QAAI,CAACG,YAAW,KAAK,OAAO,EAAG,QAAO,CAAC;AAEvC,UAAM,OAAuB,CAAC;AAC9B,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,gBAAgB;AAC7C,iBAAW,YAAY,WAAW;AAChC,YAAI;AACF,gBAAM,UAAU,MAAME,UAAS,UAAU,OAAO;AAChD,gBAAM,MAAM,KAAK,MAAM,OAAO;AAC9B,eAAK,KAAK,GAAG;AAAA,QACf,SAAS,KAAK;AACZ,kBAAQ,MAAM,6CAA6C,QAAQ,KAAK,GAAG;AAAA,QAC7E;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,4BAA4B,GAAG;AAAA,IAC/C;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAW,OAA6C;AAC5D,QAAI,CAACF,YAAW,KAAK,OAAO,EAAG,QAAO;AAEtC,QAAI;AAEF,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,KAAK,gBAAgB;AAAA,MAC7B;AAGA,YAAM,WAAW,KAAK,WAAY,IAAI,KAAK;AAC3C,UAAI,CAAC,SAAU,QAAO;AAEtB,YAAM,UAAU,MAAME,UAAS,UAAU,OAAO;AAChD,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,SAAS,KAAK;AACZ,cAAQ,MAAM,+BAA+B,KAAK,KAAK,GAAG;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,mBAA4C;AAChD,QAAI,CAACF,YAAW,KAAK,OAAO,EAAG,QAAO,CAAC;AAEvC,UAAM,YAA4B,CAAC;AAEnC,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,gBAAgB;AAC7C,iBAAW,YAAY,WAAW;AAChC,cAAM,MAAM,MAAM,KAAK,gBAAgB,QAAQ;AAC/C,YAAI,IAAK,WAAU,KAAK,GAAG;AAAA,MAC7B;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,kCAAkC,GAAG;AAAA,IACrD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,gBAAgB,UAAgD;AAC5E,QAAI;AACF,YAAM,UAAU,MAAME,UAAS,UAAU,OAAO;AAChD,YAAM,MAAM,KAAK,MAAM,OAAO;AAE9B,UAAI,IAAI,WAAW,UAAW,QAAO;AAGrC,UAAI,IAAI,OAAO,eAAe,IAAI,GAAG,EAAG,QAAO;AAI/C,YAAM,QAAQ,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,SAAS,EAAE,QAAQ;AAC3D,UAAI,QAAQ,uBAAwB,QAAO;AAE3C,UAAI,SAAS;AACb,UAAI,gBAAgB;AACpB,UAAI,aAAY,oBAAI,KAAK,GAAE,YAAY;AACvC,YAAMH,WAAU,UAAU,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,OAAO;AAC/D,WAAK,aAAa;AAElB,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAoC,QAAQ,KAAK,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,OAAe,QAA+B;AAC9D,UAAM,MAAM,MAAM,KAAK,WAAW,KAAK;AACvC,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,kBAAkB,KAAK,EAAE;AAAA,IAC3C;AAEA,QAAI,SAAS;AACb,QAAI,gBAAgB;AACpB,QAAI,aAAY,oBAAI,KAAK,GAAE,YAAY;AACvC,QAAI,aAAY,oBAAI,KAAK,GAAE,YAAY;AAEvC,UAAM,KAAK,WAAW,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAA0C;AAC9C,UAAM,UAAU,MAAM,KAAK,WAAW;AACtC,WAAO,QAAQ,OAAO,CAAC,QAAQ,IAAI,WAAW,SAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ,OAA8B;AAC1C,UAAM,MAAM,MAAM,KAAK,WAAW,KAAK;AACvC,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,kBAAkB,KAAK,EAAE;AAAA,IAC3C;AAEA,QAAI,IAAI,WAAW,WAAW;AAC5B,YAAM,IAAI,MAAM,OAAO,KAAK,4BAA4B,IAAI,MAAM,GAAG;AAAA,IACvE;AAEA,QAAI,SAAS;AACb,QAAI,gBAAgB;AACpB,QAAI,YAAY;AAChB,QAAI,aAAY,oBAAI,KAAK,GAAE,YAAY;AAEvC,UAAM,KAAK,WAAW,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBAAqB,UAAgD;AACjF,UAAM,UAAU,MAAMG,UAAS,UAAU,OAAO;AAChD,UAAM,MAAM,KAAK,MAAM,OAAO;AAE9B,QAAI,IAAI,WAAW,UAAW,QAAO;AAGrC,QAAI,IAAI,OAAO,IAAI,QAAQ,QAAQ,IAAK,QAAO;AAG/C,QAAI,IAAI,OAAO,eAAe,IAAI,GAAG,EAAG,QAAO;AAI/C,UAAM,QAAQ,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,SAAS,EAAE,QAAQ;AAC3D,QAAI,QAAQ,uBAAwB,QAAO;AAE3C,QAAI,SAAS;AACb,QAAI,aAAY,oBAAI,KAAK,GAAE,YAAY;AACvC,UAAMH,WAAU,UAAU,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,OAAO;AAC/D,SAAK,aAAa;AAElB,WAAO;AAAA,EACT;AACF;;;AEtTA,SAAS,YAAAI,iBAAgB;AACzB,OAAOC,WAAU;AAMjB,IAAM,oBAAoB;AAI1B,eAAsB,qBAAqB,UAA+C;AACxF,QAAM,WAAWA,MAAK,KAAK,UAAU,iBAAiB;AACtD,MAAI;AACF,WAAO,MAAMD,UAAS,UAAU,OAAO;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIO,SAAS,6BACd,UACA,OACA,QACA,YACA,QACA,UACe;AACf,QAAM,WAAW,UAAU;AAG3B,MAAI,MAAM,YAAY,YAAY;AAChC,QAAI,UAAU;AACZ,aAAO;AAAA;AAAA,MAA0B,OAAO,QAAQ,CAAC,gGAAgG,OAAO,QAAQ,CAAC;AAAA,IACnK;AACA,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,MAAM;AACrB,QAAI,UAAU;AACZ,aAAO;AAAA;AAAA,sBAA0C,MAAM;AAAA,sBAA4B,OAAO,QAAQ,CAAC;AAAA;AAAA,6EAA2K,OAAO,QAAQ,CAAC;AAAA,IAChS;AACA,WAAO;AAAA;AAAA,sBAA0C,MAAM,eAAe,UAAU;AAAA;AAAA,yBAAmD,MAAM,IAAI,MAAM;AAAA,2BAAgC,UAAU;AAAA;AAAA,EAC/L;AAGA,SAAO;AAAA;AAAA,sBAA0C,MAAM,eAAe,UAAU;AAAA;AAClF;AAIO,SAAS,2BAA2B,QAAwB;AACjE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsET;AAIO,SAAS,gBACd,aACA,kBACA,iBACA,YACA,eACA,iBACA,uBACQ;AACR,QAAM,WAAqB,CAAC;AAE5B,MAAI,YAAa,UAAS,KAAK,WAAW;AAC1C,MAAI,gBAAiB,UAAS,KAAK,eAAe;AAClD,MAAI,cAAe,UAAS,KAAK,aAAa;AAC9C,MAAI,iBAAkB,UAAS,KAAK;AAAA;AAAA,EAAiC,gBAAgB,EAAE;AACvF,MAAI,gBAAiB,UAAS,KAAK,eAAe;AAClD,MAAI,sBAAuB,UAAS,KAAK,qBAAqB;AAC9D,WAAS,KAAK;AAAA;AAAA,EAAc,UAAU,EAAE;AAExC,SAAO,SAAS,KAAK,aAAa;AACpC;;;ACvIA,SAAS,YAAY,KAAkC;AAErD,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AAAA,EAER;AAGA,QAAM,iBAAiB;AACvB,QAAM,QAAQ,IAAI,MAAM,cAAc;AACtC,MAAI,QAAQ,CAAC,GAAG;AACd,QAAI;AACF,aAAO,KAAK,MAAM,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,IACnC,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAIA,IAAM,eAAe;AAEd,SAAS,aAAa,KAA+D;AAC1F,QAAM,QAAQ,IAAI,MAAM,YAAY;AACpC,MAAI,CAAC,QAAQ,CAAC,EAAG,QAAO;AAExB,QAAM,QAAQ,MAAM,CAAC;AACrB,QAAM,cAAc,MAAM,MAAM,eAAe;AAE/C,MAAI,cAAc,CAAC,GAAG;AACpB,WAAO,EAAE,OAAO,UAAU,OAAO,SAAS,YAAY,CAAC,GAAG,EAAE,EAAE;AAAA,EAChE;AACA,SAAO,EAAE,MAAM;AACjB;AAUO,SAAS,YAAY,KAAa,QAAgC;AACvE,QAAM,SAAS,aAAa,GAAG;AAC/B,QAAM,OAAqB,EAAE,WAAW,IAAI;AAC5C,MAAI,QAAQ;AACV,SAAK,QAAQ,OAAO;AACpB,QAAI,OAAO,aAAa,QAAW;AACjC,WAAK,WAAW,OAAO;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,YAAY,GAAG;AACjC,MAAI,cAAc,QAAW;AAC3B,SAAK,aAAa;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,OAAO,UAAU,SAAS;AACzC,MAAI,CAAC,OAAO,SAAS;AACnB,SAAK,aAAa,6BAA6B,OAAO,MAAM,OAAO;AACnE,WAAO;AAAA,EACT;AAEA,OAAK,SAAS,OAAO;AACrB,SAAO;AACT;;;ACVO,SAAS,cAAc,KAA8C;AAC1E,SAAO,IAAI,SAAS,YAAY,IAAI,YAAY;AAClD;AAKO,SAAS,gBAAgB,KAAgD;AAC9E,SAAO,IAAI,SAAS;AACtB;AAKO,SAAS,mBAAmB,KAAmD;AACpF,SAAO,IAAI,SAAS,eAAe,CAAC,IAAI;AAC1C;AAKO,SAAS,iBAAiB,KAAiD;AAChF,SAAO,IAAI,SAAS,eAAe,IAAI,YAAY;AACrD;AAKO,SAAS,oBAAoB,KAAoD;AACtF,SAAO,IAAI,SAAS,eAAe,IAAI,YAAY;AACrD;;;ACtEA,SAAS,aAAa,QAA2B;AAC/C,MAAI,OAAO,SAAS;AAClB,UAAM,SAAS,OAAO;AACtB,UAAM,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC;AAAA,EACnE;AACF;AAEA,SAAS,eAAe,OAAgB,WAAoB,WAAiC;AAC3F,MAAI,iBAAiB,aAAc,QAAO;AAC1C,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO,IAAI,aAAa,SAAS,YAAY,YAAY,WAAW,SAAS;AAC/E;AAIA,SAAS,kBAAkB,SAAkD;AAC3E,QAAM,EAAE,aAAa,cAAc,IAAI;AAEvC,QAAM,eAAwC;AAAA;AAAA;AAAA,IAG5C,KAAK,eAAe,QAAQ;AAAA,IAC5B,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,IACzD,cAAc,cAAc;AAAA;AAAA;AAAA,IAG5B,gBAAgB;AAAA,IAChB,iCAAiC;AAAA;AAAA,IAEjC,gBAAgB,CAAC,QAAQ,WAAW,OAAO;AAAA;AAAA,IAE3C,gBAAgB;AAAA,EAClB;AAEA,MAAI,QAAQ,iBAAiB;AAC3B,iBAAa,SAAS,QAAQ;AAAA,EAChC;AAEA,MAAI,QAAQ,cAAc,OAAO,KAAK,QAAQ,UAAU,EAAE,SAAS,GAAG;AACpE,iBAAa,aAAa,QAAQ;AAAA,EACpC;AAEA,MAAI,QAAQ,UAAU,OAAO,KAAK,QAAQ,MAAM,EAAE,SAAS,GAAG;AAC5D,iBAAa,SAAS,QAAQ;AAAA,EAChC;AAEA,MAAI,QAAQ,OAAO,OAAO,KAAK,QAAQ,GAAG,EAAE,SAAS,GAAG;AAGtD,iBAAa,MAAM,EAAE,GAAG,QAAQ,KAAK,GAAG,QAAQ,IAAI;AAAA,EACtD;AAEA,SAAO;AACT;AAIA,eAAsB,WAAW,SAAiD;AAChF,QAAM,EAAE,QAAQ,eAAe,eAAe,QAAQ,IAAI;AAE1D,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,YAAY;AAEhB,QAAM,kBAAkB,IAAI,gBAAgB;AAC5C,QAAM,YAAY,WAAW,MAAM;AACjC,oBAAgB,MAAM,IAAI,MAAM,+BAA+B,CAAC;AAAA,EAClE,GAAG,aAAa;AAChB,QAAM,mBAAmB,WAAW,MAAM;AACxC,oBAAgB,MAAM,IAAI,MAAM,+BAA+B,CAAC;AAAA,EAClE,GAAG,aAAa;AAEhB,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,gCAAgC;AACzD,UAAM,eAAe,kBAAkB,OAAO;AAE9C,QAAI,SAAS;AACb,QAAI,UAAU;AACd,QAAI,YAAY;AAIhB,UAAM,SAAS,IAAI,MAAM,EAAE,QAAQ,SAAS,aAAsB,CAAC;AAEnE,qBAAiB,WAAW,QAAQ;AAClC,mBAAa,gBAAgB,MAAM;AAEnC,YAAM,MAAM;AAEZ,UAAI,cAAc,GAAG,GAAG;AACtB,oBAAY,IAAI;AAChB,qBAAa,SAAS;AACtB,kBAAU,EAAE,MAAM,iBAAiB,UAAU,CAAC;AAAA,MAChD;AAEA,UAAI,gBAAgB,GAAG,GAAG;AACxB,iBAAS,IAAI,UAAU;AACvB,kBAAU,IAAI,kBAAkB;AAChC,oBAAY,IAAI,aAAa;AAC7B,oBAAY,IAAI,cAAc;AAE9B,YAAI,IAAI,YAAY,WAAW;AAC7B,gBAAM,IAAI;AAAA,YACR,6BAA6B,IAAI,OAAO;AAAA,YACxC,IAAI;AAAA,YACJ;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAA+B;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,KAAK,IAAI,IAAI;AAAA,MACzB;AAAA,IACF;AAEA,cAAU,EAAE,MAAM,oBAAoB,WAAW,QAAQ,cAAc,CAAC;AACxE,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,iBAAiB,aAAa;AACpC,UAAM,eAAe,eAAe,OAAO,gBAAgB,OAAO,SAAS,cAAc;AAEzF,cAAU,EAAE,MAAM,gBAAgB,WAAW,gBAAgB,OAAO,aAAa,QAAQ,CAAC;AAC1F,UAAM;AAAA,EACR,UAAE;AACA,iBAAa,SAAS;AACtB,iBAAa,gBAAgB;AAAA,EAC/B;AACF;AAIO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACE,SACgB,WACA,WAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;ACxJA,SAAS,0BAA0B,KAA6B;AAC9D,SAAO;AAAA;AAAA,iCAEwB,IAAI,OAAO,eAAe,IAAI,QAAQ;AAAA,oBACnD,IAAI,SAAS;AAAA,uBACV,IAAI,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOvC;AAKA,SAAS,qBAAqB,gBAAwB,KAA6B;AACjF,SAAO,0BAA0B,GAAG,IAAI;AAC1C;AAKA,SAAS,iBAAiB,OAAmD;AAC3E,MAAI,iBAAiB,cAAc;AACjC,WAAO,EAAE,SAAS,MAAM,SAAS,MAAM,MAAM,UAAU;AAAA,EACzD;AACA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,EAAE,SAAS,MAAM,SAAS,MAAM,UAAU;AAAA,EACnD;AACA,SAAO,EAAE,SAAS,OAAO,KAAK,GAAG,MAAM,UAAU;AACnD;AAIA,IAAM,wBAAwB,CAAC,iBAAiB;AAIhD,SAAS,YAAY,SAAyB;AAC5C,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAIA,SAAS,eAAe,OAAgB,cAAiC;AACvE,SAAO,iBAAiB,gBAAgB,aAAa,SAAS,MAAM,SAAS;AAC/E;AAEA,SAAS,gBAAgB,OAAgB,SAAiD;AACxF,MAAI,iBAAiB,gBAAgB,MAAM,cAAc,WAAW;AAClE,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAgB,YAA2B;AAClE,MAAI,iBAAiB,OAAO;AAC1B,WAAO,IAAI,MAAM,yBAAyB,UAAU,0BAA0B,MAAM,OAAO,IAAI;AAAA,MAC7F,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,SAAO,IAAI,MAAM,yBAAyB,UAAU,WAAW;AACjE;AAeA,eAAsB,gBAAgB,SAAkD;AACtF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,IACR,GAAG;AAAA,EACL,IAAI;AAEJ,MAAI;AACJ,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,UAAM,WAAW,YAAY,OAAO;AACpC,gBAAY,SAAS,QAAQ;AAG7B,UAAM,SAAS,qBACX,qBAAqB,gBAAgB,kBAAkB,IACvD;AAEJ,QAAI;AACF,YAAM,SAAS,MAAM,WAAW;AAAA,QAC9B,GAAG;AAAA,QACH;AAAA,QACA,iBAAiB,aAAa,WAAW,gBAAgB;AAAA,MAC3D,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,sBAAgB,gBAAgB,OAAO,aAAa;AAEpD,UAAI,eAAe,OAAO,YAAY,EAAG,OAAM;AAC/C,UAAI,YAAY,WAAY,OAAM,gBAAgB,OAAO,UAAU;AAGnE,YAAM,YAAY,iBAAiB,KAAK;AACxC,2BAAqB;AAAA,QACnB,cAAc,UAAU;AAAA,QACxB,WAAW,UAAU;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAGA,UAAI,YAAY,UAAU,CAAC,MAAM,SAAS;AACxC,wBAAgB;AAAA,MAClB;AAEA,YAAM,MAAM,gBAAgB,OAAO;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,8BAA8B;AAChD;;;ACxHA,SAAS,uBACP,OACA,MACA,OACA,MACA,iBACmB;AACnB,QAAM,QAAQ,oBAAI,IAAqB;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,CAAC,QAAgB;AACrB,YAAM,QAAQ,gBAAgB,GAAG;AACjC,UAAI,UAAU,OAAW,QAAO;AAChC,aAAO,MAAM,IAAI,GAAG;AAAA,IACtB;AAAA,IACA,MAAM,CAAC,KAAa,UAAmB;AACrC,YAAM,IAAI,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AACF;AAQO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YACmB,QACA,iBACjB;AAFiB;AACA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMH,MAAM,QACJ,OACA,MACiC;AACjC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,IAAI;AAEJ,UAAM,EAAE,YAAY,YAAY,eAAe,UAAU,IAAI;AAG7D,QAAI,MAAM,YAAY,cAAc,CAAC,QAAQ;AAC3C,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,YAAY,aAAc,SAAoB;AAGvE,UAAM,gBAAgB,mBAAmB,OAAO,WAAW;AAG3D,UAAM,QAAQ,qBAAqB,UAAU;AAC7C,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,KAAK;AAAA,IACP;AACA,UAAM,QAAQ,cAAc,OAAO,mBAAmB,UAAU;AAGhE,UAAM,mBAAmB,MAAM,qBAAqB,QAAQ;AAC5D,UAAM,kBAAkB;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,WAAW,cAAc;AAAA,MACzB;AAAA,IACF;AAEA,UAAM,kBAAkB,cACpB;AAAA;AAAA,6CAAsE,WAAW;AAAA,4FACjF;AAEJ,UAAM,wBAAwB,2BAA2B,KAAK;AAE9D,UAAM,aAAa;AAAA,MACjB,MAAM,WAAW;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,WAAmC;AAAA,MACvC,YAAY;AAAA,MACZ,gBAAgB,MAAM;AAAA,MACtB,gBAAgB;AAAA,IAClB;AAEA,UAAM,gBAAgB,MAAM,gBAAgB;AAAA,MAC1C;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL,QAAQ,MAAM,WAAW;AAAA,MACzB,eAAe,KAAK,OAAO;AAAA,MAC3B,eAAe,KAAK,OAAO;AAAA,MAC3B,YAAY,KAAK,OAAO;AAAA,MACxB,eAAe,KAAK,OAAO;AAAA,MAC3B,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,MACrC,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;AAAA,MACnC,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,MACjC,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;AAAA,IACvD,CAAC;AAGD,QAAI,MAAM,YAAY,UAAa,cAAc,WAAW,MAAM,SAAS;AACzE,YAAM,IAAI;AAAA,QACR,mCAAmC,cAAc,QAAQ,QAAQ,CAAC,CAAC,QAAQ,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAAA,QACnG;AAAA,QACA,cAAc;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,SAAS,YAAY,cAAc,MAAM;AAG/C,UAAM,SAAiC;AAAA,MACrC,QAAQ;AAAA,MACR,WAAW,cAAc;AAAA,MACzB,QAAQ,OAAO,UAAU,OAAO;AAAA,MAChC,WAAW,cAAc;AAAA,MACzB,SAAS,cAAc;AAAA,MACvB,YAAY,cAAc;AAAA,MAC1B,OAAO,MAAM;AAAA,MACb;AAAA,MACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,SAAS;AAAA,MACT;AAAA,IACF;AAEA,QAAI,OAAO,OAAO;AAChB,aAAO,QAAQ,OAAO;AAAA,IACxB;AACA,QAAI,OAAO,aAAa,QAAW;AACjC,aAAO,WAAW,OAAO;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AACF;;;AC5NA,SAAS,KAAAE,UAAS;AAIX,IAAM,mBAAmBA,GAAE,KAAK;AAAA,EACrC;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF,CAAC;AAMM,IAAM,yBAAyBA,GAAE,KAAK,CAAC,QAAQ,WAAW,CAAC;AAM3D,IAAM,oBAAoBA,GAAE,OAAO;AAAA,EACxC,IAAIA,GAAE,OAAO;AAAA,EACb,MAAM;AAAA,EACN,OAAOA,GAAE,OAAO;AAAA;AAAA,EAChB,SAASA,GAAE,OAAO;AAAA,EAClB,QAAQA,GAAE,OAAO;AAAA;AAAA,EACjB,MAAMA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAGpC,WAAWA,GAAE,OAAO;AAAA,EACpB,gBAAgBA,GAAE,OAAO;AAAA,EACzB,aAAaA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA;AAAA,EAGjC,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAC/B,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAC7B,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,UAAUA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAC9B,UAAUA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAE/B,CAAC;AAMM,IAAM,yBAAyBA,GAAE,OAAO;AAAA,EAC7C,MAAM;AAAA,EACN,OAAOA,GAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,EAClC,SAASA,GAAE,OAAO;AAAA,EAClB,QAAQA,GAAE,OAAO,EAAE,QAAQ,MAAM;AAAA,EACjC,MAAMA,GAAE,MAAMA,GAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpC,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,UAAUA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAUA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA;AAC/B,CAAC;;;ACzDD,IAAM,gBAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,WAAW;AACb;AAMO,SAAS,wBAAwB,UAAiC;AACvE,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,QAAM,YAAY,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AAC/D,QAAM,WAAW,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAC5D,QAAM,QAAQ,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO;AAEvD,QAAM,WAAqB,CAAC;AAG5B,MAAI,UAAU,SAAS,GAAG;AACxB,UAAM,QAAQ,UAAU,OAAO,CAAC,MAAM,EAAE,YAAY,UAAU,CAAC,EAAE,OAAO;AACxE,UAAM,aAAa,UAAU,OAAO,CAAC,MAAM,EAAE,YAAY,WAAW;AAEpE,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,QAAQ,MAAM,IAAI,CAAC,MAAM;AAC7B,cAAM,aAAa,EAAE,eAAe,IAAI,KAAK;AAC7C,cAAM,OAAO,cAAc;AAC3B,eAAO,GAAG,IAAI,IAAI,EAAE,OAAO,GAAG,UAAU;AAAA,MAC1C,CAAC;AACD,eAAS,KAAK;AAAA,EAAc,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,IAChD;AAEA,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,QAAQ,WAAW,IAAI,CAAC,MAAM;AAClC,cAAM,aAAa,EAAE,eAAe,IAAI,KAAK;AAC7C,cAAM,OAAO,cAAc;AAC3B,eAAO,GAAG,IAAI,IAAI,EAAE,OAAO,GAAG,UAAU;AAAA,MAC1C,CAAC;AACD,eAAS,KAAK;AAAA,EAAgB,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,IAClD;AAAA,EACF;AAGA,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,QAAQ,SAAS,IAAI,CAAC,MAAM;AAChC,YAAM,WAAW,EAAE,WAAW,IAAI,EAAE,QAAQ,OAAO;AACnD,aAAO,UAAK,QAAQ,GAAG,EAAE,OAAO;AAAA,IAClC,CAAC;AACD,aAAS,KAAK;AAAA,EAAiB,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,EACnD;AAGA,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,QAAQ,MAAM,IAAI,CAAC,MAAM,UAAK,EAAE,OAAO,EAAE;AAC/C,aAAS,KAAK;AAAA,EAAsB,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,EACxD;AAEA,SAAO;AAAA;AAAA,EAA2C,SAAS,KAAK,MAAM,CAAC;AACzE;;;AC5DA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,cAAAC,aAAY,iBAAiB;AACtC,SAAS,qBAAqB;AAC9B,OAAOC,WAAU;AASjB,IAAM,aAAa,cAAc,YAAY,GAAG;AAKzC,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EAER,YAAY,QAAgB;AAC1B,UAAM,MAAMA,MAAK,QAAQ,MAAM;AAC/B,QAAI,CAACD,YAAW,GAAG,GAAG;AACpB,gBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAGA,UAAM,WAAW,WAAW,gBAAgB;AAC5C,SAAK,KAAK,IAAI,SAAS,MAAM;AAC7B,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,GAAG,OAAO,mBAAmB;AAElC,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAIQ,aAAmB;AAIzB,SAAK,sBAAsB;AAG3B,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAqBZ;AAGD,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAOZ;AAGD,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAWZ;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBQ,wBAA8B;AAEpC,UAAM,YAAY,KAAK,GACpB,QAAQ,sEAAsE,EAC9E,IAAI;AAGP,QAAI,CAAC,UAAW;AAIhB,UAAM,cACJ,UAAU,IAAI,SAAS,QAAQ,KAC/B,UAAU,IAAI,SAAS,aAAa,KACpC,UAAU,IAAI,SAAS,YAAY,KACnC,UAAU,IAAI,SAAS,WAAW,KAClC,UAAU,IAAI,SAAS,QAAQ;AAGjC,QAAI,CAAC,YAAa;AAKlB,UAAM,aAAa,UAAU,IAAI,SAAS,SAAS;AACnD,QAAI,CAAC,YAAY;AACf,UAAI;AACF,aAAK,GAAG,KAAK,8CAA8C;AAAA,MAC7D,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,SAAK,GAAG,KAAK,mBAAmB;AAChC,QAAI;AAEF,WAAK,GAAG,KAAK,6CAA6C;AAG1D,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAkBZ;AAOD,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAqBZ;AAGD,WAAK,GAAG,KAAK,yBAAyB;AAGtC,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA,OAGZ;AAKD,YAAM,YAAY,KAAK,GACpB,QAAQ,2EAA2E,EACnF,IAAI;AACP,UAAI,WAAW;AAEb,aAAK,GAAG,KAAK,0BAA0B;AACvC,aAAK,GAAG;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAEA,WAAK,GAAG,KAAK,QAAQ;AAAA,IACvB,SAAS,KAAK;AAEZ,UAAI;AACF,aAAK,GAAG,KAAK,UAAU;AAAA,MACzB,QAAQ;AAAA,MAER;AAIA,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA,eAAe,QAAQ,IAAI,UAAU;AAAA,QACrC;AAAA,QACA;AAAA,MACF;AAAA,IAEF;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,MAAM,OAA0C;AACpD,UAAM,KAAK,OAAOD,YAAW,EAAE,MAAM,GAAG,EAAE,CAAC;AAC3C,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,SAAK,GACF;AAAA,MACC;AAAA;AAAA,IAEF,EACC;AAAA,MACC;AAAA,MACA,MAAM;AAAA,MACN,MAAM,SAAS;AAAA,MACf,MAAM;AAAA,MACN,MAAM,UAAU;AAAA,MAChB,KAAK,UAAU,MAAM,QAAQ,CAAC,CAAC;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,MAAM,aAAa;AAAA,MACnB,MAAM,WAAW;AAAA,MACjB,MAAM,SAAS;AAAA,MACf,MAAM,YAAY;AAAA,MAClB,MAAM,YAAY;AAAA,MAClB,MAAM,WAAW;AAAA,IACnB;AAEF,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,OAAO,IAAY,SAAuB;AACxC,SAAK,GAAG,QAAQ,8CAA8C,EAAE,IAAI,SAAS,EAAE;AAAA,EACjF;AAAA;AAAA,EAIA,aAAa,IAAY,QAAsE;AAC7F,UAAM,OAAiB,CAAC;AACxB,UAAM,SAAoB,CAAC;AAC3B,QAAI,OAAO,YAAY,QAAW;AAChC,WAAK,KAAK,aAAa;AACvB,aAAO,KAAK,OAAO,OAAO;AAAA,IAC5B;AACA,QAAI,OAAO,YAAY,QAAW;AAChC,WAAK,KAAK,aAAa;AACvB,aAAO,KAAK,OAAO,OAAO;AAAA,IAC5B;AACA,QAAI,OAAO,UAAU,QAAW;AAC9B,WAAK,KAAK,YAAY;AACtB,aAAO,KAAK,OAAO,KAAK;AAAA,IAC1B;AACA,QAAI,KAAK,WAAW,EAAG;AACvB,WAAO,KAAK,EAAE;AACd,SAAK,GAAG,QAAQ,uBAAuB,KAAK,KAAK,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,MAAM;AAAA,EACtF;AAAA;AAAA,EAIA,OAAO,IAAkB;AACvB,SAAK,GAAG,QAAQ,mCAAmC,EAAE,IAAI,EAAE;AAAA,EAC7D;AAAA;AAAA,EAIA,MAAM,OAAoB,CAAC,GAAkB;AAC3C,UAAM,aAAuB,CAAC;AAC9B,UAAM,SAAoB,CAAC;AAE3B,QAAI,KAAK,OAAO;AACd,iBAAW,KAAK,iCAAiC;AACjD,aAAO,KAAK,KAAK,KAAK;AAAA,IACxB;AAEA,QAAI,KAAK,SAAS,KAAK,MAAM,SAAS,GAAG;AACvC,YAAM,eAAe,KAAK,MAAM,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG;AACvD,iBAAW,KAAK,YAAY,YAAY,GAAG;AAC3C,aAAO,KAAK,GAAG,KAAK,KAAK;AAAA,IAC3B;AAEA,QAAI,KAAK,OAAO;AACd,iBAAW,KAAK,gBAAgB;AAChC,aAAO,KAAK,KAAK,KAAK;AAAA,IACxB;AAGA,QAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AACrC,YAAM,gBAAgB,KAAK,KAAK;AAAA,QAC9B,MAAM;AAAA,MACR;AACA,iBAAW,KAAK,IAAI,cAAc,KAAK,MAAM,CAAC,GAAG;AACjD,aAAO,KAAK,GAAG,KAAK,IAAI;AAAA,IAC1B;AAEA,UAAM,QAAQ,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,OAAO,CAAC,KAAK;AAE5E,QAAI;AACJ,YAAQ,KAAK,QAAQ;AAAA,MACnB,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF;AACE,kBACE;AACF;AAAA,IACJ;AAEA,UAAM,QAAQ,KAAK,QAAQ,SAAS,KAAK,KAAK,KAAK;AAEnD,UAAM,OAAO,KAAK,GACf,QAAQ,0BAA0B,KAAK,IAAI,OAAO,IAAI,KAAK,EAAE,EAC7D,IAAI,GAAG,MAAM;AAEhB,WAAO,KAAK,IAAI,UAAU;AAAA,EAC5B;AAAA;AAAA,EAIA,MAAM,OAAO,MAAc,OAAoB,CAAC,GAA4B;AAE1E,UAAM,QAAQ,KAAK,SAAS;AAC5B,UAAM,WAAW,KACd,MAAM,KAAK,EACX,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EACnB,KAAK,MAAM;AAEd,QAAI,CAAC,UAAU;AACb,aAAO,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,EAAE,EAAE;AAAA,IACzD;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,GACf;AAAA,QACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMF,EACC,IAAI,UAAU,KAAK;AAEtB,YAAM,WAAW,KAAK,OAAO,CAAC,QAAQ;AACpC,YAAI,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,SAAU,QAAO;AAC7E,YACE,KAAK,SACL,KAAK,MAAM,SAAS,KACpB,CAAC,KAAK,MAAM,SAAS,IAAI,IAA2B;AAEpD,iBAAO;AACT,eAAO;AAAA,MACT,CAAC;AAED,UAAI,SAAS,WAAW,GAAG;AACzB,eAAO,CAAC;AAAA,MACV;AAKA,YAAM,QAAQ,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AACxC,YAAM,UAAU,KAAK,IAAI,GAAG,KAAK;AACjC,YAAM,UAAU,KAAK,IAAI,GAAG,KAAK;AAEjC,aAAO,SAAS,IAAI,CAAC,QAAQ;AAC3B,YAAI;AACJ,YAAI,YAAY,SAAS;AAEvB,kBAAQ;AAAA,QACV,OAAO;AAEL,kBAAQ,KAAK,IAAI,OAAO,YAAY,UAAU;AAAA,QAChD;AACA,eAAO;AAAA,UACL,GAAG,WAAW,GAAG;AAAA,UACjB,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAAA,QACvC;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AAEN,aAAO,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,EAAE,EAAE;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,KAAqB;AAChC,QAAI,IAAI,WAAW,EAAG;AACtB,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,OAAO,KAAK,GAAG;AAAA,MACnB;AAAA,IACF;AACA,UAAM,cAAc,KAAK,GAAG,YAAY,MAAM;AAC5C,iBAAW,MAAM,KAAK;AACpB,aAAK,IAAI,KAAK,EAAE;AAAA,MAClB;AAAA,IACF,CAAC;AACD,gBAAY;AAAA,EACd;AAAA,EAEA,MAAM,aAAa,IAAI,iBAAiB,GAAW;AAEjD,UAAM,cAAc,KAAK,GACtB;AAAA,MACC;AAAA;AAAA;AAAA;AAAA,IAIF,EACC,IAAI,gBAAgB,UAAU;AAEjC,WAAO,YAAY;AAAA,EACrB;AAAA,EAEA,kBAA0B;AACxB,UAAM,SAAS,KAAK,GACjB;AAAA,MACC;AAAA;AAAA;AAAA;AAAA,IAIF,EACC,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC;AAC/B,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA,EAIA,QAAqB;AACnB,UAAM,QACJ,KAAK,GAAG,QAAQ,wCAAwC,EAAE,IAAI,EAC9D;AAEF,UAAM,aAAa,KAAK,GACrB,QAAQ,4DAA4D,EACpE,IAAI;AACP,UAAM,SAAiC,CAAC;AACxC,eAAW,OAAO,YAAY;AAC5B,aAAO,IAAI,IAAI,IAAI,IAAI;AAAA,IACzB;AAEA,UAAM,cAAc,KAAK,GACtB,QAAQ,8DAA8D,EACtE,IAAI;AACP,UAAM,UAAkC,CAAC;AACzC,eAAW,OAAO,aAAa;AAC7B,cAAQ,IAAI,KAAK,IAAI,IAAI;AAAA,IAC3B;AAEA,WAAO,EAAE,OAAO,QAAQ,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,QAAQ,GAAkB;AACpC,UAAM,OAAO,KAAK,GACf;AAAA,MACC;AAAA;AAAA;AAAA,IAGF,EACC,IAAI,KAAK;AAEZ,WAAO,KAAK,IAAI,UAAU;AAAA,EAC5B;AAAA;AAAA,EAIA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;AAsBA,SAAS,WAAW,KAAgC;AAClD,MAAI,OAAiB,CAAC;AACtB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EAC5B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV,OAAO,IAAI;AAAA,IACX,SAAS,IAAI;AAAA,IACb,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,WAAW,IAAI;AAAA,IACf,gBAAgB,IAAI;AAAA,IACpB,aAAa,IAAI;AAAA,IACjB,WAAW,IAAI,cAAc;AAAA,IAC7B,SAAS,IAAI,WAAW;AAAA,IACxB,OAAO,IAAI,UAAU;AAAA,IACrB,UAAU,IAAI,YAAY;AAAA,IAC1B,UAAU,IAAI,YAAY;AAAA,IAC1B,SAAS,IAAI,WAAW;AAAA,EAC1B;AACF;;;AXlhBA,IAAM,kBAAkB,MAAM;AAC9B,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB,IAAI,KAAK;AACrC,IAAM,cAAc,IAAI,YAAY;AAgC7B,IAAM,eAAN,cAA2B,gBAAgB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA,mBAAmB,oBAAI,IAA2B;AAAA,EAClD,kBAAkB,oBAAI,IAA2B;AAAA,EACjD,mBAAmB,oBAAI,IAA8B;AAAA,EACrD,mBAAmB,oBAAI,IAA6B;AAAA,EACpD,YAAY,oBAAI,IAAwB;AAAA,EACxC,WAAW,IAAI,SAAS;AAAA,EACxB;AAAA,EACT,cAAkC;AAAA,EAClC,eAAoC;AAAA,EACpC,oBAA8C;AAAA,EAC9C,cAAkC;AAAA,EAClC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,aAAa;AAAA,EACb,gBAAqC;AAAA,EAE5B;AAAA,EAEjB,YAAY,QAAmB,UAA+B,CAAC,GAAG;AAChE,UAAM;AACN,SAAK,SAAS;AACd,SAAK,iBAAiB,QAAQ,cAAc,CAAC;AAC7C,SAAK,aAAa,QAAQ,cAAc,eAAe;AACvD,SAAK,qBAAqB,QAAQ,sBAAsB;AACxD,eAAW,QAAQ,OAAO,OAAO;AAC/B,YAAM,eAAeG,OAAK,QAAQ,KAAK,IAAI;AAC3C,YAAM,iBAAiB,EAAE,GAAG,MAAM,MAAM,aAAa;AACrD,WAAK,UAAU,IAAI,cAAc,cAAc;AAAA,IACjD;AACA,SAAK,YAAY,IAAI;AAAA,MACnB;AAAA,QACE,aAAa,OAAO,YAAY;AAAA,QAChC,YAAY,OAAO,YAAY;AAAA,QAC/B,UAAU,OAAO,YAAY;AAAA,MAC/B;AAAA,MACA;AAAA,QACE,WAAW,CAAC,WAAW,MAAM,aAAa;AACxC,eAAK,KAAK;AAAA,YACR,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,QACA,WAAW,CAAC,WAAW,MAAM,aAAa;AACxC,eAAK,KAAK;AAAA,YACR,MAAM;AAAA,YACN;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,cAAc,OAA4B;AACxC,SAAK,iBAAiB,IAAI,MAAM,MAAM,KAAK;AAAA,EAC7C;AAAA;AAAA,EAIA,MAAM,SAAS,OAA2C;AACxD,UAAM,iBAAiB,KAAK,kBAAkB,KAAK;AACnD,UAAM,MAAM,KAAK,qBAAqB,KAAK;AAG3C,UAAM,kBAAkB,IAAI,gBAAgB;AAC5C,SAAK,iBAAiB,IAAI,IAAI,WAAW,eAAe;AACxD,UAAM,KAAK,UAAU;AAAA,MACnB,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,MAAM,YAAY;AAAA,MAClB,gBAAgB;AAAA,IAClB;AACA,QAAI,cAAc,SAAS;AAE3B,UAAM,aAAa,MAAM,KAAK,YAAY,GAAG;AAC7C,WAAO,KAAK,iBAAiB,KAAK,YAAY,cAAc;AAAA,EAC9D;AAAA;AAAA,EAIA,QAAc;AACZ,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,SAAe;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,KAAK,WAAkC;AAC3C,UAAM,aAAa,KAAK,iBAAiB,IAAI,SAAS;AACtD,QAAI,YAAY;AACd,iBAAW,MAAM,IAAI,MAAM,gBAAgB,CAAC;AAAA,IAC9C;AAEA,SAAK,gBAAgB,OAAO,SAAS;AACrC,SAAK,iBAAiB,OAAO,SAAS;AACtC,SAAK,UAAU,QAAQ,SAAS;AAAA,EAClC;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,QAAI,KAAK,gBAAgB,SAAS,EAAG;AACrC,WAAO,IAAI,QAAc,CAACC,aAAY;AACpC,WAAK,gBAAgBA;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,IAAI,SAA6B;AAC/B,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,gBAAgB,CAAC,GAAG,KAAK,gBAAgB,OAAO,CAAC;AAAA,MACjD,gBAAgB,KAAK;AAAA,MACrB,YAAY,KAAK,UAAU,WAAW;AAAA,MACtC,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK,OAAO,OAAO;AAAA,MACjC,oBAAoB,KAAK,0BAA0B;AAAA,MACnD,QAAQ,KAAK,aAAa,IAAI,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,IAAI,iBAAkC;AACpC,WAAO,CAAC,GAAG,KAAK,gBAAgB,OAAO,CAAC;AAAA,EAC1C;AAAA,EAEA,IAAI,iBAAyB;AAC3B,QAAI,QAAQ;AACZ,eAAW,WAAW,KAAK,gBAAgB,OAAO,GAAG;AACnD,UAAI,QAAQ,WAAW,WAAW;AAChC;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAM,QAAuB;AAC3B,SAAK,aAAa,KAAK,IAAI;AAG3B,SAAK,cAAc,IAAI,YAAY,EAAE,KAAK,KAAK,WAAW,CAAC;AAC3D,SAAK,eAAe,IAAI,aAAa,EAAE,KAAK,KAAK,WAAW,CAAC;AAG7D,UAAM,qBAAqB,MAAM,KAAK,2BAA2B;AAEjE,UAAM,cAAc,CAAC,GAAG,KAAK,OAAO,UAAU,GAAG,kBAAkB;AACnE,QAAI,YAAY,SAAS,GAAG;AAC1B,WAAK,oBAAoB,IAAI,kBAAkB,WAAW;AAAA,IAC5D;AAGA,QAAI,mBAAmB,SAAS,GAAG;AAEjC,cAAQ;AAAA,QACN,oBAAoB,mBAAmB,MAAM,2BAA2B,mBAAmB,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;AAAA,MACzH;AAAA,IACF;AAGA,SAAK,aAAa,MAAM,KAAK,YAAY,YAAY;AAErD,QAAI,CAAC,KAAK,oBAAoB;AAC5B,YAAM,KAAK,oBAAoB;AAAA,IACjC;AAEA,UAAMC,OAAM,KAAK,OAAO,SAAS,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3D;AAAA,EAEA,MAAM,WAA0B;AAC9B,SAAK,UAAU;AAEf,QAAI,KAAK,gBAAgB,OAAO,GAAG;AACjC,YAAM,QAAQ,KAAK;AAAA,QACjB,KAAK,MAAM;AAAA,QACX,IAAI,QAAc,CAACD,aAAY,WAAWA,UAAS,mBAAmB,CAAC;AAAA,MACzE,CAAC;AAAA,IACH;AAEA,eAAW,MAAM,KAAK,gBAAgB;AACpC,UAAI,WAAW,MAAM,OAAO,GAAG,UAAU,YAAY;AACnD,cAAO,GAAsC,MAAM;AAAA,MACrD;AACA,UAAI,aAAa,MAAM,OAAO,GAAG,YAAY,YAAY;AACvD,mBAAW,WAAW,KAAK,gBAAgB,OAAO,GAAG;AACnD,UAAC,GAAyC,QAAQ,QAAQ,SAAS;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAEA,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAID,QAAI,KAAK,mBAAmB;AAC1B,YAAM,KAAK,kBAAkB,MAAM;AAAA,IACrC;AAAA,EACF;AAAA;AAAA,EAIS,KAAK,OAAuB;AACnC,UAAM,KAAK,KAAK;AAEhB,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,OAAO,KAAK,EAAE,MAAM,CAAC,QAAQ;AAE7C,gBAAQ,MAAM,sCAAsC,GAAG;AAAA,MACzD,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,mBAAmB;AAC1B,WAAK,kBAAkB,SAAS,KAAK;AAAA,IACvC;AAAA,EACF;AAAA;AAAA,EAIA,OAAO,aAAa;AAAA,IAClB,eAAe,CAAC,YAAsD,cAAc,OAAO;AAAA,IAC3F,UAAU,CAAC,YAML,SAAS,OAAO;AAAA,IACtB,aAAa,MAAM,YAAY;AAAA,EACjC;AAAA;AAAA,EAIQ,kBAAkB,OAAqC;AAC7D,SAAK,cAAc,KAAK;AAExB,UAAM,iBAAiB,KAAK,sBAAsB,KAAK;AACvD,QAAI,gBAAgB;AAClB,WAAK,+BAA+B;AACpC,YAAM,SAAS,KAAK,iBAAiB,IAAI,cAAc;AACvD,UAAI,UAAU,OAAO,YAAY,KAAK,IAAI,GAAG;AAC3C,cAAM,IAAI;AAAA,UACR,uCAAuC,MAAM,SAAS,gBAAgB;AAAA,QACxE;AAAA,MACF;AAAA,IACF;AAEA,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,qBAAqB,OAAuC;AAClE,UAAM,QAAQ,MAAM,SAASE,YAAW;AACxC,UAAM,YAAYA,YAAW;AAC7B,UAAM,QAAQ,KAAK,iBAAiB,IAAI,MAAM,KAAK;AACnD,QAAI,CAAC,OAAO;AACV,YAAM,YAAY,CAAC,GAAG,KAAK,iBAAiB,KAAK,CAAC,EAAE,KAAK,IAAI,KAAK;AAClE,YAAM,IAAI;AAAA,QACR,UAAU,MAAM,KAAK,kCAAkC,SAAS;AAAA,MAClE;AAAA,IACF;AACA,UAAM,aAAa,KAAK,YAAY,MAAM,IAAI;AAE9C,UAAM,gBAA+B;AAAA,MACnC;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,QAAQ;AAAA,MACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,SAAK,gBAAgB,IAAI,WAAW,aAAa;AAEjD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,YAAY,KAA2C;AACnE,UAAM,EAAE,OAAO,OAAO,WAAW,WAAW,OAAO,YAAY,cAAc,IAAI;AACjF,QAAI;AAGJ,UAAM,KAAK,WAAW;AAAA,MACpB,SAAS;AAAA,MACT;AAAA,MACA,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,QAAQ;AAAA,MACR,OAAO,CAAC;AAAA,MACR,WAAW,cAAc;AAAA,MACzB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,UAAU,MAAM;AAAA,IAClB,CAAC;AAED,QAAI;AAGF,YAAM,aAAc,MAAM,UAAqB,WAAW;AAC1D,YAAM,aAAaH,OAAK,KAAK,KAAK,OAAO,SAAS,KAAK,KAAK;AAC5D,YAAM,OAAO,MAAM,mBAAmB;AAAA,QACpC,UAAU,MAAM;AAAA,QAChB,QAAQ;AAAA,QACR,YAAY,WAAW;AAAA,QACvB;AAAA,MACF,CAAC;AACD,oBAAc,KAAK;AACnB,oBAAc,cAAc;AAE5B,YAAM,aAAa,MAAM,KAAK,gBAAgB,KAAK,WAAW;AAC9D,WAAK,eAAe,WAAW,WAAW,SAAS,GAAG;AACtD,WAAK,oBAAoB,KAAK,UAAU;AACxC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACtE,WAAK,gBAAgB,KAAK,QAAQ;AAElC,YAAM,aAAyB;AAAA,QAC7B,QAAQ;AAAA,QACR;AAAA,QACA,SAAS;AAAA,QACT,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,OAAO,MAAM;AAAA,QACb,WAAW,cAAc;AAAA,QACzB,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,OAAO;AAAA,QACP,SAAS;AAAA,MACX;AAGA,aAAO;AAAA,IACT,UAAE;AAEA,UAAI,aAAa;AACf,cAAM,KAAK,gBAAgB,aAAa,GAAG;AAAA,MAC7C;AAGA,iBAAW,MAAM,KAAK,gBAAgB;AACpC,YAAI,aAAa,MAAM,OAAO,GAAG,YAAY,YAAY;AACvD,UAAC,GAAyC,QAAQ,SAAS;AAAA,QAC7D;AAAA,MACF;AAEA,WAAK,UAAU,QAAQ,SAAS;AAChC,WAAK,gBAAgB,OAAO,SAAS;AACrC,WAAK,iBAAiB,OAAO,SAAS;AAEtC,UAAI,KAAK,gBAAgB,SAAS,KAAK,KAAK,eAAe;AACzD,aAAK,cAAc;AACnB,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAAgB,aAAqB,KAAqC;AAEtF,QAAI,IAAI,MAAM,YAAY,YAAY;AACpC,YAAM,SAAS,IAAI,MAAM;AACzB,YAAM,SAAS,IAAI,WAAW,cAAc;AAC5C,UAAI;AACF,cAAM,kBAAkB,aAAa,QAAQ,MAAM,EAAE,MAAM,CAAC,QAAQ;AAElE,kBAAQ,MAAM,sBAAsB,GAAG;AAAA,QACzC,CAAC;AAAA,MACH,SAAS,KAAK;AAEZ,gBAAQ,MAAM,6BAA6B,GAAG;AAAA,MAChD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,mBAAmB,WAAW;AAAA,IACtC,SAAS,KAAK;AAEZ,cAAQ,MAAM,iCAAiC,GAAG;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAc,gBACZ,KACA,aACqB;AACrB,UAAM,EAAE,OAAO,OAAO,WAAW,OAAO,YAAY,cAAc,IAAI;AAEtE,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAGD,UAAM,WAAW,IAAI;AAAA,MACnB;AAAA,QACE,eAAe,KAAK,OAAO,SAAS;AAAA,QACpC,eAAe,KAAK,OAAO,SAAS;AAAA,QACpC,YAAY,KAAK,OAAO,SAAS;AAAA,QACjC,eAAe,KAAK,OAAO,SAAS;AAAA,MACtC;AAAA,MACA,CAAC,QAAgB;AACf,YAAI,QAAQ,YAAa,QAAO,KAAK;AACrC,YAAI,QAAQ,eAAgB,QAAO,KAAK,OAAO,OAAO;AACtD,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,WAAW,MAAM,eAAe,WAAW,eAAe;AAChE,UAAM,aAAa,KAAK,kBAAkB,KAAK;AAC/C,UAAM,gBAAgB,KAAK,kBAAkB,MAAM,IAAI;AAEvD,UAAM,SAAS,MAAM,SAAS;AAAA,MAC5B;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,MAAM;AAAA,QAChB,QAAQ,MAAM;AAAA,QACd,QAAQ,MAAM;AAAA,QACd,aAAa;AAAA,QACb;AAAA,QACA,UAAU,MAAM;AAAA,QAChB,WAAW,cAAc;AAAA,MAC3B;AAAA,MACA;AAAA,QACE,YAAY,KAAK;AAAA,QACjB;AAAA,QACA;AAAA,QACA,WAAW,CAAC,SAASI,cAAa;AAChC,cAAI,UAAU,GAAG;AACf,iBAAK,KAAK;AAAA,cACR,MAAM;AAAA,cACN;AAAA,cACA;AAAA,cACA,OAAO,2BAA2BA,SAAQ;AAAA,cAC1C,SAAS,UAAU;AAAA,cACnB,YAAY,KAAK,OAAO,SAAS;AAAA,cACjC,WAAW;AAAA,cACX,UAAU,MAAM;AAAA,cAChB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,iBACZ,KACA,YACA,gBACqB;AACrB,UAAM,EAAE,OAAO,OAAO,OAAO,cAAc,IAAI;AAE/C,UAAM,aAAyB;AAAA,MAC7B;AAAA,MACA,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,QAAQ,WAAW,WAAW,YAAY,YAAY;AAAA,MACtD,OAAO,EAAE,SAAS,WAAW;AAAA,MAC7B,QACE,WAAW,WAAW,aAAa,cAAc,cAAc,MAAM,SAAS;AAAA,MAChF,SAAS,WAAW;AAAA,MACpB,YAAY,KAAK,IAAI,IAAI,IAAI;AAAA,MAC7B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,UAAU,MAAM;AAAA,IAClB;AAEA,QAAI,WAAW,OAAO;AACpB,iBAAW,QAAQ,WAAW;AAAA,IAChC;AACA,QAAI,WAAW,aAAa,QAAW;AACrC,iBAAW,WAAW,WAAW;AAAA,IACnC;AAEA,UAAM,KAAK,WAAW;AAAA,MACpB,SAAS;AAAA,MACT;AAAA,MACA,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,QAAQ,WAAW;AAAA,MACnB,QAAQ,WAAW,WAAW,YAAY,cAAc;AAAA,MACxD,OAAO,WAAW;AAAA,MAClB,WAAW,cAAc;AAAA,MACzB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,UAAU,MAAM;AAAA,IAClB,CAAC;AAED,QAAI,gBAAgB;AAClB,YAAM,MAAM,KAAK,OAAO,aAAa,SAAS;AAC9C,WAAK,iBAAiB,IAAI,gBAAgB;AAAA,QACxC,QAAQ;AAAA,QACR,WAAW,KAAK,IAAI,IAAI;AAAA,MAC1B,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAIQ,iBAA8B;AACpC,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,gBAAgBJ,OAAK,KAAK,kBAAkB,GAAG,YAAY;AACjE,WAAK,cAAc,IAAI,YAAYA,OAAK,KAAK,eAAe,eAAe,CAAC;AAAA,IAC9E;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,kBAAkB,UAAsC;AAC9D,QAAI;AACF,YAAM,QAAQ,KAAK,eAAe;AAClC,YAAM,WAAW,MAAM,MAAM;AAAA,QAC3B,OAAO;AAAA,QACP,OAAO,CAAC,aAAa,SAAS;AAAA,QAC9B,OAAO;AAAA,QACP,QAAQ;AAAA,MACV,CAAC;AACD,UAAI,SAAS,WAAW,EAAG,QAAO;AAClC,YAAM,aAAa,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC5C,aAAO,wBAAwB,QAAQ;AAAA,IACzC,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC7F;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAIQ,eAAe,WAAmB,aAAqB,KAA4B;AACzF,SAAK,cAAc;AAGnB,QAAI,KAAK,aAAa;AACpB,YAAM,YAAuB;AAAA,QAC3B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,OAAO,IAAI;AAAA,QACX,MAAM;AAAA,QACN;AAAA,QACA,OAAO,IAAI,MAAM;AAAA,QACjB,SAAS;AAAA,QACT,QAAQ,CAAC;AAAA,QACT,YAAY,KAAK,IAAI,IAAI,IAAI;AAAA,QAC7B,MAAM,IAAI,MAAM;AAAA,MAClB;AACA,WAAK,YAAY,OAAO,SAAS,EAAE,MAAM,CAAC,QAAQ;AAEhD,gBAAQ,MAAM,qCAAqC,GAAG;AAAA,MACxD,CAAC;AAAA,IACH;AAEA,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,oBAAoB,KAAK,0BAA0B;AAAA,MACnD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAED,UAAM,iBAAkB,KAAK,aAAa,KAAK,OAAO,OAAO,cAAe;AAC5E,QAAI,kBAAkB,KAAK,OAAO,OAAO,mBAAmB;AAC1D,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,YAAY,KAAK;AAAA,QACjB,QAAQ,KAAK,OAAO,OAAO;AAAA,QAC3B;AAAA,QACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,oBAAoB,KAAsB,YAA8B;AAC9E,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,WAAW,IAAI;AAAA,MACf,OAAO,IAAI;AAAA,MACX,QAAQ;AAAA,MACR,SAAS,WAAW;AAAA,MACpB,YAAY,WAAW;AAAA,MACvB,QAAQ,WAAW;AAAA,MACnB,UAAU,IAAI,MAAM;AAAA,MACpB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB,KAAsB,UAAwB;AACpE,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,WAAW,IAAI;AAAA,MACf,OAAO,IAAI;AAAA,MACX,OAAO;AAAA,MACP,SAAS;AAAA,MACT,YAAY,KAAK,OAAO,SAAS;AAAA,MACjC,WAAW;AAAA,MACX,UAAU,IAAI,MAAM;AAAA,MACpB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA,EAIQ,cAAc,OAA4B;AAChD,QAAI,CAAC,MAAM,UAAU,MAAM,OAAO,KAAK,EAAE,WAAW,GAAG;AACrD,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AACA,QAAI,YAAY,OAAO,MAAM,MAAM,EAAE,SAAS,iBAAiB;AAC7D,YAAM,IAAI;AAAA,QACR,oDAAoD,OAAO,eAAe,CAAC;AAAA,MAC7E;AAAA,IACF;AAEA,QAAI,CAACK,YAAW,MAAM,IAAI,GAAG;AAC3B,YAAM,IAAI,MAAM,+CAA+C,MAAM,IAAI,EAAE;AAAA,IAC7E;AAEA,QAAI,CAAC,KAAK,iBAAiB,IAAI,MAAM,KAAK,GAAG;AAC3C,YAAM,IAAI,MAAM,4BAA4B,MAAM,KAAK,yBAAyB;AAAA,IAClF;AAEA,QAAI,MAAM,aAAa,QAAW;AAChC,UAAI,CAAC,cAAc,MAAM,QAAQ,GAAG;AAClC,cAAM,IAAI,MAAM,mDAAmD;AAAA,MACrE;AACA,UAAI,YAAY,MAAM,QAAQ,IAAI,oBAAoB;AACpD,cAAM,IAAI;AAAA,UACR,+DAA+D,OAAO,kBAAkB,CAAC;AAAA,QAC3F;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAgB,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO;AAC1E,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,IAAI,MAAM,gEAAgE;AAAA,IAClF;AAAA,EACF;AAAA;AAAA,EAIQ,iCAAuC;AAC7C,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,kBAAkB;AAChD,UAAI,MAAM,aAAa,KAAK;AAC1B,aAAK,iBAAiB,OAAO,GAAG;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAAsB,OAAqC;AACjE,UAAM,cAAc,KAAK,OAAO;AAChC,QAAI,CAAC,aAAa,QAAS,QAAO;AAElC,UAAM,MAAM,YAAY,OAAO;AAC/B,QAAI,QAAQ,UAAU;AACpB,aAAO,GAAG,MAAM,KAAK,IAAI,MAAM,IAAI,IAAI,MAAM,MAAM;AAAA,IACrD;AACA,WAAO,GAAG,MAAM,KAAK,IAAI,MAAM,IAAI,IAAI,KAAK,UAAU,MAAM,YAAY,CAAC,CAAC,CAAC;AAAA,EAC7E;AAAA,EAEQ,YAAY,UAA8B;AAChD,UAAM,OAAO,KAAK,UAAU,IAAIL,OAAK,QAAQ,QAAQ,CAAC;AACtD,QAAI,KAAM,QAAO;AACjB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,eAAe;AAAA,MACf,cAAc;AAAA,MACd,YAAY;AAAA,MACZ,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EAEQ,4BAAoC;AAC1C,UAAM,MAAM,KAAK,OAAO,OAAO;AAC/B,QAAI,OAAO,EAAG,QAAO;AACrB,WAAO,KAAK,IAAI,IAAK,MAAM,KAAK,cAAc,MAAO,GAAG;AAAA,EAC1D;AAAA;AAAA,EAIQ,kBAAkB,OAAmE;AAC3F,UAAM,gBAAgB,KAAK,OAAO;AAClC,QAAI,CAAC,cAAe,QAAO;AAG3B,UAAM,QAAQ,MAAM,WAAW;AAC/B,QAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO;AAEzC,UAAM,WAA4C,CAAC;AACnD,eAAW,QAAQ,OAAO;AACxB,YAAM,eAAe,cAAc,IAAI;AACvC,UAAI,cAAc;AAChB,iBAAS,IAAI,IAAI;AAAA,MACnB;AAAA,IACF;AAEA,WAAO,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW;AAAA,EACvD;AAAA;AAAA;AAAA,EAKA,MAAc,6BAA6D;AACzE,UAAM,EAAE,SAAAM,SAAQ,IAAI,MAAM,OAAO,aAAkB;AACnD,UAAM,iBAAiB,kBAAkB;AACzC,QAAI,CAACD,YAAW,cAAc,EAAG,QAAO,CAAC;AAEzC,UAAM,WAAkC,CAAC;AAEzC,QAAI;AACF,YAAM,UAAU,MAAMC,SAAQ,gBAAgB,EAAE,eAAe,KAAK,CAAC;AACrE,iBAAW,SAAS,SAAS;AAC3B,YAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,YAAI;AACF,gBAAM,YAAYN,OAAK,KAAK,gBAAgB,MAAM,MAAM,YAAY;AACpE,gBAAM,MAAM,MAAMO,UAAS,WAAW,OAAO;AAC7C,gBAAM,QAAQ,KAAK,MAAM,GAAG;AAE5B,cAAI,MAAM,WAAW,aAAa,CAAC,MAAM,KAAM;AAC/C,cAAI,MAAM,OAAO,CAAC,eAAe,MAAM,GAAG,EAAG;AAE7C,mBAAS,KAAK;AAAA,YACZ,KAAK,oBAAoB,OAAO,MAAM,IAAI,CAAC;AAAA,YAC3C,QAAQ,CAAC,oBAAoB,gBAAgB,cAAc;AAAA,YAC3D,QAAQ,KAAK,OAAO,WAAW;AAAA,YAC/B,WAAW;AAAA,UACb,CAAC;AAAA,QACH,SAAS,KAAK;AAEZ,kBAAQ;AAAA,YACN,4DAA4D,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UAC9G;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,wDAAwD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC1G;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAc,WAAW,KAAkC;AACzD,UAAM,KAAK,SAAS,WAAW,GAAG;AAAA,EACpC;AAAA,EAEA,MAAc,sBAAqC;AACjD,UAAM,eAAe,MAAM,KAAK,SAAS,oBAAoB;AAG7D,eAAW,OAAO,cAAc;AAC9B,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,WAAW,IAAI;AAAA,QACf,OAAO,IAAI;AAAA,QACX,OAAO;AAAA,QACP,SAAS;AAAA,QACT,YAAY,KAAK,OAAO,SAAS;AAAA,QACjC,WAAW;AAAA,QACX,UAAU,IAAI;AAAA,QACd,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAIA,SAAS,cAAc,OAAkD;AACvE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,YAAY,KAAc,UAAU,GAAW;AACtD,MAAI,CAAC,cAAc,GAAG,EAAG,QAAO;AAChC,MAAI,MAAM,UAAU;AACpB,aAAW,SAAS,OAAO,OAAO,GAAG,GAAG;AACtC,UAAM,QAAQ,YAAY,OAAO,UAAU,CAAC;AAC5C,QAAI,QAAQ,IAAK,OAAM;AAAA,EACzB;AACA,SAAO;AACT;;;AYp4BA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,cAAAC,aAAY,YAAAC,WAAU,QAAQ,QAAAC,aAAY;AACnD,OAAOC,YAAU;AAGjB,IAAM,gBAAgB;AACtB,IAAM,iBAAiB,KAAK,OAAO;AAE5B,IAAM,cAAN,MAAkB;AAAA,EACd;AAAA,EACQ;AAAA;AAAA,EAET,YAA2B,QAAQ,QAAQ;AAAA,EAEnD,YAAY,KAAa;AACvB,SAAK,MAAM;AACX,SAAK,WAAWA,OAAK,KAAK,KAAK,aAAa;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAiB,IAAkC;AAE/D,UAAM,UAAU,KAAK;AACrB,QAAI,cAA0B,MAAM;AAAA,IAAC;AACrC,SAAK,YAAY,IAAI,QAAQ,CAAC,MAAM;AAClC,oBAAc;AAAA,IAChB,CAAC;AAED,QAAI;AAEF,YAAM;AACN,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AAEA,kBAAY;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,OAAqC;AAChD,WAAO,KAAK,cAAc,YAAY;AACpC,YAAM,KAAK,cAAc;AACzB,YAAM,OAAO,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA;AACrC,YAAMH,YAAW,KAAK,UAAU,MAAM,OAAO;AAAA,IAC/C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,MAA6B,SAAiB,QAAiC;AACvF,UAAM,KAAK,OAAO;AAAA,MAChB,IAAID,YAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,GAAqC;AAC9C,QAAI;AACJ,QAAI;AACF,gBAAU,MAAME,UAAS,KAAK,UAAU,OAAO;AAAA,IACjD,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,8CAA8C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAChG;AACA,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,UAAM,YAAY,MAAM,MAAM,CAAC,CAAC;AAEhC,UAAM,UAA2B,CAAC;AAClC,eAAW,QAAQ,WAAW;AAC5B,UAAI;AACF,gBAAQ,KAAK,KAAK,MAAM,IAAI,CAAkB;AAAA,MAChD,SAAS,KAAK;AAEZ,gBAAQ;AAAA,UACN,0CAA0C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC5F;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,gBAA+B;AAC3C,QAAI;AACF,YAAM,QAAQ,MAAMC,MAAK,KAAK,QAAQ;AACtC,UAAI,MAAM,OAAO,gBAAgB;AAC/B,cAAM,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,SAAS,GAAG;AAC/D,cAAM,cAAcC,OAAK,KAAK,KAAK,KAAK,YAAY,SAAS,QAAQ;AACrE,cAAM,OAAO,KAAK,UAAU,WAAW;AAAA,MACzC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AC/GA,SAAS,aAAa;AAIf,IAAM,gBAAN,MAAyC;AAAA,EACtC;AAAA,EAER,mBAA8C;AAC5C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,eAAe,QAA6B;AAC1C,QAAI,OAAO,aAAa,UAAU;AAChC,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,OAAO,MAAM,SAA2D;AACtE,UAAM,WAAW,QAAQ,MAAM,IAAI,CAAC,OAAO;AAAA,MACzC,MAAM,EAAE;AAAA,MACR,aAAa,EAAE;AAAA,MACf,cAAc,EAAE;AAAA,IAClB,EAAE;AAKF,UAAM,eAAe;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,SAAS;AAAA,QACP,OAAO;AAAA,QACP,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,QAChD,GAAI,KAAK,gBAAgB,EAAE,QAAQ,KAAK,cAAc,UAAU,IAAI,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,qBAAiB,WAAW,MAAM,YAAqB,GAAG;AACxD,UAAI,cAAc,OAAO,GAAG;AAC1B,aAAK,gBAAgB,EAAE,UAAU,UAAU,WAAW,QAAQ,WAAW;AACzE;AAAA,MACF;AAEA,UAAI,iBAAiB,OAAO,GAAG;AAC7B,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,UAAU,QAAQ;AAAA,UAClB,WAAW,QAAQ;AAAA,QACrB;AACA;AAAA,MACF;AAEA,UAAI,mBAAmB,OAAO,GAAG;AAC/B,mBAAW,SAAS,QAAQ,SAAS,WAAW,CAAC,GAAG;AAClD,cAAI,MAAM,SAAS,UAAU,MAAM,SAAS,QAAW;AACrD,kBAAM,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK;AAAA,UACzC;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,gBAAgB,OAAO,GAAG;AAC5B,cAAM,EAAE,MAAM,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;;;AC9CO,SAAS,kBAAkB,MAAmC;AACnE,QAAM,UAAU,KAAK,KAAK;AAE1B,QAAM,cAAc,iCAAiC,KAAK,OAAO;AACjE,MAAI,aAAa;AACf,UAAM,eAAe,YAAY,CAAC;AAClC,UAAM,UAAU,YAAY,CAAC;AAC7B,QAAI,CAAC,gBAAgB,CAAC,QAAS,QAAO;AACtC,WAAO,EAAE,MAAM,UAAU,cAAc,QAAQ;AAAA,EACjD;AAEA,QAAM,eAAe,kCAAkC,KAAK,OAAO;AACnE,MAAI,cAAc;AAChB,UAAM,eAAe,aAAa,CAAC;AACnC,UAAM,SAAS,aAAa,CAAC;AAC7B,QAAI,CAAC,gBAAgB,CAAC,OAAQ,QAAO;AACrC,WAAO,EAAE,MAAM,WAAW,cAAc,OAAO;AAAA,EACjD;AAEA,QAAM,YAAY,wBAAwB,KAAK,OAAO;AACtD,MAAI,WAAW;AACb,UAAM,eAAe,UAAU,CAAC;AAChC,QAAI,CAAC,aAAc,QAAO;AAC1B,WAAO,EAAE,MAAM,QAAQ,aAAa;AAAA,EACtC;AAEA,SAAO;AACT;AAMO,SAAS,uBAAuB,MAAwC;AAC7E,QAAM,UAAU,KAAK,KAAK;AAC1B,MAAI,CAAC,QAAQ,WAAW,cAAc,EAAG,QAAO;AAEhD,QAAM,WAAW,QAAQ,MAAM,eAAe,MAAM,EAAE,KAAK;AAE3D,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,QAAQ;AAElC,QAAI,OAAO,OAAO,cAAc,YAAY,CAAC,OAAO,WAAW;AAC7D,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,MAAM,QAAQ,OAAO,kBAAkB,KAAK,OAAO,mBAAmB,WAAW,GAAG;AACvF,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,OAAO,mBAAmB,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ;AAE3F,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO;AAAA,IACT;AAEA,UAAM,SAA4B;AAAA,MAChC,WAAW,OAAO;AAAA,MAClB,oBAAoB;AAAA,IACtB;AAEA,QAAI,OAAO,OAAO,eAAe,UAAU;AACzC,aAAO,aAAa,OAAO;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACzFA,SAA4B,YAAY;AACxC,SAAS,cAAAC,mBAAkB;AAoB3B,IAAM,YAAY;AAMlB,eAAsB,qBAAqB,SAAuD;AAChG,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACV,IAAI;AAGJ,MAAI,QAAQ,WAAW;AACrB,UAAM,IAAI,MAAM,2BAA2B,KAAK,MAAM,SAAS,EAAE;AAAA,EACnE;AAEA,QAAM,eAAeA,YAAW;AAChC,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAGnC,QAAM,eAAe,KAAK,YAAY,CAAC,GAAG;AAAA,IACxC,OAAO,CAAC,QAAQ,QAAQ,QAAQ,KAAK;AAAA,IACrC,KAAK;AAAA,MACH,GAAG,QAAQ;AAAA,MACX,yBAAyB;AAAA,MACzB,qBAAqB;AAAA,MACrB,oBAAoB,KAAK,UAAU,kBAAkB;AAAA,MACrD,uBAAuB;AAAA,MACvB,wBAAwB,YAAY,SAAS,KAAK;AAAA,MAClD,iBAAiB,OAAO,KAAK;AAAA,IAC/B;AAAA,EACF,CAAC;AAGD,QAAM,SAAsB;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,EACV;AAGA,QAAM,eAAe,MAAM;AACzB,QAAI,aAAa,WAAW;AAC1B,mBAAa,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,IACpC;AAAA,EACF;AAGA,eAAa,GAAG,WAAW,CAAC,QAAiB;AAE3C,QAAI,uBAAuB,GAAG,GAAG;AAC/B,eAAS,cAAc,GAAG;AAAA,IAC5B;AAAA,EACF,CAAC;AAED,eAAa,GAAG,QAAQ,CAAC,SAAS;AAEhC,UAAM,gBAAgB,SAAS,IAAI,YAAY;AAC/C,QAAI,iBAAiB,cAAc,WAAW,WAAW;AACvD,eAAS,cAAc;AAAA,QACrB,MAAM;AAAA,QACN;AAAA,QACA,OAAO,4BAA4B,IAAI;AAAA,MACzC,CAAC;AAAA,IACH;AACA,aAAS,OAAO,YAAY;AAAA,EAC9B,CAAC;AAGD,WAAS,SAAS,QAAQ,cAAc,YAAY;AAEpD,SAAO,EAAE,cAAc,aAAa;AACtC;AAKA,SAAS,uBAAuB,KAA2C;AACzE,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO;AACpD,QAAM,MAAM;AACZ,SACE,OAAO,IAAI,SAAS,YACpB,OAAO,IAAI,iBAAiB,YAC5B,CAAC,YAAY,YAAY,WAAW,UAAU,SAAS,EAAE,SAAS,IAAI,IAAI;AAE9E;;;ACrHA,SAAS,SAAAC,QAAO,YAAAC,WAAU,aAAAC,kBAAiB;AAC3C,OAAOC,YAAU;AAOjB,eAAsB,kBAAkB,UAAkB,SAAuC;AAC/F,QAAMH,OAAMG,OAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,QAAMD,WAAU,UAAU,KAAK,UAAU,SAAS,MAAM,CAAC,GAAG,OAAO;AACrE;AAMA,eAAsB,iBAAiB,UAA0C;AAC/E,MAAI;AACF,UAAM,MAAM,MAAMD,UAAS,UAAU,OAAO;AAC5C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,SAAS,KAAK;AAEZ,YAAQ,MAAM,uCAAuC,GAAG;AACxD,WAAO,CAAC;AAAA,EACV;AACF;;;AC1BA,SAAS,cAAAG,oBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,SAAAC,QAAO,MAAM,YAAAC,YAAU,UAAAC,SAAQ,MAAAC,KAAI,aAAAC,kBAAiB;AAC7D,SAAS,WAAAC,gBAAe;AACxB,OAAOC,YAAU;;;ACWV,IAAM,gBAAN,MAAoB;AAAA,EACR,UAAU,oBAAI,IAAyB;AAAA,EACvC,YAAY,oBAAI,IAA0B;AAAA,EAC1C,gBAAgB,oBAAI,IAAwB;AAAA,EAC5C,cAAc,oBAAI,IAA2C;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAA+B;AACzC,SAAK,YAAY,QAAQ;AACzB,SAAK,iBAAiB,QAAQ,kBAAkB,KAAK,KAAK;AAC1D,SAAK,mBAAmB,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,QAAqB,cAA2B,cAAmC;AAC1F,SAAK,QAAQ,IAAI,OAAO,cAAc,EAAE,GAAG,OAAO,CAAC;AACnD,QAAI,aAAc,MAAK,cAAc,IAAI,OAAO,cAAc,YAAY;AAC1E,QAAI,aAAc,MAAK,UAAU,IAAI,OAAO,cAAc,YAAY;AACtE,SAAK,gBAAgB,OAAO,YAAY;AACxC,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,IAAI,cAA+C;AACjD,WAAO,KAAK,QAAQ,IAAI,YAAY;AAAA,EACtC;AAAA,EAEA,OAAsB;AACpB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,cAAsB,SAAqC;AAC9D,UAAM,OAAO,KAAK,UAAU,IAAI,YAAY;AAC5C,QAAI,MAAM,WAAW;AACnB,WAAK,KAAK,OAAO;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,SAAqC;AACjD,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ,YAAY;AACpD,QAAI,CAAC,OAAQ;AAEb,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK,YAAY;AACf,eAAO,WAAW,QAAQ;AAC1B,eAAO,kBAAiB,oBAAI,KAAK,GAAE,YAAY;AAC/C,aAAK,gBAAgB,QAAQ,YAAY;AACzC,YAAI,OAAO,eAAe,UAAa,OAAO,WAAW,OAAO,YAAY;AAC1E,eAAK,UAAU,QAAQ,YAAY;AACnC;AAAA,QACF;AACA;AAAA,MACF;AAAA,MACA,KAAK,WAAW;AACd,eAAO,YAAY,QAAQ;AAC3B;AAAA,MACF;AAAA,MACA,KAAK,YAAY;AACf,eAAO,SAAS;AAChB,aAAK,gBAAgB,QAAQ,YAAY;AACzC;AAAA,MACF;AAAA,MACA,KAAK,WAAW;AACd,eAAO,SAAS;AAChB,aAAK,gBAAgB,QAAQ,YAAY;AACzC;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,eAAO,SAAS;AAChB,aAAK,gBAAgB,QAAQ,YAAY;AACzC;AAAA,MACF;AAAA,IACF;AAEA,SAAK,gBAAgB;AACrB,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,cAA4B;AACjC,SAAK,QAAQ,OAAO,YAAY;AAChC,SAAK,UAAU,OAAO,YAAY;AAClC,SAAK,cAAc,OAAO,YAAY;AACtC,SAAK,gBAAgB,YAAY;AACjC,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,eAAW,gBAAgB,KAAK,QAAQ,KAAK,GAAG;AAC9C,WAAK,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AACxC,WAAK,gBAAgB,YAAY;AAAA,IACnC;AAAA,EACF;AAAA,EAEQ,UAAU,cAA4B;AAC5C,UAAM,SAAS,KAAK,QAAQ,IAAI,YAAY;AAC5C,QAAI,QAAQ;AACV,aAAO,SAAS;AAAA,IAClB;AACA,SAAK,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AACxC,SAAK,gBAAgB,YAAY;AACjC,UAAM,SAAS,KAAK,cAAc,IAAI,YAAY;AAClD,QAAI,OAAQ,QAAO;AACnB,SAAK,gBAAgB;AACrB,SAAK,UAAU;AAAA,MACb,MAAM;AAAA,MACN;AAAA,MACA,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,iBAAkB;AAC5B,UAAM,UAAU,KAAK,KAAK;AAE1B,sBAAkB,KAAK,kBAAkB,OAAO,EAAE,MAAM,CAAC,QAAQ;AAE/D,cAAQ;AAAA,QACN,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC7F;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB,cAA4B;AAClD,SAAK,gBAAgB,YAAY;AACjC,UAAM,QAAQ,WAAW,MAAM;AAC7B,YAAM,SAAS,KAAK,QAAQ,IAAI,YAAY;AAC5C,UAAI,QAAQ,WAAW,WAAW;AAChC,eAAO,SAAS;AAChB,aAAK,gBAAgB;AACrB,aAAK,UAAU;AAAA,UACb,MAAM;AAAA,UACN;AAAA,UACA,OAAO,mCAAmC,KAAK,cAAc;AAAA,QAC/D,CAAC;AAAA,MACH;AAAA,IACF,GAAG,KAAK,cAAc;AACtB,SAAK,YAAY,IAAI,cAAc,KAAK;AAAA,EAC1C;AAAA,EAEQ,gBAAgB,cAA4B;AAClD,UAAM,QAAQ,KAAK,YAAY,IAAI,YAAY;AAC/C,QAAI,OAAO;AACT,mBAAa,KAAK;AAClB,WAAK,YAAY,OAAO,YAAY;AAAA,IACtC;AAAA,EACF;AACF;;;ACjLA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,cAAAC,aAAY,YAAAC,WAAU,UAAAC,SAAQ,QAAAC,OAAM,aAAAC,kBAAiB;AAC9D,OAAOC,YAAU;AACjB,SAAS,KAAAC,UAAS;AAQX,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YACkB,UACA,eACA,cAChB;AACA;AAAA,MACE,uCAAuC,QAAQ,MAAM,gBAAgB,OAAO,MAAM,QAAQ,CAAC,CAAC,SAAS,eAAe,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC7I;AANgB;AACA;AACA;AAKhB,SAAK,OAAO;AAAA,EACd;AACF;AAIO,IAAM,uBAAuBC,GAAE,OAAO;AAAA,EAC3C,KAAKA,GAAE,OAAO;AAAA,EACd,OAAOA,GAAE,OAAO;AAAA,EAChB,aAAaA,GAAE,OAAO,EAAE,SAAS;AACnC,CAAC;AAEM,IAAM,iBAAiBA,GAAE,OAAO;AAAA,EACrC,IAAIA,GAAE,OAAO;AAAA,EACb,UAAUA,GAAE,OAAO;AAAA,EACnB,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,SAASA,GAAE,MAAM,oBAAoB,EAAE,SAAS;AAAA,EAChD,MAAMA,GAAE,OAAO,EAAE,QAAQ,SAAS;AAAA,EAClC,QAAQA,GAAE,OAAO;AAAA,EACjB,UAAUA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACrD,WAAWA,GAAE,OAAO,OAAO;AAAA,EAC3B,WAAWA,GAAE,OAAO,OAAO,EAAE,SAAS;AAAA,EACtC,eAAeA,GAAE,OAAO,EAAE,SAAS;AAAA,EACnC,YAAYA,GAAE,OAAO,OAAO,EAAE,SAAS;AAAA,EACvC,QAAQA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,WAAWA,GAAE,OAAO,OAAO,EAAE,SAAS;AACxC,CAAC;AAOM,IAAM,kBAAkBA,GAAE,OAAO;AAAA,EACtC,QAAQA,GAAE,QAAQ,WAAW;AAAA,EAC7B,IAAIA,GAAE,OAAO;AAAA,EACb,WAAWA,GAAE,OAAO,OAAO;AAAA,EAC3B,QAAQA,GAAE,KAAK,CAAC,WAAW,WAAW,QAAQ,CAAC;AACjD,CAAC;AA8BM,IAAM,gBAAN,MAAoB;AAAA,EACR;AAAA,EACA;AAAA,EACA,WAAW,oBAAI,IAAY;AAAA;AAAA,EAEpC,YAA2B,QAAQ,QAAQ;AAAA;AAAA,EAElC,mBAA2B,KAAK,OAAO;AAAA,EAExD,YAAY,UAAkB;AAC5B,SAAK,WAAW;AAChB,SAAK,MAAMC,OAAK,QAAQ,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAiB,IAAkC;AAE/D,UAAM,UAAU,KAAK;AACrB,QAAI,cAA0B,MAAM;AAAA,IAAC;AACrC,SAAK,YAAY,IAAI,QAAQ,CAAC,MAAM;AAClC,oBAAc;AAAA,IAChB,CAAC;AAED,QAAI;AAEF,YAAM;AACN,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AAEA,kBAAY;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,OAAuC;AAClD,UAAM,UAAU,KAAK,KAAK,KAAK,QAAQ;AAEvC,UAAM,KAAK,OAAOC,YAAW,EAAE,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAC7D,UAAM,WAAqB;AAAA,MACzB,GAAG;AAAA,MACH;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAEA,UAAM,KAAK,cAAc,YAAY;AACnC,YAAMC,YAAW,KAAK,UAAU,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,GAAM,OAAO;AAAA,IAC1E,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,IAAY,QAA+B;AACtD,UAAM,KAAK,cAAc,YAAY;AACnC,YAAM,YAAY,MAAM,KAAK,QAAQ;AACrC,YAAM,WAAW,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAElD,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AAAA,MAC7C;AAEA,UAAI,SAAS,WAAW,QAAW;AACjC,cAAM,IAAI,MAAM,8BAA8B,EAAE,EAAE;AAAA,MACpD;AAEA,eAAS,SAAS;AAClB,eAAS,cAAa,oBAAI,KAAK,GAAE,YAAY;AAE7C,YAAM,KAAK,SAAS,SAAS;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAA+B;AACnC,UAAM,YAAY,MAAM,KAAK,QAAQ;AACrC,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,WAAO,UAAU,OAAO,CAAC,MAAM;AAC7B,UAAI,EAAE,WAAW,OAAW,QAAO;AACnC,UAAI,EAAE,cAAc,OAAW,QAAO;AACtC,UAAI,EAAE,aAAa,EAAE,YAAY,IAAK,QAAO;AAC7C,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAS,OAAqC;AAClD,UAAM,YAAY,MAAM,KAAK,QAAQ;AAErC,WAAO,UAAU,OAAO,CAAC,MAAM;AAC7B,UAAI,EAAE,WAAW,OAAW,QAAO;AACnC,UAAI,SAAS,EAAE,cAAc,EAAE,aAAa,MAAO,QAAO;AAC1D,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,IAAsC;AAC9C,UAAM,YAAY,MAAM,KAAK,QAAQ;AACrC,WAAO,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,IAA8B;AAC7C,UAAM,WAAW,MAAM,KAAK,IAAI,EAAE;AAClC,WAAO,UAAU,WAAW;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAA8B;AAClC,WAAO,KAAK,cAAc,YAAY;AACpC,YAAM,YAAY,MAAM,KAAK,QAAQ;AACrC,YAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,YAAM,UAAsB,CAAC;AAE7B,iBAAW,YAAY,WAAW;AAChC,YACE,SAAS,WAAW,UACpB,SAAS,cAAc,UACvB,SAAS,aACT,SAAS,YAAY,KACrB;AACA,cAAI,SAAS,kBAAkB,QAAW;AACxC,qBAAS,SAAS,SAAS;AAC3B,qBAAS,aAAa;AAAA,UACxB,OAAO;AACL,qBAAS,YAAY;AAAA,UACvB;AACA,kBAAQ,KAAK,QAAQ;AAAA,QACvB;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,GAAG;AACtB,cAAM,KAAK,SAAS,SAAS;AAAA,MAC/B;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAc,UAA+B;AAC3C,QAAI;AACJ,QAAI;AAEF,YAAM,QAAQ,MAAMC,MAAK,KAAK,QAAQ;AACtC,UAAI,MAAM,OAAO,KAAK,kBAAkB;AACtC,cAAM,IAAI,sBAAsB,KAAK,UAAU,MAAM,MAAM,KAAK,gBAAgB;AAAA,MAClF;AAEA,gBAAU,MAAMC,UAAS,KAAK,UAAU,OAAO;AAAA,IACjD,SAAS,OAAO;AACd,UAAK,MAAgC,SAAS,UAAU;AACtD,eAAO,CAAC;AAAA,MACV;AACA,YAAM;AAAA,IACR;AAEA,UAAM,YAAwB,CAAC;AAC/B,eAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,UAAI,CAAC,KAAK,KAAK,EAAG;AAClB,UAAI;AACF,cAAM,SAAS,eAAe,MAAM,KAAK,MAAM,IAAI,CAAC;AACpD,kBAAU,KAAK,MAAM;AAAA,MACvB,SAAS,OAAO;AAEd,gBAAQ;AAAA,UACN,kDAAkD,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,QAC5G;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,SAAS,WAAsC;AAC3D,UAAM,UAAU,KAAK,KAAK,KAAK,QAAQ;AACvC,UAAM,UAAU,GAAG,UAAU,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AAGrE,UAAM,WAAW,GAAG,KAAK,QAAQ,IAAI,QAAQ,GAAG;AAChD,UAAMC,WAAU,UAAU,SAAS,OAAO;AAC1C,UAAMC,QAAO,UAAU,KAAK,QAAQ;AAAA,EACtC;AACF;;;AC1SA,SAAyB,SAAAC,cAAa;AACtC,SAAS,YAAAC,WAAU,aAAAC,kBAAiB;AAkC7B,IAAM,aAAN,MAAiB;AAAA,EACL,QAAuB,CAAC;AAAA;AAAA,EAExB,UAAU,oBAAI,IAAkB;AAAA,EAChC,aAAa;AAAA,EACb;AAAA,EACT,uBAAuB;AAAA,EACvB,gBAAgB;AAAA,EAChB,WAAwB,CAAC;AAAA,EACzB,cAAc,oBAAI,IAAoB;AAAA;AAAA,EAGtC,SAA8B;AAAA;AAAA,EAGrB,aAAa,oBAAI,IAA2B;AAAA,EAE7D,YAAY,SAA4B;AACtC,SAAK,kBAAkB,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAiB,UAAkB,IAAkC;AACjF,UAAM,UAAU,KAAK,WAAW,IAAI,QAAQ,KAAK,QAAQ,QAAQ;AACjE,QAAI,cAA0B,MAAM;AAAA,IAAC;AACrC,UAAM,UAAU,IAAI,QAAc,CAAC,MAAM;AACvC,oBAAc;AAAA,IAChB,CAAC;AACD,SAAK,WAAW,IAAI,UAAU,OAAO;AAErC,QAAI;AACF,YAAM;AACN,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AACA,kBAAY;AACZ,UAAI,KAAK,WAAW,IAAI,QAAQ,MAAM,SAAS;AAC7C,aAAK,WAAW,OAAO,QAAQ;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAA6B;AAEhC,UAAM,KAAK,KAAK,WAAW,KAAK;AAChC,QAAI,MAAM,KAAK,QAAQ,IAAI,EAAE,EAAG,QAAO;AAGvC,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAI,QAAQ,KAAK,eAAe;AAC9B,WAAK,gBAAgB;AACrB,WAAK,uBAAuB;AAAA,IAC9B;AACA,QAAI,KAAK,wBAAwB,KAAK,gBAAiB,QAAO;AAC9D,SAAK;AAGL,QAAI,IAAI;AACN,WAAK,QAAQ,IAAI,IAAI,IAAI;AACzB,UAAI,KAAK,QAAQ,OAAO,KAAK,YAAY;AACvC,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF;AAEA,SAAK,MAAM,KAAK,KAAK;AACrB,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,oBAA0B;AAChC,UAAM,WAAW,KAAK,QAAQ,KAAK,EAAE,KAAK,EAAE;AAC5C,QAAI,aAAa,QAAW;AAC1B,WAAK,QAAQ,OAAO,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAuB;AACrB,UAAM,SAAS,CAAC,GAAG,KAAK,KAAK;AAC7B,SAAK,MAAM,SAAS;AACpB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAqC;AACnC,UAAM,YAAY,KAAK,MAAM;AAE7B,UAAM,aAAa,oBAAI,IAA4B;AACnD,UAAM,WAA0B,CAAC;AACjC,UAAM,iBAAgC,CAAC;AAEvC,eAAW,SAAS,WAAW;AAC7B,UAAI,MAAM,SAAS,WAAW;AAC5B,YAAI,CAAC,MAAM,KAAK,KAAM;AACtB,cAAM,MAAM,MAAM,KAAK,KAAK,KAAK,EAAE,YAAY;AAC/C,cAAM,WAAW,WAAW,IAAI,GAAG;AACnC,YAAI,UAAU;AACZ,mBAAS;AAAA,QACX,OAAO;AACL,qBAAW,IAAI,KAAK,EAAE,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM,KAAK,MAAM,OAAO,EAAE,CAAC;AAAA,QAChF;AAAA,MACF,WAAW,MAAM,SAAS,WAAW;AACnC,iBAAS,KAAK,KAAK;AAAA,MACrB,OAAO;AACL,uBAAe,KAAK,KAAK;AAAA,MAC3B;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP,UAAU,CAAC,GAAG,WAAW,OAAO,CAAC;AAAA,QACjC;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAe;AACb,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAc,WAAmB,YAAmC;AAExE,eAAW,KAAK,CAAC,WAAW,UAAU,GAAG;AACvC,UAAI;AACF,cAAMA,WAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC;AAAA,MACtC,SAAS,KAAK;AAIZ,gBAAQ,MAAM,sCAAsC,CAAC,KAAK,GAAG;AAAA,MAC/D;AAAA,IACF;AACA,SAAK,eAAe,WAAW,SAAS;AACxC,SAAK,eAAe,YAAY,SAAS;AAAA,EAC3C;AAAA,EAEA,eAAqB;AACnB,eAAW,KAAK,KAAK,SAAU,GAAE,MAAM;AACvC,SAAK,WAAW,CAAC;AACjB,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,WAAmB,YAAmC;AAC5E,UAAM,KAAK,WAAW,WAAW,SAAS;AAC1C,UAAM,KAAK,WAAW,YAAY,SAAS;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,WAAkC;AAC7C,QAAI,KAAK,MAAM,SAAS,EAAG,QAAO,QAAQ,QAAQ;AAClD,WAAO,IAAI,QAAc,CAACC,aAAY;AACpC,YAAM,QAAQ,WAAW,MAAM;AAC7B,aAAK,SAAS;AACd,QAAAA,SAAQ;AAAA,MACV,GAAG,SAAS;AAEZ,WAAK,SAAS,MAAM;AAClB,qBAAa,KAAK;AAClB,aAAK,SAAS;AACd,QAAAA,SAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,YAAkB;AAChB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEQ,WAAW,OAAwC;AACzD,QAAI,MAAM,SAAS,UAAW,QAAO,MAAM,KAAK;AAChD,QAAI,MAAM,SAAS,UAAW,QAAO,MAAM,KAAK;AAChD,QAAI,MAAM,SAAS,eAAgB,QAAO,OAAO,MAAM,KAAK;AAC5D,WAAO;AAAA,EACT;AAAA,EAEQ,eAAe,UAAkB,MAAmC;AAC1E,QAAI;AACF,YAAM,UAAUH,OAAM,UAAU,MAAM;AAEpC,aAAK,aAAa,UAAU,IAAI,EAAE,MAAM,CAAC,QAAQ;AAE/C,kBAAQ,MAAM,uCAAuC,QAAQ,KAAK,GAAG;AAAA,QACvE,CAAC;AAAA,MACH,CAAC;AAGD,cAAQ,GAAG,SAAS,CAAC,QAAQ;AAE3B,gBAAQ,MAAM,2BAA2B,QAAQ,kBAAkB,GAAG;AACtE,aAAK,eAAe,OAAO;AAAA,MAC7B,CAAC;AAED,WAAK,SAAS,KAAK,OAAO;AAAA,IAC5B,SAAS,KAAK;AAGZ,cAAQ,MAAM,8BAA8B,QAAQ,KAAK,GAAG;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,SAA0B;AAC/C,QAAI;AACF,cAAQ,MAAM;AAAA,IAChB,SAAS,KAAK;AAGZ,cAAQ,MAAM,gCAAgC,GAAG;AAAA,IACnD;AACA,UAAM,QAAQ,KAAK,SAAS,QAAQ,OAAO;AAC3C,QAAI,UAAU,IAAI;AAChB,WAAK,SAAS,OAAO,OAAO,CAAC;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,UAAkB,MAA4C;AACvF,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMC,UAAS,UAAU,OAAO;AAAA,IAC5C,SAAS,MAAM;AAGb;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,YAAY,IAAI,QAAQ,KAAK;AACjD,QAAI,QAAQ,UAAU,OAAQ;AAE9B,UAAM,aAAa,QAAQ,MAAM,MAAM;AACvC,SAAK,YAAY,IAAI,UAAU,QAAQ,MAAM;AAE7C,UAAM,QAAQ,WAAW,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAC1D,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,YAAI,OAAO,YAAa;AAExB,YAAI,SAAS,WAAW;AACtB,eAAK,KAAK,EAAE,MAAM,WAAW,MAAM,OAA0C,CAAC;AAAA,QAChF,OAAO;AACL,eAAK,KAAK,EAAE,MAAM,WAAW,MAAM,OAAkC,CAAC;AAAA,QACxE;AAAA,MACF,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,UAAkB,MAA4C;AACrF,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMA,UAAS,UAAU,OAAO;AAAA,IAC5C,SAAS,MAAM;AAGb;AAAA,IACF;AAGA,SAAK,YAAY,IAAI,UAAU,QAAQ,MAAM;AAE7C,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,UAAM,cAAwB,CAAC;AAC/B,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,YAAI,OAAO,YAAa;AAExB,YAAI,SAAS,WAAW;AACtB,eAAK,KAAK,EAAE,MAAM,WAAW,MAAM,OAA0C,CAAC;AAAA,QAChF,OAAO;AACL,eAAK,KAAK,EAAE,MAAM,WAAW,MAAM,OAAkC,CAAC;AAAA,QACxE;AACA,oBAAY,KAAK,IAAI;AAAA,MACvB,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,WAAmB,YAAoB,QAAsC;AAC/F,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,SAAS,WAAW;AAC5B,cAAM,KAAK,WAAW,YAAY,MAAM,KAAK,YAAY,GAAG;AAAA,MAC9D,WAAW,MAAM,SAAS,WAAW;AACnC,cAAM,KAAK,WAAW,WAAW,MAAM,KAAK,WAAW,GAAG;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,WACZ,UACA,gBACA,aACe;AACf,WAAO,KAAK,cAAc,UAAU,YAAY;AAC9C,UAAI;AACF,cAAM,UAAU,MAAMA,UAAS,UAAU,OAAO;AAChD,cAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,YAAI,UAAU;AAEd,cAAM,UAAU,MAAM,IAAI,CAAC,SAAS;AAClC,cAAI,CAAC,KAAK,KAAK,EAAG,QAAO;AACzB,cAAI;AACF,kBAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,iBACG,OAAO,eAAe,kBAAkB,OAAO,cAAc,mBAC9D,CAAC,OAAO,aACR;AACA,qBAAO,cAAc;AACrB,wBAAU;AACV,qBAAO,KAAK,UAAU,MAAM;AAAA,YAC9B;AAAA,UACF,SAAS,MAAM;AAAA,UAEf;AACA,iBAAO;AAAA,QACT,CAAC;AAED,YAAI,SAAS;AACX,gBAAMC,WAAU,UAAU,QAAQ,KAAK,IAAI,GAAG,OAAO;AACrD,eAAK,YAAY,IAAI,UAAU,QAAQ,KAAK,IAAI,EAAE,MAAM;AAAA,QAC1D;AAAA,MACF,SAAS,KAAK;AAIZ,gBAAQ,MAAM,4CAA4C,QAAQ,KAAK,GAAG;AAAA,MAC5E;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AClZA,SAAS,cAAAE,mBAAkB;AAC3B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,WAAAC,UAAS,YAAAC,YAAU,aAAAC,kBAAiB;AAC7C,SAAS,WAAAC,gBAAe;AACxB,OAAOC,YAAU;;;ACJjB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,cAAAC,aAAY,aAAAC,kBAAiB;AACtC,SAAS,iBAAAC,sBAAqB;AAC9B,OAAOC,YAAU;AACjB,SAAS,KAAAC,UAAS;AAElB,IAAMC,cAAaH,eAAc,YAAY,GAAG;AAIzC,IAAM,mBAAmBE,GAAE,KAAK,CAAC,WAAW,eAAe,QAAQ,WAAW,WAAW,CAAC;AAI1F,IAAM,qBAAqBA,GAAE,KAAK,CAAC,YAAY,QAAQ,UAAU,KAAK,CAAC;AAIvE,IAAM,kBAAkBA,GAAE,OAAO;AAAA,EACtC,IAAIA,GAAE,OAAO;AAAA,EACb,OAAOA,GAAE,OAAO;AAAA,EAChB,OAAOA,GAAE,OAAO;AAAA,EAChB,QAAQ;AAAA,EACR,UAAU,mBAAmB,SAAS;AAAA,EACtC,YAAYA,GAAE,OAAO,EAAE,SAAS;AAAA,EAChC,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,SAASA,GAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAC7B,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,WAAWA,GAAE,OAAO;AAAA,EACpB,WAAWA,GAAE,OAAO;AACtB,CAAC;AAuBM,IAAM,YAAN,MAAgB;AAAA,EACb;AAAA,EAER,YAAY,QAAgB;AAC1B,UAAM,MAAMD,OAAK,QAAQ,MAAM;AAC/B,QAAI,CAACH,YAAW,GAAG,GAAG;AACpB,MAAAC,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAEA,UAAM,WAAWI,YAAW,gBAAgB;AAC5C,SAAK,KAAK,IAAI,SAAS,MAAM;AAC7B,SAAK,GAAG,OAAO,oBAAoB;AACnC,SAAK,GAAG,OAAO,mBAAmB;AAElC,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAIQ,aAAmB;AACzB,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAkBZ;AAGD,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAA4B;AAClC,QAAI;AAEF,YAAM,cAAc,KAAK,GACtB,QAAQ,uEAAuE,EAC/E,IAAI;AACP,UAAI,CAAC,YAAa;AAGlB,YAAM,YAAY,KAAK,GACpB,QAAQ,4DAA4D,EACpE,IAAI;AACP,UAAI,UAAU,UAAU,EAAG;AAG3B,WAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAkBZ;AAAA,IACH,SAAS,KAAK;AAGZ,cAAQ,MAAM,oDAAoD,GAAG;AAAA,IACvE;AAAA,EACF;AAAA;AAAA,EAIA,WAAW,OAAgC;AACzC,UAAM,KAAK,OAAON,YAAW,EAAE,MAAM,GAAG,EAAE,CAAC;AAC3C,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,SAAK,GACF;AAAA,MACC;AAAA;AAAA,IAEF,EACC;AAAA,MACC;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM,YAAY;AAAA,MAClB,MAAM,cAAc;AAAA,MACpB,MAAM,aAAa;AAAA,MACnB,MAAM,WAAW;AAAA,MACjB,MAAM,SAAS;AAAA,MACf;AAAA,MACA;AAAA,IACF;AAEF,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,IAAmC;AACzC,UAAM,MAAM,KAAK,GAAG,QAAQ,kCAAkC,EAAE,IAAI,EAAE;AAGtE,WAAO,MAAMO,YAAW,GAAG,IAAI;AAAA,EACjC;AAAA,EAEA,aAAa,IAAY,QAAoB,OAAsB;AACjE,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAI,UAAU,QAAW;AACvB,WAAK,GACF,QAAQ,sEAAsE,EAC9E,IAAI,QAAQ,OAAO,KAAK,EAAE;AAAA,IAC/B,OAAO;AACL,WAAK,GACF,QAAQ,0DAA0D,EAClE,IAAI,QAAQ,KAAK,EAAE;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,SAASC,SAAmB,CAAC,GAAgB;AAC3C,UAAM,aAAuB,CAAC;AAC9B,UAAM,SAAoB,CAAC;AAE3B,QAAIA,OAAM,YAAY;AACpB,iBAAW,KAAK,gBAAgB;AAChC,aAAO,KAAKA,OAAM,UAAU;AAAA,IAC9B;AAEA,QAAIA,OAAM,UAAUA,OAAM,OAAO,SAAS,GAAG;AAC3C,YAAM,eAAeA,OAAM,OAAO,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG;AACzD,iBAAW,KAAK,cAAc,YAAY,GAAG;AAC7C,aAAO,KAAK,GAAGA,OAAM,MAAM;AAAA,IAC7B;AAEA,QAAIA,OAAM,OAAO;AACf,iBAAW,KAAK,WAAW;AAC3B,aAAO,KAAKA,OAAM,KAAK;AAAA,IACzB;AAEA,UAAM,QAAQ,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,OAAO,CAAC,KAAK;AAC5E,UAAM,OAAO,KAAK,GACf,QAAQ,uBAAuB,KAAK,2BAA2B,EAC/D,IAAI,GAAG,MAAM;AAEhB,WAAO,KAAK,IAAID,WAAU;AAAA,EAC5B;AAAA,EAEA,WAAW,IAAkB;AAC3B,SAAK,GAAG,QAAQ,gCAAgC,EAAE,IAAI,EAAE;AAAA,EAC1D;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;AAkBA,SAASA,YAAW,KAA4B;AAC9C,SAAO;AAAA,IACL,IAAI,IAAI;AAAA,IACR,OAAO,IAAI;AAAA,IACX,OAAO,IAAI;AAAA,IACX,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,YAAY,IAAI,cAAc;AAAA,IAC9B,WAAW,IAAI,cAAc;AAAA,IAC7B,SAAS,IAAI,WAAW;AAAA,IACxB,OAAO,IAAI,UAAU;AAAA,IACrB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EACjB;AACF;;;ACjQA,SAAS,cAAAE,mBAAkB;AAC3B,SAAS,cAAAC,aAAY,aAAAC,kBAAiB;AACtC,SAAS,cAAAC,aAAY,YAAAC,YAAU,UAAAC,SAAQ,aAAAC,kBAAiB;AACxD,OAAOC,YAAU;AACjB,SAAS,KAAAC,UAAS;AAIX,IAAM,yBAAyBA,GAAE,KAAK,CAAC,QAAQ,WAAW,UAAU,CAAC;AAIrE,IAAM,kBAAkBA,GAAE,OAAO;AAAA,EACtC,IAAIA,GAAE,OAAO;AAAA,EACb,SAAS;AAAA,EACT,QAAQA,GAAE,OAAO;AAAA,EACjB,aAAaA,GAAE,OAAO,EAAE,SAAS;AAAA,EACjC,UAAUA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAC9B,SAASA,GAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,WAAWA,GAAE,OAAO,OAAO;AAAA,EAC3B,WAAWA,GAAE,OAAO,OAAO,EAAE,SAAS;AAAA,EACtC,iBAAiBA,GAAE,OAAO,OAAO,EAAE,SAAS;AAC9C,CAAC;AA0BM,SAAS,uBAAuB,OAAmC;AACxE,QAAM,UAAU,MAAM,KAAK,EAAE,YAAY;AAGzC,MAAI,CAAC,WAAW,YAAY,kBAAkB,YAAY,WAAW;AACnE,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,oBAAI,KAAK;AAGrB,QAAM,iBAAiB,QAAQ,MAAM,gBAAgB;AACrD,MAAI,gBAAgB;AAClB,UAAM,QAAQ,OAAO,eAAe,CAAC,CAAC;AACtC,UAAM,OAAO,eAAe,CAAC;AAC7B,QAAI,KAAK;AACT,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,aAAK,QAAQ,KAAK,KAAK;AACvB;AAAA,MACF,KAAK;AACH,aAAK,QAAQ,KAAK;AAClB;AAAA,MACF,KAAK;AACH,aAAK,QAAQ,KAAK,KAAK,KAAK;AAC5B;AAAA,IACJ;AACA,WAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,EAAE,EAAE,YAAY;AAAA,EAClD;AAGA,QAAM,WAAW,QAAQ,MAAM,4CAA4C;AAC3E,MAAI,UAAU;AACZ,UAAM,QAAQ,OAAO,SAAS,CAAC,CAAC;AAChC,UAAM,OAAO,SAAS,CAAC;AACvB,QAAI,KAAK;AACT,YAAQ,MAAM;AAAA,MACZ,KAAK;AAAA,MACL,KAAK;AACH,aAAK,QAAQ,KAAK,KAAK;AACvB;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,aAAK,QAAQ,KAAK;AAClB;AAAA,MACF,KAAK;AACH,aAAK,QAAQ,KAAK,KAAK,KAAK;AAC5B;AAAA,IACJ;AACA,WAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,EAAE,EAAE,YAAY;AAAA,EAClD;AAGA,MAAI,YAAY,kBAAkB;AAChC,UAAM,WAAW,IAAI,KAAK,GAAG;AAC7B,aAAS,SAAS,IAAI,IAAI,IAAI,GAAG;AACjC,WAAO,SAAS,YAAY;AAAA,EAC9B;AAGA,QAAM,iBAAiB,QAAQ,MAAM,6BAA6B;AAClE,MAAI,gBAAgB;AAClB,UAAM,QAAQ,OAAO,eAAe,CAAC,CAAC;AACtC,UAAM,UAAU,OAAO,eAAe,CAAC,CAAC;AACxC,UAAM,SAAS,IAAI,KAAK,GAAG;AAC3B,WAAO,SAAS,OAAO,SAAS,GAAG,CAAC;AAGpC,QAAI,OAAO,QAAQ,KAAK,IAAI,QAAQ,GAAG;AACrC,aAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAAA,IACrC;AAEA,WAAO,OAAO,YAAY;AAAA,EAC5B;AAGA,SAAO;AACT;AASO,IAAM,iBAAN,MAAqB;AAAA,EACT;AAAA;AAAA,EAET,YAA2B,QAAQ,QAAQ;AAAA,EAEnD,YAAY,UAAkB;AAC5B,SAAK,WAAW;AAChB,UAAM,MAAMD,OAAK,QAAQ,QAAQ;AACjC,QAAI,CAACN,YAAW,GAAG,GAAG;AACpB,MAAAC,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAiB,IAAkC;AAE/D,UAAM,UAAU,KAAK;AACrB,QAAI,cAA0B,MAAM;AAAA,IAAC;AACrC,SAAK,YAAY,IAAI,QAAQ,CAAC,MAAM;AAClC,oBAAc;AAAA,IAChB,CAAC;AAED,QAAI;AAEF,YAAM;AACN,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AAEA,kBAAY;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,OAA8C;AACzD,UAAM,KAAK,OAAOF,YAAW,EAAE,MAAM,GAAG,EAAE,CAAC;AAC3C,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,UAAM,YAAuB;AAAA,MAC3B;AAAA,MACA,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,aAAa,MAAM;AAAA,MACnB,UAAU,MAAM,YAAY;AAAA,MAC5B,SAAS;AAAA,MACT,WAAW;AAAA,MACX,WAAW,MAAM;AAAA,IACnB;AAEA,UAAM,KAAK,cAAc,YAAY;AACnC,YAAM,KAAK,OAAO,SAAS;AAAA,IAC7B,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAM,IAAI,IAA4C;AACpD,UAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,WAAO,IAAI,IAAI,EAAE;AAAA,EACnB;AAAA,EAEA,MAAM,OAA6B;AACjC,UAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,WAAO,MAAM,KAAK,IAAI,OAAO,CAAC,EAAE;AAAA,MAC9B,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,IAC5E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,SAAkD;AAC7D,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,MAAM,MAAM,KAAK,QAAQ;AAE/B,WAAO,MAAM,KAAK,IAAI,OAAO,CAAC,EAC3B,OAAO,CAAC,MAAM;AACb,UAAI,CAAC,EAAE,QAAS,QAAO;AACvB,UAAI,EAAE,aAAa,EAAE,YAAY,IAAK,QAAO;AAC7C,UAAI,WAAW,EAAE,YAAY,QAAS,QAAO;AAC7C,aAAO;AAAA,IACT,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EAC3C;AAAA;AAAA,EAIA,MAAM,OAAO,IAAY,SAAiC;AACxD,UAAM,KAAK,cAAc,YAAY;AACnC,YAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,YAAM,YAAY,IAAI,IAAI,EAAE;AAC5B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,wBAAwB,EAAE,EAAE;AAAA,MAC9C;AAEA,gBAAU,UAAU;AACpB,UAAI,IAAI,IAAI,SAAS;AACrB,YAAM,KAAK,SAAS,GAAG;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,IAA2B;AAC7C,UAAM,KAAK,cAAc,YAAY;AACnC,YAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,YAAM,YAAY,IAAI,IAAI,EAAE;AAC5B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,wBAAwB,EAAE,EAAE;AAAA,MAC9C;AAEA,gBAAU,mBAAkB,oBAAI,KAAK,GAAE,YAAY;AACnD,UAAI,IAAI,IAAI,SAAS;AACrB,YAAM,KAAK,SAAS,GAAG;AAAA,IACzB,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,OAAO,IAA2B;AACtC,UAAM,KAAK,cAAc,YAAY;AACnC,YAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,UAAI,CAAC,IAAI,IAAI,EAAE,GAAG;AAChB,cAAM,IAAI,MAAM,wBAAwB,EAAE,EAAE;AAAA,MAC9C;AAEA,UAAI,OAAO,EAAE;AACb,YAAM,KAAK,SAAS,GAAG;AAAA,IACzB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAA+B;AACnC,WAAO,KAAK,cAAc,YAAY;AACpC,YAAM,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI,EAAE,YAAY;AACtE,YAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,YAAM,UAAoB,CAAC;AAE3B,iBAAW,CAAC,IAAI,SAAS,KAAK,KAAK;AACjC,YAAI,UAAU,aAAa,UAAU,YAAY,QAAQ;AACvD,cAAI,OAAO,EAAE;AACb,kBAAQ,KAAK,EAAE;AAAA,QACjB;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,GAAG;AACtB,cAAM,KAAK,SAAS,GAAG;AAAA,MACzB;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,MAAc,UAA2C;AACvD,UAAM,MAAM,oBAAI,IAAuB;AAEvC,QAAI,CAACC,YAAW,KAAK,QAAQ,GAAG;AAC9B,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,UAAU,MAAMG,WAAS,KAAK,UAAU,OAAO;AACrD,YAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAEvD,iBAAW,QAAQ,OAAO;AACxB,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,gBAAM,YAAY,gBAAgB,MAAM,GAAG;AAC3C,cAAI,IAAI,UAAU,IAAI,SAAS;AAAA,QACjC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,SAAS,KAA4C;AACjE,UAAM,QAAQ,MAAM,KAAK,IAAI,OAAO,CAAC,EAClC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,EAC5B,KAAK,IAAI;AACZ,UAAM,UAAU,QAAQ,GAAG,KAAK;AAAA,IAAO;AAGvC,UAAM,WAAW,GAAG,KAAK,QAAQ,IAAI,QAAQ,GAAG;AAChD,UAAME,WAAU,UAAU,SAAS,OAAO;AAC1C,UAAMD,QAAO,UAAU,KAAK,QAAQ;AAAA,EACtC;AAAA,EAEA,MAAc,OAAO,WAAqC;AACxD,UAAM,OAAO,GAAG,KAAK,UAAU,SAAS,CAAC;AAAA;AACzC,UAAMF,YAAW,KAAK,UAAU,MAAM,OAAO;AAAA,EAC/C;AACF;;;ACvVA,SAAS,cAAAM,mBAAkB;AAC3B,OAAOC,YAAU;AAQV,SAAS,qBAAqB,WAAsB,SAAyB;AAClF,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,IAET,KAAK;AACH,aAAO;AAAA,IAET;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,cAAc,QAA2B;AACvD,QAAM,QAAQ,OAAO,YAAY;AAEjC,MAAI,MAAM,SAAS,SAAS,KAAK,MAAM,SAAS,WAAW,GAAG;AAC5D,WAAO;AAAA,EACT;AAEA,MACE,MAAM,SAAS,UAAU,KACzB,MAAM,SAAS,aAAa,KAC5B,MAAM,SAAS,kBAAkB,GACjC;AACA,WAAO;AAAA,EACT;AACA,MACE,MAAM,SAAS,QAAQ,KACvB,MAAM,SAAS,eAAe,KAC9B,MAAM,SAAS,iBAAiB,GAChC;AACA,WAAO;AAAA,EACT;AACA,MAAI,MAAM,SAAS,OAAO,KAAK,MAAM,SAAS,QAAQ,KAAK,MAAM,SAAS,WAAW,GAAG;AACtF,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMA,eAAsB,mBACpB,eACA,QACe;AACf,QAAM,QAAuB;AAAA,IAC3B,GAAG;AAAA,IACH,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AAEA,QAAM,YAAYA,OAAK,KAAK,eAAe,aAAa;AAExD,MAAI;AACF,UAAMD,YAAW,WAAW,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM,OAAO;AAAA,EACnE,SAAS,OAAO;AAEd,YAAQ;AAAA,MACN,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAC7F;AAAA,EACF;AACF;AAKO,SAAS,oBAAoB,MAMC;AACnC,QAAM,YAAY,cAAc,KAAK,MAAM;AAC3C,QAAM,kBAAkB,qBAAqB,WAAW,KAAK,MAAM;AAEnE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,KAAK;AAAA,IACZ,MAAM,KAAK;AAAA,IACX,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AAAA,IAChC,cAAc,KAAK;AAAA,IACnB,eAAe;AAAA,IACf;AAAA,IACA,SAAS,KAAK;AAAA,EAChB;AACF;;;AC5CO,IAAM,yBAAN,MAA6B;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YACE,aACA,QACA,cACA,gBACA;AACA,SAAK,cAAc;AACnB,SAAK,SAAS;AACd,SAAK,eAAe;AACpB,SAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,qBAAqB,SAAsC;AAC/D,UAAM,WAAW,KAAK,eAAe,QAAQ,KAAK;AAGlD,UAAM,KAAK,KAAK;AAAA,MACd,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,OAAO,SAAS,MAAM,GAAG,GAAI;AAAA;AAAA,MAC7B,qBAAqB,QAAQ;AAAA,IAC/B,CAAC;AAGD,UAAM,KAAK,IAAI,SAAS,qBAAqB,QAAQ,IAAI;AAAA,MACvD,aAAa,QAAQ;AAAA,MACrB,QAAQ,QAAQ;AAAA,MAChB,qBAAqB,QAAQ;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,uBAAuB,qBAAmD;AACxE,QAAI,sBAAsB,KAAK,OAAO,wBAAwB;AAC5D,aAAO,EAAE,eAAe,OAAO,WAAW,EAAE;AAAA,IAC9C;AAEA,UAAM,WAAW,sBAAsB,KAAK,OAAO;AACnD,UAAM,YAAY,KAAK,IAAI,KAAK,OAAO,gBAAgB,KAAK,UAAU,KAAK,OAAO,YAAY;AAE9F,WAAO,EAAE,eAAe,MAAM,UAAU;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,qBAA6B,WAAkC;AACrF,UAAM,KAAK;AAAA,MACT;AAAA,MACA,gCAAgC,KAAK,MAAM,YAAY,GAAI,CAAC,WAAW,mBAAmB;AAAA,IAC5F;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBAAkB,QAAgB,OAAsB;AACtD,UAAM,WAAW,KAAK,eAAe,KAAK;AAG1C,YAAQ,MAAM,yBAAyB,MAAM,KAAK,QAAQ,EAAE;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,uBACJ,QACA,OACA,QACe;AACf,UAAM,WAAW,KAAK,eAAe,KAAK;AAC1C,UAAM,KAAK,IAAI,SAAS,GAAG,MAAM,YAAY,QAAQ,IAAI,MAAM;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,KAAK,OAA6C;AAC9D,QAAI,CAAC,KAAK,eAAgB;AAE1B,QAAI;AACF,YAAM,KAAK,eAAe,KAAK;AAAA,IACjC,QAAQ;AAGN,cAAQ,MAAM,2CAA2C,MAAM,IAAI,EAAE;AAAA,IACvE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,IACZ,OACA,SACA,QACe;AACf,QAAI;AACF,YAAM,KAAK,YAAY,IAAI,OAAO,SAAS,MAAM;AAAA,IACnD,QAAQ;AAGN,cAAQ,MAAM,8BAA8B,OAAO,EAAE;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,OAAwB;AAC7C,QAAI,iBAAiB,MAAO,QAAO,MAAM;AACzC,QAAI,OAAO,UAAU,SAAU,QAAO;AACtC,WAAO,OAAO,KAAK;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,cAAc,QAAgB,OAA+B;AAC3D,UAAM,WAAW,KAAK,eAAe,KAAK;AAG1C,QAAI,WAAW,SAAS,WAAW,gBAAgB;AACjD,aAAO;AAAA,IACT;AAGA,QACE,WAAW,eACX,WAAW,iBACX,WAAW,oBACX,WAAW,kBACX,WAAW,qBACX;AACA,aAAO;AAAA,IACT;AAGA,QAAI,SAAS,SAAS,QAAQ,KAAK,SAAS,SAAS,QAAQ,GAAG;AAC9D,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT;AACF;;;ACnPA,SAAS,KAAAE,UAAS;AAIX,IAAM,2BAA2BA,GAAE,OAAO;AAAA,EAC/C,aAAaA,GAAE,OAAO;AAAA,EACtB,mBAAmBA,GAAE,OAAO;AAC9B,CAAC;AAEM,IAAM,oBAAoBA,GAAE,OAAO;AAAA,EACxC,YAAYA,GAAE,OAAO;AAAA,EACrB,YAAYA,GAAE,OAAO;AAAA,EACrB,yBAAyBA,GAAE,QAAQ;AAAA,EACnC,qBAAqBA,GAAE,QAAQ;AAAA,EAC/B,0BAA0BA,GAAE,OAAO;AAAA,EACnC,eAAeA,GAAE,OAAO;AAAA,EACxB,qBAAqBA,GAAE,OAAO;AAChC,CAAC;AAEM,IAAM,mBAAmBA,GAAE,OAAO;AAAA,EACvC,YAAYA,GAAE,QAAQ;AAAA,EACtB,QAAQA,GAAE,OAAO;AACnB,CAAC;AAcM,IAAM,eAAN,MAAmB;AAAA,EACP;AAAA,EAEjB,YAAY,QAA4B;AACtC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,SAAkC;AAE3C,QAAI,QAAQ,aAAa,GAAG;AAC1B,aAAO,EAAE,YAAY,OAAO,QAAQ,iBAAiB;AAAA,IACvD;AAGA,QAAI,QAAQ,yBAAyB;AACnC,aAAO,EAAE,YAAY,OAAO,QAAQ,wBAAwB;AAAA,IAC9D;AAGA,QAAI,QAAQ,qBAAqB;AAC/B,aAAO,EAAE,YAAY,OAAO,QAAQ,oBAAoB;AAAA,IAC1D;AAGA,QAAI,QAAQ,aAAa,GAAG;AAC1B,UAAI,QAAQ,uBAAuB,KAAK,OAAO,mBAAmB;AAChE,eAAO,EAAE,YAAY,OAAO,QAAQ,sCAAsC;AAAA,MAC5E;AACA,aAAO,EAAE,YAAY,MAAM,QAAQ,gCAAgC;AAAA,IACrE;AAGA,QAAI,QAAQ,iBAAiB,KAAK,OAAO,aAAa;AACpD,aAAO,EAAE,YAAY,OAAO,QAAQ,+BAA+B;AAAA,IACrE;AAEA,WAAO,EAAE,YAAY,MAAM,QAAQ,yBAAyB;AAAA,EAC9D;AACF;;;AC9EA,SAAS,cAAAC,aAAY,YAAAC,YAAU,UAAAC,SAAQ,QAAAC,OAAM,aAAAC,kBAAiB;AAC9D,OAAOC,YAAU;AAGjB,IAAM,kBAAkB;AACxB,IAAM,iBAAiB,OAAO;AAC9B,IAAM,oBAAoB,KAAK,KAAK,KAAK;AAOzC,IAAM,aAAa,oBAAI,IAA2B;AAMlD,eAAe,cAAiB,KAAa,IAAkC;AAE7E,QAAM,UAAU,WAAW,IAAI,GAAG,KAAK,QAAQ,QAAQ;AACvD,MAAI,cAA0B,MAAM;AAAA,EAAC;AACrC,QAAM,UAAU,IAAI,QAAc,CAAC,MAAM;AACvC,kBAAc;AAAA,EAChB,CAAC;AACD,aAAW,IAAI,KAAK,OAAO;AAE3B,MAAI;AAEF,UAAM;AACN,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AAEA,gBAAY;AAEZ,QAAI,WAAW,IAAI,GAAG,MAAM,SAAS;AACnC,iBAAW,OAAO,GAAG;AAAA,IACvB;AAAA,EACF;AACF;AAeA,SAAS,WAAW,KAAqB;AACvC,SAAOC,OAAK,KAAK,KAAK,eAAe;AACvC;AAEA,SAAS,WAAW,SAAmC;AACrD,QAAM,UAA4B,CAAC;AACnC,QAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,aAAW,QAAQ,OAAO;AACxB,QAAI;AACF,cAAQ,KAAK,KAAK,MAAM,IAAI,CAAmB;AAAA,IACjD,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,yCAAyC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,eAAsB,cAAc,KAAwC;AAC1E,MAAI;AACF,UAAM,UAAU,MAAMC,WAAS,WAAW,GAAG,GAAG,OAAO;AACvD,WAAO,WAAW,OAAO;AAAA,EAC3B,SAAS,KAAK;AAEZ,YAAQ;AAAA,MACN,uCAAuC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACzF;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAaA,eAAsB,mBAAmB,KAAwC;AAC/E,QAAM,UAAU,MAAM,cAAc,GAAG;AACvC,SAAO,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,cAAc;AAChD;AAOA,eAAsB,iBAAiB,KAAa,KAA8B;AAChF,SAAO,cAAc,KAAK,YAAY;AACpC,UAAM,WAAW,WAAW,GAAG;AAC/B,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMC,WAAS,UAAU,OAAO;AAAA,IAC5C,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,kDAAkD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACpG;AACA;AAAA,IACF;AAEA,UAAM,QAAQ,IAAI,IAAI,GAAG;AACzB,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,UAAM,UAAoB,CAAC;AAE3B,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,YAAI,MAAM,IAAI,MAAM,EAAE,KAAK,CAAC,MAAM,gBAAgB;AAChD,gBAAM,iBAAiB;AAAA,QACzB;AACA,gBAAQ,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,MACpC,SAAS,KAAK;AAEZ,gBAAQ;AAAA,UACN,gEAAgE,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAClH;AACA,gBAAQ,KAAK,IAAI;AAAA,MACnB;AAAA,IACF;AAGA,UAAM,WAAW,GAAG,QAAQ,IAAI,QAAQ,GAAG;AAC3C,UAAMC,WAAU,UAAU,GAAG,QAAQ,KAAK,IAAI,CAAC;AAAA,GAAM,OAAO;AAC5D,UAAMC,QAAO,UAAU,QAAQ;AAAA,EACjC,CAAC;AACH;AAMA,eAAsB,iBAAiB,KAA4B;AACjE,SAAO,cAAc,KAAK,YAAY;AACpC,UAAM,WAAW,WAAW,GAAG;AAC/B,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMF,WAAS,UAAU,OAAO;AAAA,IAC5C,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,+CAA+C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACjG;AACA;AAAA,IACF;AAEA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,UAAM,OAAiB,CAAC;AAExB,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,YAAI,MAAM,gBAAgB;AACxB,gBAAM,mBAAmB,IAAI,KAAK,MAAM,cAAc,EAAE,QAAQ;AAChE,cAAI,MAAM,mBAAmB,mBAAmB;AAC9C;AAAA,UACF;AAAA,QACF;AACA,aAAK,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,MACjC,SAAS,KAAK;AAEZ,gBAAQ;AAAA,UACN,2DAA2D,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC7G;AAAA,MACF;AAAA,IACF;AAGA,QAAI,SAAS,GAAG,KAAK,KAAK,IAAI,CAAC;AAAA;AAC/B,WAAO,OAAO,WAAW,QAAQ,OAAO,IAAI,kBAAkB,KAAK,SAAS,GAAG;AAC7E,WAAK,MAAM;AACX,eAAS,GAAG,KAAK,KAAK,IAAI,CAAC;AAAA;AAAA,IAC7B;AAGA,UAAM,WAAW,GAAG,QAAQ,IAAI,QAAQ,GAAG;AAC3C,UAAMC,WAAU,UAAU,QAAQ,OAAO;AACzC,UAAMC,QAAO,UAAU,QAAQ;AAAA,EACjC,CAAC;AACH;AAqEA,eAAsB,gBAAgB,KAAa,OAAsC;AACvF,SAAO,cAAc,KAAK,YAAY;AACpC,QAAI;AAEF,YAAMC,YAAW,WAAW,GAAG,GAAG,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM,OAAO;AAAA,IACzE,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC1F;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACjPA,IAAM,OAAO;AAAA;AAAA;AAMb,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyB7B,IAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqD/B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CxB,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBxB,SAAS,uBAA+B;AACtC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDT;AAEA,SAAS,2BAAmC;AAC1C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWT;AAUA,SAAS,iBAAiB,gBAAwB,OAAwB;AACxE,QAAM,SAAS,QAAQ,KAAK,KAAK,MAAM;AACvC,SAAO;AAAA,EAAW,IAAI;AAAA,aAAgB,cAAc,GAAG,MAAM;AAAA;AAC/D;AAKA,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyEtB,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASzB,SAAS,mBAAmB,gBAAgC;AAC1D,SAAO,kBAAkB,IAAI,gBAAgB;AAC/C;AAEA,SAAS,sBAAsB,gBAAgC;AAC7D,SAAO;AAAA,EAAgB,mBAAmB,cAAc,CAAC;AAAA;AAC3D;AAMA,SAAS,kBAAkB,UAAiC;AAC1D,QAAM,eAAe,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO;AAE9D,MAAI,aAAa,SAAS,GAAG;AAC3B,UAAM,QAAQ,aAAa,IAAI,CAAC,MAAM,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI;AACjE,WAAO;AAAA,EAAY,KAAK;AAAA;AAAA,EAC1B;AAEA,SAAO;AACT;AASA,SAAS,6BAA6B,WAA2C;AAC/E,MAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,WAAW;AACzB,UAAM,SAAS,EAAE,YAAY,cAAc,EAAE,SAAS,MAAM;AAC5D,UAAM,cAAc,EAAE,gBAAgB,cAAc,EAAE,aAAa,MAAM;AACzE,UAAM,KAAK,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,EAAE;AAEhE,QAAI,EAAE,WAAW,EAAE,QAAQ,SAAS,GAAG;AACrC,iBAAW,OAAO,EAAE,SAAS;AAC3B,cAAM,OAAO,IAAI,cAAc,WAAM,IAAI,WAAW,KAAK;AACzD,cAAM,KAAK,gBAAW,IAAI,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE;AAAA,MACxD;AAAA,IACF;AAEA,QAAI,EAAE,SAAS;AACb,YAAM,KAAK,gBAAgB,EAAE,OAAO,EAAE;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUpB,SAAO,sBAAsB,UAAU,MAAM;AAAA,EAC7C,MAAM,KAAK,IAAI,CAAC;AAAA;AAAA,EAEhB,WAAW;AACb;AAMA,SAAS,8BAA8B,WAA2C;AAChF,MAAI,CAAC,aAAa,UAAU,WAAW,GAAG;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,UAAU,IAAI,CAAC,MAAM;AACjC,UAAM,aAAa,EAAE,SAAS,QAAQ,EAAE,MAAM,MAAM;AACpD,WAAO,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,cAAS,EAAE,MAAM,KAAK,UAAU;AAAA,EAClE,CAAC;AAED,SAAO,qBAAqB,UAAU,MAAM;AAAA,EAAO,MAAM,KAAK,IAAI,CAAC;AACrE;AAOA,SAAS,iBAAiB,MAA6B;AACrD,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,kBAAkB,KAAK,QAAQ,CAAC;AAG3C,QAAM,YAAY,sBAAsB,KAAK,KAAK;AAClD,MAAI,WAAW;AACb,UAAM,KAAK,SAAS;AAAA,EACtB;AAEA,MAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,UAAM,KAAK;AAAA,EAAiB,KAAK,WAAW,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EAC/E;AAEA,QAAM,gBAAgB,0BAA0B,KAAK,aAAa;AAClE,MAAI,eAAe;AACjB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAGA,QAAM,mBAAmB,6BAA6B,KAAK,gBAAgB;AAC3E,MAAI,kBAAkB;AACpB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,QAAM,oBAAoB,8BAA8B,KAAK,iBAAiB;AAC9E,MAAI,mBAAmB;AACrB,UAAM,KAAK,iBAAiB;AAAA,EAC9B;AAGA,QAAM,aAAa,uBAAuB,KAAK,gBAAgB;AAC/D,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,KAAK,sBAAsB,KAAK,QAAQ,CAAC;AAG/C,QAAM,KAAK,GAAG,yBAAyB,IAAI,CAAC;AAG5C,QAAM,KAAK;AAAA,EAAY,mBAAmB,KAAK,OAAO,CAAC,EAAE;AAEzD,SAAO;AAAA,EAAc,MAAM,KAAK,MAAM,CAAC;AAAA;AACzC;AAMA,SAAS,uBAAuB,MAA6B;AAC3D,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,kBAAkB,KAAK,QAAQ,CAAC;AAC3C,QAAM,KAAK,sBAAsB,KAAK,QAAQ,CAAC;AAE/C,QAAM,YAAY,sBAAsB,KAAK,KAAK;AAClD,MAAI,WAAW;AACb,UAAM,KAAK,SAAS;AAAA,EACtB;AAEA,QAAM,KAAK,GAAG,yBAAyB,IAAI,CAAC;AAE5C,SAAO;AAAA,EAAc,MAAM,KAAK,MAAM,CAAC;AAAA;AACzC;AAMA,SAAS,sBACP,MACA,SACU;AACV,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,oBAAoB;AAC/B,QAAM,KAAK,sBAAsB;AACjC,QAAM,KAAK,eAAe;AAC1B,QAAM,KAAK,eAAe;AAC1B,QAAM,KAAK,qBAAqB,CAAC;AAEjC,MAAI,QAAQ,iBAAiB;AAC3B,UAAM,KAAK,yBAAyB,CAAC;AAAA,EACvC;AAEA,MAAI,KAAK,oBAAoB;AAC3B,UAAM,KAAK;AAAA,EAA4B,KAAK,kBAAkB,EAAE;AAAA,EAClE;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAyB;AACjD,SAAO;AAAA,EAAmB,MAAM,KAAK,MAAM,CAAC;AAAA;AAC9C;AAIA,SAAS,yBAAyB,MAA+B;AAC/D,QAAM,QAAkB,CAAC;AAEzB,MAAI,KAAK,MAAM,SAAS,GAAG;AACzB,UAAM,WAAW,KAAK,MAAM,IAAI,CAAC,MAAM,KAAK,EAAE,IAAI,aAAa,EAAE,aAAa,GAAG,EAAE,KAAK,IAAI;AAC5F,UAAM,KAAK;AAAA,EAAkB,QAAQ,EAAE;AAAA,EACzC;AAEA,MAAI,KAAK,eAAe,SAAS,GAAG;AAClC,UAAM,UAAU,KAAK,eAAe,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI;AAClE,UAAM,KAAK;AAAA,EAAwB,OAAO,EAAE;AAAA,EAC9C;AAEA,QAAM;AAAA,IACJ,YAAY,KAAK,aAAa,SAAS,QAAQ,CAAC,CAAC,OAAO,KAAK,aAAa,OAAO,QAAQ,CAAC,CAAC,KAAK,KAAK,aAAa,aAAa,QAAQ,CAAC,CAAC;AAAA,EAC3I;AAEA,SAAO;AACT;AAMA,SAAS,sBAAsB,UAAiC;AAC9D,QAAM,mBAAmB,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AACtE,QAAM,iBAAiB,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,SAAS;AAElE,QAAM,cAAc,iBAAiB,OAAO,CAAC,MAAM,EAAE,YAAY,UAAU,CAAC,EAAE,OAAO;AACrF,QAAM,mBAAmB,iBAAiB,OAAO,CAAC,MAAM,EAAE,YAAY,WAAW;AAEjF,QAAM,QAAkB,CAAC;AAGzB,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,UAAU,oBAAI,IAA2B;AAC/C,eAAW,KAAK,aAAa;AAC3B,YAAM,QAAQ,EAAE,UAAU,WAAW,WAAY,EAAE,MAAM,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE;AAC/E,YAAM,QAAQ,QAAQ,IAAI,KAAK,KAAK,CAAC;AACrC,YAAM,KAAK,CAAC;AACZ,cAAQ,IAAI,OAAO,KAAK;AAAA,IAC1B;AAEA,UAAM,gBAA0B,CAAC;AACjC,eAAW,CAAC,OAAO,OAAO,KAAK,SAAS;AACtC,YAAM,eAAe,KAAK;AAAA,QACxB,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAC;AAAA,MACzE;AACA,YAAM,UAAU,KAAK,MAAM,eAAe,KAAU;AACpD,YAAM,YAAY,WAAW,IAAI,mBAAmB,OAAO,WAAW;AACtE,YAAM,QAAQ,QACX,IAAI,CAAC,MAAM;AACV,cAAM,aAAa,EAAE,eAAe,IAAI,KAAK;AAC7C,eAAO,OAAO,EAAE,OAAO,GAAG,UAAU;AAAA,MACtC,CAAC,EACA,KAAK,IAAI;AACZ,oBAAc,KAAK,MAAM,KAAK,IAAI,SAAS,KAAK,QAAQ,MAAM;AAAA,EAAM,KAAK,EAAE;AAAA,IAC7E;AACA,UAAM,KAAK;AAAA,EAAiB,cAAc,KAAK,IAAI,CAAC,EAAE;AAAA,EACxD;AAGA,MAAI,iBAAiB,SAAS,GAAG;AAC/B,UAAM,QAAQ,iBAAiB,IAAI,CAAC,MAAM,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI;AACrE,UAAM,KAAK;AAAA,EAAgB,KAAK,EAAE;AAAA,EACpC;AAGA,MAAI,eAAe,SAAS,GAAG;AAC7B,UAAM,QAAQ,eACX,IAAI,CAAC,MAAM,MAAM,EAAE,YAAY,SAAS,KAAK,EAAE,OAAO,EAAE,EACxD,KAAK,IAAI;AACZ,UAAM,KAAK;AAAA,EAA6B,KAAK,EAAE;AAAA,EACjD;AAEA,SAAO,MAAM,KAAK,MAAM;AAC1B;AAIA,IAAM,gBAAgB,oBAAI,IAAI,CAAC,QAAQ,WAAW,CAAC;AACnD,IAAM,YAAY;AAOX,SAAS,sBAAsB,OAA4B;AAChE,QAAM,cAAc,MAAM,OAAO,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE,MAAM,CAAC;AACpE,QAAM,YAAY,MAAM,OAAO,CAAC,MAAM,cAAc,IAAI,EAAE,MAAM,CAAC,EAAE;AAEnE,MAAI,YAAY,WAAW,GAAG;AAC5B,QAAI,YAAY,GAAG;AACjB,aAAO,4BAA4B,SAAS;AAAA,IAC9C;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,uBAAuB,WAAW;AACjD,QAAM,QAAQ,iBAAiB,MAAM;AAErC,MAAI,YAAY,SAAS,WAAW;AAClC,UAAM,KAAK,aAAa,YAAY,SAAS,SAAS,eAAe;AAAA,EACvE;AAEA,QAAM,SAAS,eAAe,YAAY,MAAM,eAAe,SAAS;AACxE,SAAO,GAAG,MAAM;AAAA,EAAK,MAAM,KAAK,IAAI,CAAC;AACvC;AAEA,SAAS,uBAAuB,OAAiC;AAC/D,QAAM,gBAAgB,oBAAI,IAAyB;AACnD,QAAM,eAA4B,CAAC;AAEnC,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,YAAY;AACnB,YAAM,QAAQ,cAAc,IAAI,KAAK,UAAU,KAAK,CAAC;AACrD,YAAM,KAAK,IAAI;AACf,oBAAc,IAAI,KAAK,YAAY,KAAK;AAAA,IAC1C,OAAO;AACL,mBAAa,KAAK,IAAI;AAAA,IACxB;AAAA,EACF;AAEA,QAAM,SAAsB,CAAC;AAC7B,aAAW,CAAC,YAAY,QAAQ,KAAK,eAAe;AAClD,WAAO,KAAK,EAAE,YAAY,OAAO,SAAS,CAAC;AAAA,EAC7C;AACA,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO,KAAK,EAAE,YAAY,MAAM,OAAO,aAAa,CAAC;AAAA,EACvD;AACA,SAAO;AACT;AAEA,IAAMC,kBAAyC;AAAA,EAC7C,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACP;AAEA,SAAS,WAAW,GAAc,GAAsB;AACtD,QAAM,SAASA,gBAAe,EAAE,YAAY,QAAQ,KAAK;AACzD,QAAM,SAASA,gBAAe,EAAE,YAAY,QAAQ,KAAK;AACzD,SAAO,SAAS;AAClB;AAEA,SAAS,eAAe,OAItB;AACA,QAAM,SAAsB,CAAC;AAC7B,QAAM,UAAuB,CAAC;AAC9B,QAAM,UAAuB,CAAC;AAC9B,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,WAAW,cAAe,QAAO,KAAK,CAAC;AAAA,aACpC,EAAE,WAAW,UAAW,SAAQ,KAAK,CAAC;AAAA,QAC1C,SAAQ,KAAK,CAAC;AAAA,EACrB;AACA,SAAO,EAAE,QAAQ,SAAS,QAAQ;AACpC;AAEA,SAAS,wBAAwB,OAA0B;AACzD,QAAM,EAAE,QAAQ,QAAQ,IAAI,eAAe,MAAM,KAAK;AACtD,QAAM,eAAe,CAAC,GAAG,OAAO,EAAE,KAAK,UAAU,EAAE,CAAC;AACpD,QAAM,MAAM,cAAc,UAAU,OAAO,aAAa,OAAO,KAAK;AACpE,QAAM,YAAY,eACd,WAAW,aAAa,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,aAAa,MAAM,SAAS,KAAK,QAAQ,EAAE,KAAK,aAAa,YAAY,QAAQ,OAC9H;AACJ,SAAO,IAAI,MAAM,UAAU,KAAK,OAAO,MAAM,YAAY,QAAQ,MAAM,WAAW,SAAS,GAAG,GAAG;AACnG;AAEA,SAAS,wBAAwB,OAAkB,OAAiB,UAA0B;AAC5F,QAAM,KAAK,KAAK,wBAAwB,KAAK,CAAC,EAAE;AAEhD,QAAM,EAAE,QAAQ,SAAS,QAAQ,IAAI,eAAe,MAAM,KAAK;AAC/D,QAAM,eAAe,CAAC,GAAG,OAAO,EAAE,KAAK,UAAU,EAAE,CAAC;AAEpD,aAAW,QAAQ,CAAC,GAAG,QAAQ,GAAG,OAAO,GAAG;AAC1C,QAAI,YAAY,UAAW;AAC3B,UAAM,KAAK,OAAO,eAAe,IAAI,CAAC,EAAE;AACxC;AAAA,EACF;AAGA,MAAI,gBAAgB,OAAO,WAAW,KAAK,QAAQ,WAAW,KAAK,WAAW,WAAW;AACvF,UAAM,KAAK,OAAO,eAAe,YAAY,CAAC,EAAE;AAChD;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,gBACP,OACA,YACA,OACA,UACQ;AACR,MAAI,cAAc,MAAM,YAAY;AAClC,UAAM,KAAK,MAAM,MAAM,UAAU,GAAG;AAAA,EACtC;AACA,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,YAAY,UAAW;AAC3B,UAAM,KAAK,KAAK,eAAe,IAAI,CAAC,EAAE;AACtC;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,QAA+B;AACvD,QAAM,QAAkB,CAAC;AACzB,MAAI,WAAW;AAEf,aAAW,SAAS,QAAQ;AAC1B,QAAI,YAAY,UAAW;AAE3B,UAAM,iBAAiB,MAAM,cAAc,MAAM,MAAM,UAAU;AACjE,QAAI,gBAAgB;AAClB,iBAAW,wBAAwB,OAAO,OAAO,QAAQ;AAAA,IAC3D,OAAO;AACL,YAAM,aAAa,MAAM,eAAe,QAAQ,OAAO,SAAS;AAChE,iBAAW,gBAAgB,OAAO,YAAY,OAAO,QAAQ;AAAA,IAC/D;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,MAAyB;AAC/C,QAAM,SAAS,iBAAiB,KAAK,MAAM;AAC3C,QAAM,WAAW,KAAK,WAAW,IAAI,KAAK,QAAQ,OAAO;AACzD,QAAM,QAAQ,KAAK,UAAU,WAAW,KAAK,YAAY,KAAK,KAAK,CAAC,MAAM;AAC1E,QAAM,MAAM,KAAK,QAAQ,SAAS,KAAK,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM;AAC9D,QAAM,MAAM,KAAK,UAAU,WAAW,KAAK,OAAO,KAAK;AACvD,SAAO,GAAG,MAAM,IAAI,QAAQ,GAAG,KAAK,KAAK,GAAG,KAAK,GAAG,GAAG,GAAG,GAAG;AAC/D;AAEA,SAAS,iBAAiB,QAAwB;AAChD,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,YAAY,WAA2B;AAC9C,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,SAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACpC;AAIA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,YAAY,UAAU,YAAY,OAAO,CAAC;AAE7E,SAAS,0BAA0B,SAAkC;AACnE,QAAM,cAAc,QAAQ,OAAO,CAAC,MAAM,kBAAkB,IAAI,EAAE,IAAI,CAAC;AACvE,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,QAAM,QAAQ,YAAY,IAAI,CAAC,MAAM;AACnC,UAAM,MAAM,cAAc,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;AACtE,WAAO,MAAM,EAAE,IAAI,KAAK,EAAE,OAAO,KAAK,GAAG;AAAA,EAC3C,CAAC;AAED,SAAO;AAAA,EAA2C,MAAM,KAAK,IAAI,CAAC;AACpE;AAEA,SAAS,cAAc,IAAoB;AACzC,MAAI,KAAK,IAAQ,QAAO;AACxB,QAAM,UAAU,KAAK,MAAM,KAAK,GAAM;AACtC,MAAI,UAAU,GAAI,QAAO,GAAG,OAAO;AACnC,QAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,MAAI,QAAQ,GAAI,QAAO,GAAG,KAAK,IAAI,UAAU,EAAE;AAC/C,SAAO,GAAG,KAAK,MAAM,QAAQ,EAAE,CAAC;AAClC;AAIA,SAAS,mBAAmB,SAAgC;AAC1D,QAAM,EAAE,UAAU,UAAU,eAAe,IAAI;AAC/C,QAAM,cAAc,SAAS,SAAS,SAAS,SAAS,eAAe;AAEvE,MAAI,gBAAgB,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC;AACzB,aAAW,OAAO,UAAU;AAC1B,UAAM,cAAc,IAAI,QAAQ,IAAI,MAAM,IAAI,KAAK,MAAM;AACzD,UAAM,KAAK,gBAAgB,IAAI,IAAI,GAAG,WAAW,KAAK,IAAI,IAAI,EAAE;AAAA,EAClE;AACA,aAAW,OAAO,UAAU;AAC1B,UAAM,KAAK,YAAY,GAAG,CAAC;AAAA,EAC7B;AACA,aAAW,OAAO,gBAAgB;AAChC,UAAM,KAAK,YAAY,GAAG,CAAC;AAAA,EAC7B;AACA,SAAO,GAAG,WAAW;AAAA,EAAuB,MAAM,KAAK,MAAM,CAAC;AAChE;AAEA,SAAS,YAAY,OAA4B;AAC/C,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,YAAY,MAAM,KAAK,UAAU,SAAS,KAAK,MAAM,KAAK,SAAS,EAAE;AAAA;AAAA,EAAiB,KAAK,UAAU,MAAM,KAAK,WAAW,CAAC,GAAG,MAAM,CAAC,CAAC;AAAA;AAAA,IAChJ,KAAK;AACH,aAAO,gBAAgB,MAAM,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI;AAAA,IAC5D,KAAK;AACH,aAAO,kBAAkB,MAAM,KAAK;AAAA,IACtC,KAAK;AACH,aAAO,mBAAmB,MAAM,SAAS;AAAA,IAC3C,KAAK,oBAAoB;AACvB,YAAM,MAAM,MAAM;AAClB,cAAQ,IAAI,MAAM;AAAA,QAChB,KAAK;AACH,iBAAO,UAAU,IAAI,YAAY,eAAe,IAAI,OAAO;AAAA,QAC7D,KAAK;AACH,iBAAO,UAAU,IAAI,YAAY,eAAe,IAAI,OAAO;AAAA;AAAA,EAAgB,IAAI,SAAS,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,QAC3H,KAAK;AACH,iBAAO,UAAU,IAAI,YAAY,cAAc,IAAI,OAAO,MAAM,IAAI,MAAM;AAAA,YAAe,IAAI,QAAQ;AAAA,QACvG,KAAK;AACH,iBAAO,UAAU,IAAI,YAAY,aAAa,IAAI,KAAK;AAAA,QACzD,KAAK;AACH,iBAAO,UAAU,IAAI,YAAY,sBAAsB,IAAI,SAAS;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AACF;AAIA,SAAS,YAAY,SAAgC;AACnD,SAAO,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAAQ,eAAe;AACpF;AAUA,SAAS,uBAAuB,YAA6C;AAC3E,MAAI,CAAC,cAAc,WAAW,WAAW,GAAG;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,IAAI,CAAC,MAAM;AAClC,UAAM,WAAW,EAAE,WAAW,IAAI,eAAe,EAAE,QAAQ,MAAM;AACjE,UAAM,SAAS,EAAE,YACb,cAAc,IAAI,KAAK,EAAE,SAAS,EAAE,eAAe,CAAC,MACpD;AACJ,UAAM,OAAO,EAAE,cAAc,WAAM,EAAE,WAAW,KAAK;AACrD,WAAO,OAAO,EAAE,MAAM,KAAK,QAAQ,GAAG,MAAM,GAAG,IAAI;AAAA,EACrD,CAAC;AAED,SAAO,sBAAsB,WAAW,MAAM;AAAA,EAC9C,MAAM,KAAK,IAAI,CAAC;AAAA;AAAA;AAGlB;AAKO,SAAS,gBAAgB,MAA8B;AAC5D,QAAM,UAAU,sBAAsB,KAAK,KAAK,MAAM;AACtD,SAAO,YAAY,KAAK,OAAO,MAAM,KAAK,KAAK,WAAW,WAAW,KAAK,CAAC;AAC7E;AAOO,SAAS,gBAAgB,MAA6B;AAC3D,QAAM,aAAa,YAAY,KAAK,aAAa,SAAS,QAAQ,CAAC,CAAC,OAAO,KAAK,aAAa,OAAO,QAAQ,CAAC,CAAC,KAAK,KAAK,aAAa,aAAa,QAAQ,CAAC,CAAC;AAC5J,QAAM,WAAW,KAAK,MAAM,SAAS;AACrC,QAAM,YAAY,KAAK,aAAa,eAAe;AAGnD,QAAM,sBAAsB,KAAK,wBAAwB,KAAK,kBAAkB,UAAU,KAAK;AAG/F,MAAI,CAAC,YAAY,CAAC,WAAW;AAC3B,WAAO,GAAG,iBAAiB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAIjD,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMV;AAEA,QAAM,WAAW,KAAK,MAAM,IAAI,CAAC,MAAM,KAAK,EAAE,IAAI,aAAa,EAAE,aAAa,GAAG,EAAE,KAAK,IAAI;AAG5F,MAAI,qBAAqB;AACvB,UAAM,iBAAiB,6BAA6B,KAAK,gBAAgB;AAGzE,QAAI,KAAK,YAAY;AACnB,aAAO,GAAG,iBAAiB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAInD,UAAU;AAAA;AAAA,EAEV,cAAc;AAAA;AAAA;AAAA,EAGd,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIR,mBAAmB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMrC;AAEA,WAAO,GAAG,iBAAiB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAIjD,UAAU;AAAA;AAAA,EAEV,cAAc;AAAA;AAAA;AAAA,EAGd,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,kDAKmC,OAAO,KAAK,kBAAkB,UAAU,CAAC,CAAC;AAAA;AAAA,EAErF;AAGA,QAAM,oBAAoB,uBAAuB,KAAK,gBAAgB;AACtE,MAAI,mBAAmB;AACrB,WAAO,GAAG,iBAAiB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAIjD,UAAU;AAAA;AAAA,EAEV,iBAAiB;AAAA;AAAA;AAAA,EAGjB,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIR,mBAAmB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvC;AAEA,SAAO,GAAG,iBAAiB,KAAK,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA,EAI/C,UAAU;AAAA;AAAA;AAAA,EAGV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAMV;AAaO,SAAS,oBAAoB,MAA6B;AAC/D,QAAM,mBAAmB,sBAAsB,MAAM,EAAE,iBAAiB,MAAM,CAAC;AAC/E,QAAM,YAAY,YAAY,KAAK,OAAO,IAAI;AAE9C,mBAAiB;AAAA,IACf,YACI,oGACA;AAAA,EACN;AAEA,SAAO;AAAA,IACL,iBAAiB,KAAK,cAAc;AAAA,IACpC,iBAAiB,IAAI;AAAA,IACrB,sBAAsB,KAAK,cAAc;AAAA,IACzC,iBAAiB,gBAAgB;AAAA,EACnC,EAAE,KAAK,MAAM;AACf;AAOO,SAAS,yBAAyB,MAA0C;AAEjF,QAAM,mBAAmB,sBAAsB,MAAM;AAAA,IACnD,iBAAiB,KAAK,kBAAkB;AAAA,EAC1C,CAAC;AAED,mBAAiB;AAAA,IACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYF;AAEA,SAAO;AAAA,IACL,iBAAiB,KAAK,gBAAgB,eAAe;AAAA,IACrD,iBAAiB,IAAI;AAAA,IACrB,sBAAsB,KAAK,cAAc;AAAA,IACzC,iBAAiB,gBAAgB;AAAA,EACnC,EAAE,KAAK,MAAM;AACf;AAOO,SAAS,sBAAsB,MAA0C;AAE9E,QAAM,mBAAmB,sBAAsB,MAAM;AAAA,IACnD,iBAAiB,KAAK,kBAAkB;AAAA,EAC1C,CAAC;AAED,mBAAiB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAgBjB;AAEL,SAAO;AAAA,IACL,iBAAiB,KAAK,gBAAgB,YAAY;AAAA,IAClD,uBAAuB,IAAI;AAAA,IAC3B,sBAAsB,KAAK,cAAc;AAAA,IACzC,iBAAiB,gBAAgB;AAAA,EACnC,EAAE,KAAK,MAAM;AACf;;;AClnCA,SAAS,KAAAC,UAAS;AAWX,IAAM,mBAAmBA,GAAE,KAAK,CAAC,UAAU,SAAS,eAAe,QAAQ,CAAC;AAUnF,IAAM,6BAA6BA,GAAE,OAAO;AAAA,EAC1C,KAAKA,GAAE,OAAO;AAAA,EACd,WAAWA,GAAE,OAAO;AAAA,EACpB,WAAWA,GAAE,OAAO;AAAA,EACpB,gBAAgBA,GAAE,OAAO;AAAA,EACzB,cAAcA,GAAE,OAAO;AAAA,EACvB,cAAcA,GAAE,OAAO;AACzB,CAAC;AAIM,IAAM,8BAA8B,2BAA2B,OAAO;AAAA,EAC3E,MAAMA,GAAE,OAAO;AAAA,EACf,KAAKA,GAAE,OAAO;AAAA,EACd,eAAeA,GAAE,OAAO,EAAE,SAAS;AAAA,EACnC,gBAAgBA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACpC,cAAcA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAClC,cAAcA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAClC,eAAeA,GAAE,OAAO,EAAE,SAAS;AAAA,EACnC,eAAeA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACnC,qBAAqBA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACzC,QAAQA,GAAE,KAAK,CAAC,WAAW,YAAY,SAAS,CAAC,EAAE,QAAQ,SAAS;AAAA,EACpE,4BAA4BA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAChD,yBAAyBA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAC7C,4BAA4BA,GAAE,OAAO,EAAE,SAAS;AAAA,EAChD,YAAY,iBAAiB,SAAS;AACxC,CAAC;AAMM,IAAM,6BAA6BA,GAAE,OAAO;AAAA,EACjD,IAAIA,GAAE,OAAO,EAAE,SAAS;AAAA,EACxB,QAAQA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAASA,GAAE,OAAOA,GAAE,OAAO,GAAGA,GAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACpD,YAAYA,GAAE,OAAO;AAAA,EACrB,aAAaA,GAAE,OAAO,EAAE,SAAS;AACnC,CAAC;AAMM,IAAM,qBAAqBA,GAAE,OAAO;AAAA,EACzC,IAAIA,GAAE,OAAO;AAAA,EACb,MAAMA,GAAE,KAAK,CAAC,OAAO,OAAO,YAAY,OAAO,CAAC;AAAA,EAChD,MAAMA,GAAE,OAAO;AAAA,EACf,WAAWA,GAAE,OAAO;AAAA,EACpB,aAAaA,GAAE,OAAO,EAAE,SAAS;AACnC,CAAC;AAMM,IAAM,sBAAsBA,GAAE,OAAO;AAAA,EAC1C,IAAIA,GAAE,OAAO;AAAA,EACb,MAAMA,GAAE,KAAK;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,SAASA,GAAE,OAAO;AAAA,EAClB,QAAQA,GAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,WAAWA,GAAE,OAAO;AACtB,CAAC;AAMM,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EAC3C,IAAIA,GAAE,OAAO;AAAA,EACb,MAAMA,GAAE,KAAK,CAAC,YAAY,UAAU,YAAY,WAAW,aAAa,WAAW,CAAC;AAAA,EACpF,SAASA,GAAE,OAAO;AAAA,EAClB,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,OAAOA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,MAAMA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,QAAQA,GAAE,KAAK,CAAC,UAAU,aAAa,QAAQ,CAAC;AAAA,EAChD,WAAWA,GAAE,OAAO;AAAA,EACpB,gBAAgBA,GAAE,OAAO,EAAE,SAAS;AACtC,CAAC;AAMM,IAAM,0BAA0BA,GAAE,KAAK,CAAC,uBAAuB,kBAAkB,CAAC;AAMlF,IAAM,yBAAyB,2BAA2B,OAAO;AAAA,EACtE,QAAQA,GAAE,KAAK,CAAC,WAAW,QAAQ,UAAU,CAAC;AAAA,EAC9C,eAAeA,GAAE,OAAO;AAAA,EACxB,gBAAgBA,GAAE,OAAO;AAAA,EACzB,uBAAuBA,GAAE,MAAMA,GAAE,OAAO,CAAC;AAC3C,CAAC;AAYM,IAAM,2BAA2BA,GAAE,KAAK;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAIM,IAAM,6BAA6BA,GAAE,OAAO;AAAA,EACjD,OAAOA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS;AAAA,EAC7D,QAAQA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACpD,MAAM,yBAAyB,SAAS;AAAA,EACxC,OAAOA,GAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACtC,OAAOA,GAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AACxC,CAAC;AAeM,IAAM,sBAAsBA,GAAE,OAAO;AAAA,EAC1C,MAAMA,GAAE,QAAQ,gBAAgB;AAAA,EAChC,OAAOA,GAAE,OAAO;AAAA,EAChB,MAAMA,GAAE,OAAO;AAAA,EACf,QAAQA,GAAE,OAAO;AAAA,EACjB,cAAcA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,EACpC,eAAeA,GAAE,KAAK,CAAC,eAAe,WAAW,UAAU,sBAAsB,SAAS,CAAC;AAAA,EAC3F,iBAAiBA,GAAE,OAAO;AAAA,EAC1B,SAASA,GAAE,OAAO;AAAA,EAClB,WAAWA,GAAE,OAAO;AACtB,CAAC;AAMM,IAAM,0BAA0BA,GAAE,KAAK;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,oBAAoBA,GAAE,OAAO;AAAA,EACxC,cAAcA,GAAE,OAAO;AAAA,EACvB,WAAWA,GAAE,OAAO;AAAA,EACpB,OAAOA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EACpC,WAAWA,GAAE,OAAO;AAAA,EACpB,gBAAgBA,GAAE,OAAO;AAAA,EACzB,SAASA,GAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EAC7B,YAAYA,GAAE,OAAO,EAAE,SAAS;AAAA,EAChC,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQ;AACV,CAAC;AAMM,IAAM,6BAA6BA,GAAE,mBAAmB,QAAQ;AAAA,EACrEA,GAAE,OAAO;AAAA,IACP,MAAMA,GAAE,QAAQ,UAAU;AAAA,IAC1B,cAAcA,GAAE,OAAO;AAAA,IACvB,SAASA,GAAE,OAAO;AAAA,IAClB,WAAWA,GAAE,OAAO;AAAA,EACtB,CAAC;AAAA,EACDA,GAAE,OAAO;AAAA,IACP,MAAMA,GAAE,QAAQ,UAAU;AAAA,IAC1B,cAAcA,GAAE,OAAO;AAAA,IACvB,SAASA,GAAE,OAAO;AAAA,IAClB,UAAUA,GAAE,MAAMA,GAAE,OAAO,CAAC;AAAA,EAC9B,CAAC;AAAA,EACDA,GAAE,OAAO;AAAA,IACP,MAAMA,GAAE,QAAQ,SAAS;AAAA,IACzB,cAAcA,GAAE,OAAO;AAAA,IACvB,QAAQA,GAAE,OAAO;AAAA,IACjB,UAAUA,GAAE,OAAO;AAAA,IACnB,SAASA,GAAE,KAAK,CAAC,OAAO,MAAM,CAAC;AAAA,EACjC,CAAC;AAAA,EACDA,GAAE,OAAO;AAAA,IACP,MAAMA,GAAE,QAAQ,QAAQ;AAAA,IACxB,cAAcA,GAAE,OAAO;AAAA,IACvB,OAAOA,GAAE,OAAO;AAAA,EAClB,CAAC;AAAA,EACDA,GAAE,OAAO;AAAA,IACP,MAAMA,GAAE,QAAQ,SAAS;AAAA,IACzB,cAAcA,GAAE,OAAO;AAAA,IACvB,WAAWA,GAAE,OAAO;AAAA,EACtB,CAAC;AACH,CAAC;AAMM,IAAM,6BAA6BA,GAAE,mBAAmB,QAAQ;AAAA,EACrEA,GAAE,OAAO,EAAE,MAAMA,GAAE,QAAQ,SAAS,GAAG,QAAQA,GAAE,OAAO,EAAE,CAAC;AAAA,EAC3DA,GAAE,OAAO,EAAE,MAAMA,GAAE,QAAQ,MAAM,EAAE,CAAC;AAAA,EACpCA,GAAE,OAAO,EAAE,MAAMA,GAAE,QAAQ,QAAQ,GAAG,SAASA,GAAE,OAAO,EAAE,CAAC;AAC7D,CAAC;;;AC9PD,SAAS,KAAAC,UAAS;AAIX,IAAM,+BAA+BA,GAAE,OAAO;AAAA,EACnD,MAAMA,GAAE,QAAQ,oBAAoB;AAAA,EACpC,cAAcA,GAAE,OAAO;AAAA,EACvB,WAAWA,GAAE,OAAO,EAAE,SAAS;AACjC,CAAC;AAMM,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EAC3C,MAAMA,GAAE,QAAQ,WAAW;AAAA,EAC3B,cAAcA,GAAE,OAAO;AAAA,EACvB,iBAAiBA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,EACvC,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,EAClC,QAAQA,GAAE,OAAO;AAAA,IACf,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IAC1B,UAAUA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC5B,CAAC;AACH,CAAC;AAMM,IAAM,2BAA2BA,GAAE,OAAO;AAAA,EAC/C,MAAMA,GAAE,QAAQ,gBAAgB;AAAA,EAChC,cAAcA,GAAE,OAAO;AAAA,EACvB,OAAOA,GAAE,OAAO;AAAA,EAChB,OAAOA,GAAE,OAAO;AAAA,EAChB,MAAMA,GAAE,OAAO;AAAA,EACf,QAAQA,GAAE,OAAO;AAAA,EACjB,QAAQA,GAAE,OAAO,EAAE,IAAI,GAAG;AAAA;AAC5B,CAAC;AAMM,IAAM,0BAA0BA,GAAE,OAAO;AAAA,EAC9C,MAAMA,GAAE,QAAQ,eAAe;AAAA,EAC/B,cAAcA,GAAE,OAAO;AAAA,EACvB,OAAOA,GAAE,OAAO;AAAA,EAChB,QAAQA,GAAE,KAAK,CAAC,aAAa,UAAU,WAAW,CAAC;AAAA,EACnD,QAAQA,GAAE,OAAO,EAAE,IAAI,GAAI,EAAE,SAAS;AAAA;AAAA,EACtC,SAASA,GAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,YAAYA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AACpC,CAAC;AAMM,IAAM,8BAA8BA,GAAE,OAAO;AAAA,EAClD,MAAMA,GAAE,QAAQ,mBAAmB;AAAA,EACnC,cAAcA,GAAE,OAAO;AAAA,EACvB,aAAaA,GAAE,OAAO;AAAA,EACtB,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,OAAOA,GAAE,OAAO,EAAE,IAAI,GAAI;AAAA,EAC1B,qBAAqBA,GAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAC7C,CAAC;AAMM,IAAM,+BAA+BA,GAAE,OAAO;AAAA,EACnD,MAAMA,GAAE,QAAQ,qBAAqB;AAAA,EACrC,cAAcA,GAAE,OAAO;AAAA,EACvB,OAAOA,GAAE,OAAO;AAAA,EAChB,OAAOA,GAAE,OAAO;AAAA,EAChB,MAAMA,GAAE,OAAO;AAAA,EACf,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQA,GAAE,QAAQ,oBAAoB;AACxC,CAAC;AAMM,IAAM,+BAA+BA,GAAE,OAAO;AAAA,EACnD,MAAMA,GAAE,QAAQ,oBAAoB;AAAA,EACpC,cAAcA,GAAE,OAAO;AAAA,EACvB,WAAWA,GAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,QAAQA,GAAE,KAAK,CAAC,YAAY,mBAAmB,SAAS,QAAQ,CAAC;AACnE,CAAC;AAMM,IAAM,+BAA+BA,GAAE,mBAAmB,QAAQ;AAAA,EACvE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;;;ATxCD,IAAM,iCAAiC;AAShC,SAAS,kBACd,gBACA,4BACA,uBACA,mBACS;AACT,QAAM,QAAQ,iBAAiB;AAC/B,MAAI,SAAS,sBAAuB,QAAO;AAC3C,MAAI,qBAAqB,SAAS,EAAG,QAAO;AAC5C,SAAO;AACT;AAMO,SAAS,cACd,gBACA,yBACA,qBAAqB,IACZ;AACT,QAAM,QAAQ,iBAAiB;AAC/B,SAAO,SAAS;AAClB;AAGO,IAAM,wBAAwB;AAc9B,SAAS,YACd,KACA,UAAoC,gBACpC,MAAc,KAAK,IAAI,GACd;AAET,MAAI,IAAI,WAAW,eAAe,IAAI,WAAW,UAAU;AACzD,WAAO;AAAA,EACT;AAGA,MAAI,IAAI,WAAW,YAAY,IAAI,WAAW,WAAW;AACvD,WAAO;AAAA,EACT;AAIA,MAAI,IAAI,OAAO,QAAQ,IAAI,GAAG,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,IAAI,KAAK;AACX,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,MAAM,IAAI,KAAK,IAAI,SAAS,EAAE,QAAQ;AAEpD,SAAO,QAAQ;AACjB;AAiHO,IAAM,gBAAN,MAAoB;AAAA,EACjB,WAAW;AAAA,EACX,sBAAsB;AAAA,EACtB,cAAsC;AAAA,EACtC;AAAA,EACS;AAAA,EACA;AAAA,EACT;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EAET;AAAA,EACS;AAAA,EACT,cAAkC;AAAA,EACzB;AAAA,EACA;AAAA,EACT,gBAAsC;AAAA;AAAA,EAE7B,sBAAsB,oBAAI,IAAY;AAAA;AAAA,EAG/C,gBAAsC;AAAA,EACtC,cAAkC;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,iBAAwC;AAAA,EAC/B;AAAA,EACT,gBAA+C;AAAA,EAEvD,YAAY,SAA+B;AACzC,SAAK,SAAS,QAAQ;AACtB,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,YAAY,QAAQ;AACzB,SAAK,YAAY,QAAQ;AACzB,SAAK,aAAa,QAAQ;AAC1B,SAAK,cAAc,QAAQ;AAC3B,SAAK,cAAc,QAAQ;AAC3B,SAAK,0BAA0B,QAAQ;AACvC,SAAK,eAAe,QAAQ;AAC5B,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,WAAW,QAAQ;AACxB,SAAK,0BAA0B,QAAQ;AACvC,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,aAAa,QAAQ;AAC1B,SAAK,iBAAiB,QAAQ;AAC9B,SAAK,iBAAiB,QAAQ;AAAA,EAChC;AAAA;AAAA,EAGA,IAAI,aAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGQ,kBAAuC,oBAAI,IAAI;AAAA,EAE/C,iBAAqC;AAC3C,QAAI,CAAC,KAAK,eAAe,KAAK,cAAc;AAC1C,UAAI;AACF,aAAK,cAAc,IAAI,YAAY,KAAK,YAAY;AACpD,aAAK,gBAAgB,OAAO,QAAQ;AAAA,MACtC,SAAS,OAAO;AAEd,cAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,aAAK,gBAAgB,IAAI,UAAU,GAAG;AACtC,aAAK,iBAAiB,GAAG,kBAAkB,kBAAkB,KAAK;AAAA,MACpE;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,YAA8B;AAAA,EAE9B,eAAiC;AACvC,QAAI,CAAC,KAAK,aAAa,KAAK,cAAc;AACxC,UAAI;AACF,aAAK,YAAY,IAAI,UAAU,KAAK,YAAY;AAChD,aAAK,gBAAgB,OAAO,MAAM;AAAA,MACpC,SAAS,OAAO;AAEd,cAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,aAAK,gBAAgB,IAAI,QAAQ,GAAG;AACpC,aAAK,iBAAiB,GAAG,kBAAkB,gBAAgB,KAAK;AAAA,MAClE;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,mBAAkC;AACxC,QAAI,CAAC,KAAK,eAAe;AACvB,WAAK,gBAAgB,IAAI,cAAcC,OAAK,KAAK,KAAK,eAAe,iBAAiB,CAAC;AAAA,IACzF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,oBAA2C;AACjD,QAAI,CAAC,KAAK,kBAAkB,KAAK,gBAAgB;AAC/C,UAAI;AACF,aAAK,iBAAiB,IAAI,eAAe,KAAK,cAAc;AAC5D,aAAK,gBAAgB,OAAO,WAAW;AAAA,MACzC,SAAS,OAAO;AAEd,cAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,aAAK,gBAAgB,IAAI,aAAa,GAAG;AACzC,aAAK,iBAAiB,GAAG,kBAAkB,qBAAqB,KAAK;AAAA,MACvE;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAKE;AACA,WAAO;AAAA,MACL,QAAQ;AAAA,QACN,WAAW,KAAK,gBAAgB;AAAA,QAChC,OAAO,KAAK,gBAAgB,IAAI,QAAQ;AAAA,MAC1C;AAAA,MACA,MAAM;AAAA,QACJ,WAAW,KAAK,cAAc;AAAA,QAC9B,OAAO,KAAK,gBAAgB,IAAI,MAAM;AAAA,MACxC;AAAA,MACA,WAAW;AAAA,QACT,WAAW,KAAK,mBAAmB;AAAA,QACnC,OAAO,KAAK,gBAAgB,IAAI,WAAW;AAAA,MAC7C;AAAA,MACA,UAAU;AAAA,QACR,WAAW,KAAK,kBAAkB;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,mBAA2C;AACjD,QAAI,CAAC,KAAK,eAAe;AACvB,WAAK,gBAAgB,IAAI;AAAA,QACvB,KAAK;AAAA,QACL;AAAA,UACE,wBAAwB,KAAK,OAAO,WAAW;AAAA,UAC/C,eAAe,KAAK,OAAO,WAAW;AAAA,UACtC,cAAc,KAAK,KAAK;AAAA;AAAA,QAC1B;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,qBAAqB,MAAM,KAAK,iBAAiB;AAGtD,UAAM,KAAK,kBAAkB;AAG7B,UAAM,KAAK,iBAAiB;AAE5B,UAAM,KAAK,YAAY,IAAI,aAAa,mCAAmC;AAC3E,UAAM,KAAK,sBAAsB;AAEjC,WAAO,CAAC,KAAK,UAAU;AACrB,UAAI;AACF,cAAM,KAAK,aAAa;AACxB,aAAK,sBAAsB;AAAA,MAC7B,QAAQ;AAGN,aAAK;AACL,cAAM,WAAW,KAAK,iBAAiB;AAGvC,cAAM,gBAAgB,SAAS,uBAAuB,KAAK,mBAAmB;AAC9E,YAAI,cAAc,eAAe;AAC/B,gBAAM,SAAS,kBAAkB,KAAK,qBAAqB,cAAc,SAAS;AAClF,gBAAM,KAAK,MAAM,cAAc,SAAS;AACxC;AAAA,QACF;AAAA,MACF;AAEA,UAAI,KAAK,SAAU;AAGnB,YAAM,KAAK,WAAW,aAAa,KAAK,OAAO,WAAW,cAAc;AAAA,IAC1E;AAEA,UAAM,KAAK,sBAAsB,UAAU;AAC3C,UAAM,KAAK,YAAY,IAAI,aAAa,mCAAmC;AAAA,EAC7E;AAAA,EAEA,OAAa;AACX,SAAK,WAAW;AAChB,SAAK,aAAa,MAAM,IAAI,MAAM,0BAA0B,CAAC;AAC7D,SAAK,WAAW,UAAU;AAG1B,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,KAAK;AACxB,WAAK,gBAAgB;AAAA,IACvB;AAGA,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,oBAAmC;AAE/C,SAAK,cAAc,IAAI,YAAY,KAAK,QAAQ;AAChD,UAAM,KAAK,YAAY,KAAK;AAG5B,UAAM,iBACJ,KAAK,4BAA4B,SAC7B,EAAE,YAAY,KAAK,wBAAwB,IAC3C;AAEN,SAAK,gBAAgB,IAAI,cAAc,KAAK,aAAa,cAAc;AAGvE,SAAK,cAAc,GAAG,UAAU,MAAM;AACpC,WAAK,mBAAmB;AAAA,IAC1B,CAAC;AAED,SAAK,cAAc,MAAM;AACzB,UAAM,KAAK,YAAY,IAAI,SAAS,sCAAsC;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,qBAA2B;AAEjC,QAAI,KAAK,aAAa;AACpB,WAAK,SAAS,KAAK,YAAY,OAAO;AAAA,IACxC;AAGA,SAAK,YAAY,IAAI,SAAS,qCAAqC,EAAE,MAAM,CAAC,QAAQ;AAClF,WAAK,iBAAiB,GAAG,kBAAkB,sBAAsB,GAAG;AAAA,IACtE,CAAC;AAID,SAAK,WAAW,UAAU;AAAA,EAC5B;AAAA,EAEA,MAAc,eAA8B;AAC1C,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,cAAcC,YAAW;AAE/B,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,UAAU;AACnC,YAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAGlD,YAAM,cAAc,MAAM,KAAK,oBAAoB,OAAO,KAAK;AAC/D,UAAI,YAAY,SAAU;AAG1B,YAAM,WAAW,MAAM,KAAK,mBAAmB;AAG/C,YAAM,EAAE,kBAAkB,mBAAmB,qBAAqB,oBAAoB,IACpF,MAAM,KAAK,iBAAiB,SAAS,WAAW,OAAO,aAAa;AAGtE,YAAM,wBAAwB,MAAM,mBAAmB,KAAK,aAAa;AACzE,YAAM,0BAA0B,sBAAsB,SAAS;AAG/D,YAAM,aAAa,MAAM,KAAK,gBAAgB;AAAA,QAC5C;AAAA,QACA,iBAAiB,SAAS;AAAA,QAC1B,YAAY,SAAS;AAAA,QACrB;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,WAAW,WAAY;AAC3B,UAAI,WAAW,eAAe;AAC5B,cAAM,KAAK,YAAY,EAAE,eAAe,GAAG,qBAAqB,EAAE,CAAC;AAAA,MACrE;AAGA,YAAM,aAAa,MAAM,KAAK,uBAAuB,KAAK;AAG1D,YAAM,EAAE,QAAQ,UAAU,IAAI,MAAM,KAAK,yBAAyB;AAAA,QAChE,SAAS,SAAS;AAAA,QAClB,WAAW,YAAY;AAAA,QACvB,gBAAgB,WAAW;AAAA,QAC3B,gBAAgB,WAAW;AAAA,QAC3B,cAAc,WAAW;AAAA,QACzB,iBAAiB,WAAW;AAAA,QAC5B,YAAY,SAAS;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,OAAO;AAAA,QACtB,4BAA4B,WAAW;AAAA,QACvC,UAAU,SAAS;AAAA,QACnB,OAAO,SAAS;AAAA,QAChB,eAAe,SAAS;AAAA,QACxB,gBAAgB,SAAS;AAAA,QACzB,kBAAkB,SAAS;AAAA,MAC7B,CAAC;AACD,YAAM,KAAK,YAAY;AAAA,QACrB;AAAA,QACA,cAAc,WAAW,cAAc,cAAc,SAAS;AAAA,QAC9D;AAAA,UACE;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS,QAAQ,SAAS;AAAA,UACpC,UAAU,SAAS,QAAQ,SAAS;AAAA,UACpC,gBAAgB,SAAS,QAAQ,eAAe;AAAA,UAChD,iBAAiB,WAAW;AAAA,QAC9B;AAAA,MACF;AAGA,YAAM,EAAE,SAAS,UAAU,IAAI,MAAM,KAAK,QAAQ,QAAQ,WAAW;AAGrE,UAAI,cAAc,GAAG;AACnB,cAAM,KAAK,YAAY;AAAA,UACrB;AAAA,UACA,cAAc,WAAW,cAAc;AAAA,UACvC,EAAE,YAAY;AAAA,QAChB;AAAA,MACF;AAGA,YAAM,KAAK,wBAAwB;AAAA,QACjC,WAAW,SAAS;AAAA,QACpB,iBAAiB,WAAW;AAAA,QAC5B,cAAc,WAAW;AAAA,QACzB,gBAAgB,WAAW;AAAA,MAC7B,CAAC;AAGD,YAAM,aAAa,KAAK,IAAI,IAAI;AAChC,YAAM,EAAE,YAAY,IAAI,KAAK,iBAAiB;AAAA,QAC5C;AAAA,QACA;AAAA,QACA,WAAW,YAAY;AAAA,QACvB;AAAA,QACA,gBAAgB,WAAW;AAAA,QAC3B,iBAAiB,WAAW;AAAA,QAC5B,cAAc,WAAW;AAAA,MAC3B,CAAC;AACD,YAAM,KAAK,YAAY,WAAW;AAElC,YAAM,KAAK,YAAY;AAAA,QACrB;AAAA,QACA,cAAc,WAAW,iBAAiB,CAAC,cAAc,SAAS;AAAA,QAClE;AAAA,UACE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,iBAAiB,WAAW;AAAA,QAC9B;AAAA,MACF;AAGA,YAAM,KAAK,qBAAqB;AAAA,QAC9B,gBAAgB,WAAW;AAAA,QAC3B,YAAY,SAAS;AAAA,QACrB,WAAW,YAAY;AAAA,QACvB;AAAA,QACA,WAAW,SAAS;AAAA,MACtB,CAAC;AAAA,IACH,SAAS,OAAO;AAId,YAAM,WAAW,KAAK,iBAAiB;AAGvC,YAAM,SAAS,qBAAqB;AAAA,QAClC;AAAA,QACA,qBAAqB,KAAK,sBAAsB;AAAA,QAChD;AAAA,QACA,QAAQ;AAAA,MACV,CAAC;AAED,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBACZ,OACA,OAC4B;AAC5B,UAAM,YAAY,OAAO,kBAAkB,QAAS,MAAM,gBAAgB,IAAK;AAE/E,QAAI,aAAa,KAAK,OAAO,WAAW,aAAa;AACnD,YAAM,KAAK,YAAY;AAAA,QACrB;AAAA,QACA,sCAAsC,UAAU,QAAQ,CAAC,CAAC,OAAO,KAAK,OAAO,WAAW,WAAW;AAAA,MACrG;AACA,YAAM,KAAK,MAAM,KAAK,OAAO,WAAW,cAAc;AACtD,aAAO,EAAE,WAAW,UAAU,KAAK;AAAA,IACrC;AAEA,WAAO,EAAE,WAAW,UAAU,MAAM;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBACZ,WACA,eACiC;AACjC,UAAM,gBAAgB,KAAK,iBAAiB;AAG5C,UAAM,KAAK,uBAAuB,WAAW,aAAa;AAC1D,UAAM,KAAK,qBAAqB,SAAS;AACzC,UAAM,KAAK,0BAA0B,SAAS;AAG9C,UAAM,mBAAmB,MAAM,cAAc,OAAO;AACpD,UAAM,sBAAsB,iBAAiB,SAAS;AAItD,UAAM,aAAa,MAAM,cAAc,QAAQ;AAC/C,UAAM,sBAAsB,WAAW,SAAS;AAChD,UAAM,mBAAmB,KAAK,OAAO,WAAW,aAAa,aAAa,CAAC;AAC3E,UAAM,oBAAoB,KAAK,OAAO,WAAW,aAC7C,MAAM,cAAc,SAAS,aAAa,IAC1C,CAAC;AAEL,WAAO,EAAE,kBAAkB,mBAAmB,qBAAqB,oBAAoB;AAAA,EACzF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAA4C;AACxD,UAAM,EAAE,SAAS,UAAU,IAAI,KAAK,WAAW,cAAc;AAC7D,UAAM,kBACJ,QAAQ,SAAS,SAAS,QAAQ,SAAS,SAAS,QAAQ,eAAe;AAE7E,UAAM,iBAAiB,KAAK,OAAO,aAAa,OAAO,KAAK,KAAK,OAAO,UAAU,IAAI,CAAC;AAGvF,UAAM,cAAc,KAAK,eAAe;AACxC,UAAM,WAA0B,cAC5B,YAAY,MAAM,EAAE,OAAO,IAAI,QAAQ,YAAY,CAAC,IACpD,CAAC;AACL,UAAM,YAAY,KAAK,aAAa;AACpC,UAAM,QAAqB,YAAY,UAAU,SAAS,IAAI,CAAC;AAG/D,UAAM,iBAAiB,KAAK,kBAAkB;AAC9C,UAAM,CAAC,YAAY,eAAe,gBAAgB,IAAI,MAAM,QAAQ,IAAI;AAAA,MACtE,KAAK,cAAc;AAAA,MACnB,KAAK,YAAY,KAAK,EAAE;AAAA,MACxB,iBAAiB,eAAe,OAAO,MAAM,IAAI,QAAQ,QAAQ,CAAC,CAAgB;AAAA,IACpF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBAAwB,OAA8C;AAElF,QAAI,MAAM,UAAU,SAAS,GAAG;AAC9B,YAAM,YAAYD,OAAK,KAAK,KAAK,eAAe,aAAa;AAC7D,YAAM,KAAK,WAAW,cAAc,WAAW,KAAK,YAAY,MAAM,SAAS;AAAA,IACjF;AAGA,QAAI,MAAM,iBAAiB;AACzB,YAAM,SAAS,MAAM,eAAe,IAAI,CAAC,MAAM,EAAE,EAAE;AACnD,UAAI,OAAO,SAAS,GAAG;AACrB,cAAM,iBAAiB,KAAK,eAAe,MAAM;AAAA,MACnD;AACA,YAAM,iBAAiB,KAAK,aAAa;AAAA,IAC3C;AAGA,QAAI,MAAM,cAAc;AACtB,YAAM,iBAAiB,KAAK,kBAAkB;AAC9C,UAAI,gBAAgB;AAClB,cAAM,UAAU,MAAM,eAAe,UAAU;AAC/C,YAAI,QAAQ,SAAS,GAAG;AACtB,gBAAM,KAAK,YAAY,IAAI,SAAS,cAAc,QAAQ,MAAM,yBAAyB;AAAA,YACvF,YAAY;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAqB,OAA6C;AAE9E,UAAM,KAAK,uBAAuB;AAAA,MAChC,iBAAiB,MAAM,iBAAiB;AAAA,MACxC,YAAY,MAAM,WAAW;AAAA,MAC7B,UAAU,MAAM,YAAY,MAAM;AAAA,MAClC,UAAU,KAAK,OAAO,WAAW;AAAA,IACnC,CAAC;AAGD,eAAW,SAAS,MAAM,WAAW;AACnC,UAAI,MAAM,SAAS,gBAAgB;AACjC,cAAM,UAAU,MAAM,KAAK,iBAAiB,MAAM,KAAK;AACvD,cAAM,WAAwD;AAAA,UAC5D,OAAO,MAAM;AAAA,UACb,QAAQ,SAAS,WAAW,WAAW,WAAW;AAAA,UAClD,SAAS,SAAS,gBAAgB;AAAA,UAClC,YAAY,SAAS,cAAc;AAAA,UACnC,cAAc,SAAS,gBAAgB;AAAA,QACzC;AACA,YAAI,SAAS,WAAW,QAAW;AACjC,mBAAS,SAAS,QAAQ;AAAA,QAC5B;AACA,YAAI,SAAS,SAAS,QAAW;AAC/B,mBAAS,OAAO,QAAQ;AAAA,QAC1B;AACA,cAAM,KAAK,iBAAiB,QAAQ;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAAgB,MAAgD;AAC5E,UAAM,EAAE,OAAO,iBAAiB,YAAY,yBAAyB,oBAAoB,IACvF;AACF,UAAM,gBAAgB,OAAO,iBAAiB;AAC9C,UAAM,sBAAsB,OAAO,uBAAuB;AAC1D,UAAM,gBAAgB,WAAW,SAAS;AAG1C,UAAM,kBAAkB,OAAO,gBAC3B,IAAI,KAAK,MAAM,aAAa,EAAE,QAAQ,IACtC,KAAK,IAAI;AACb,UAAM,2BAA2B,KAAK,IAAI,IAAI;AAG9C,UAAM,UAAuB;AAAA,MAC3B,YAAY;AAAA,MACZ,YAAY,WAAW;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,WAAW,IAAI,aAAa;AAAA,MAChC,aAAa,KAAK,OAAO,WAAW;AAAA,MACpC,mBAAmB,KAAK,OAAO,WAAW;AAAA,IAC5C,CAAC;AAED,UAAM,SAAS,SAAS,WAAW,OAAO;AAE1C,QAAI,OAAO,YAAY;AAErB,UAAI,eAAe;AACjB,cAAM,KAAK,YAAY;AAAA,UACrB,qBAAqB,sBAAsB;AAAA,UAC3C,eAAe;AAAA,QACjB,CAAC;AACD,cAAM,KAAK,YAAY;AAAA,UACrB;AAAA,UACA,qBAAqB,sBAAsB,CAAC,IAAI,KAAK,OAAO,WAAW,iBAAiB,WAAM,OAAO,MAAM;AAAA,QAC7G;AAAA,MACF,OAAO;AACL,cAAM,KAAK,YAAY;AAAA,UACrB,eAAe,gBAAgB;AAAA,UAC/B,qBAAqB;AAAA,QACvB,CAAC;AACD,cAAM,KAAK,YAAY;AAAA,UACrB;AAAA,UACA,cAAc,gBAAgB,CAAC,IAAI,KAAK,OAAO,WAAW,WAAW,WAAM,OAAO,MAAM;AAAA,QAC1F;AAAA,MACF;AACA,aAAO,EAAE,YAAY,MAAM,eAAe,MAAM;AAAA,IAClD;AAEA,UAAM,aAAa,gBAAgB,KAAK,sBAAsB;AAC9D,WAAO,EAAE,YAAY,OAAO,eAAe,WAAW;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBACZ,OAC8B;AAC9B,UAAM,iBAAiB,OAAO,kBAAkB;AAChD,UAAM,oBAAoB,OAAO,8BAA8B;AAC/D,UAAM,iBAAiB,OAAO,2BAA2B;AACzD,UAAM,sBAAsB,OAAO;AACnC,UAAM,iBAAiB,MAAM,mBAAmB,KAAK,aAAa;AAElE,UAAM,sCAAsC,sBACxC,eAAe,KAAK,CAAC,MAAM,EAAE,YAAY,mBAAmB,IAC5D,eAAe,SAAS;AAE5B,UAAM,oBAAoB,eAAe,SAAS;AAClD,UAAM,eAAe,cAAc,gBAAgB,cAAc;AACjE,UAAM,mBAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,kBACJ,gBAAiB,oBAAoB;AAEvC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,MAQH;AACpB,UAAM,cAA8C;AAAA,MAClD,WAAW,KAAK;AAAA,MAChB,gBAAe,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC,gBAAgB,KAAK,iBAAiB;AAAA,MACtC,eAAe,KAAK,OAAO,gBAAgB,KAAK,KAAK;AAAA,MACrD,cAAc,KAAK,YAAY,KAAK;AAAA,MACpC,eAAe,KAAK;AAAA,IACtB;AAEA,QAAI,KAAK,iBAAiB;AACxB,kBAAY,6BAA6B,KAAK,iBAAiB;AAC/D,kBAAY,8BAA6B,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClE;AAEA,QAAI,KAAK,cAAc;AACrB,kBAAY,0BAA0B,KAAK,iBAAiB;AAAA,IAC9D;AAEA,WAAO,EAAE,YAAY;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,yBAAyB,MAkBY;AACjD,UAAM,aAAa;AAAA,MACjB,OAAO,KAAK,OAAO;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,cAAc;AAAA,QACZ,UAAU,KAAK;AAAA,QACf,QAAQ,KAAK,OAAO,WAAW;AAAA,QAC/B,eACI,KAAK,OAAO,WAAW,cAAc,KAAK,aAC1C,KAAK,OAAO,WAAW,cACzB;AAAA,MACJ;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,gBAAgB,KAAK;AAAA,MACrB,gBAAgB,KAAK;AAAA,MACrB,oBAAoB,KAAK;AAAA,MACzB,eAAe,KAAK;AAAA,MACpB,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,eAAe,KAAK;AAAA,MACpB,kBAAkB,KAAK;AAAA,MACvB,mBAAmB,KAAK;AAAA,MACxB,qBAAqB,KAAK;AAAA,MAC1B,YAAY,KAAK,OAAO,WAAW;AAAA,MACnC,kBAAkB,KAAK;AAAA,IACzB;AAEA,QAAI,KAAK,cAAc;AACrB,aAAO;AAAA,QACL,QAAQ,sBAAsB;AAAA,UAC5B,GAAG;AAAA,UACH,4BAA4B,KAAK;AAAA,QACnC,CAAC;AAAA,QACD,WAAW;AAAA,MACb;AAAA,IACF;AAEA,QAAI,KAAK,iBAAiB;AACxB,aAAO;AAAA,QACL,QAAQ,yBAAyB;AAAA,UAC/B,GAAG;AAAA,UACH,4BAA4B,KAAK;AAAA,QACnC,CAAC;AAAA,QACD,WAAW;AAAA,MACb;AAAA,IACF;AAEA,QAAI,gBAAgB,UAAU,GAAG;AAC/B,aAAO;AAAA,QACL,QAAQ,gBAAgB,UAAU;AAAA,QAClC,WAAW;AAAA,MACb;AAAA,IACF;AAEA,WAAO;AAAA,MACL,QAAQ,oBAAoB,UAAU;AAAA,MACtC,WAAW;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,QACZ,QACA,aACiE;AACjE,UAAM,kBAAkB,IAAI,gBAAgB;AAC5C,SAAK,cAAc;AACnB,UAAM,UAAU,WAAW,MAAM;AAC/B,sBAAgB,MAAM,IAAI,MAAM,4BAA4B,CAAC;AAAA,IAC/D,GAAG,KAAK,OAAO,WAAW,kBAAkB;AAE5C,QAAI,SAAS;AACb,QAAI,UAAU;AACd,QAAI,YAAY;AAEhB,QAAI;AACF,YAAM,MAAM,MAAM,OAAO,gCAAgC;AAGzD,YAAM,eAAyB,CAAC,QAAQ,MAAM;AAC9C,UAAI,KAAK,OAAO,YAAY;AAC1B,mBAAW,QAAQ,OAAO,KAAK,KAAK,OAAO,UAAU,GAAG;AACtD,uBAAa,KAAK,QAAQ,IAAI,KAAK;AAAA,QACrC;AAAA,MACF;AAEA,YAAM,eAAwC;AAAA,QAC5C,KAAKE,SAAQ;AAAA,QACb;AAAA,QACA,gBAAgB;AAAA,QAChB,iCAAiC;AAAA,QACjC,YAAY,KAAK,OAAO,cAAc,CAAC;AAAA;AAAA;AAAA,QAGvC,gBAAgB;AAAA,MAClB;AAEA,YAAM,SAAS,IAAI,MAAM,EAAE,QAAQ,SAAS,aAAsB,CAAC;AAGnE,YAAM,eAAe,IAAI,QAA2B,CAACC,aAAY;AAC/D,YAAI,gBAAgB,OAAO,SAAS;AAClC,UAAAA,SAAQ,EAAE,SAAS,KAAK,CAAC;AACzB;AAAA,QACF;AACA,wBAAgB,OAAO,iBAAiB,SAAS,MAAMA,SAAQ,EAAE,SAAS,KAAK,CAAC,GAAG;AAAA,UACjF,MAAM;AAAA,QACR,CAAC;AAAA,MACH,CAAC;AAGD,YAAM,WAAW,OAAO,OAAO,aAAa,EAAE;AAC9C,UAAI;AACF,eAAO,MAAM;AACX,gBAAM,aAAa,MAAM,QAAQ,KAAK,CAAC,SAAS,KAAK,GAAG,YAAY,CAAC;AAGrE,cAAI,aAAa,YAAY;AAC3B,kBAAM,KAAK,YAAY,IAAI,aAAa,qBAAqB,EAAE,YAAY,CAAC;AAC5E;AAAA,UACF;AAGA,gBAAM,aAAa;AACnB,cAAI,WAAW,KAAM;AAErB,gBAAM,MAAM,WAAW;AAEvB,cAAI,cAAc,GAAG,GAAG;AACtB,iBAAK,YAAY,IAAI;AAAA,UACvB;AAEA,cAAI,gBAAgB,GAAG,GAAG;AACxB,qBAAS,IAAI,UAAU;AACvB,sBAAU,IAAI,kBAAkB;AAChC,wBAAY,IAAI,aAAa;AAAA,UAC/B;AAEA,gBAAM,KAAK,iBAAiB,KAAK,WAAW;AAAA,QAC9C;AAAA,MACF,UAAE;AAEA,cAAM,SAAS,SAAS;AAAA,MAC1B;AAAA,IACF,UAAE;AACA,mBAAa,OAAO;AACpB,WAAK,cAAc;AAAA,IACrB;AAEA,WAAO,EAAE,QAAQ,SAAS,UAAU;AAAA,EACtC;AAAA,EAEA,MAAc,YAAmD;AAC/D,QAAI;AACF,YAAM,MAAM,MAAMC,WAAS,KAAK,WAAW,OAAO;AAClD,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,YAAM,SAAS,4BAA4B,UAAU,MAAM;AAC3D,aAAO,OAAO,UAAU,OAAO,OAAO;AAAA,IACxC,SAAS,OAAO;AACd,WAAK,iBAAiB,GAAG,kBAAkB,aAAa,KAAK;AAC7D,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,YAAY,SAAwD;AAChF,QAAI;AACF,YAAM,MAAM,MAAMA,WAAS,KAAK,WAAW,OAAO;AAClD,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,YAAM,SAAS,4BAA4B,UAAU,MAAM;AAC3D,UAAI,CAAC,OAAO,QAAS;AACrB,YAAM,QAAQ,OAAO;AACrB,aAAO,OAAO,OAAO,OAAO;AAC5B,YAAMC,WAAU,KAAK,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,IACzE,SAAS,OAAO;AAEd,WAAK,iBAAiB,GAAG,kBAAkB,eAAe,KAAK;AAAA,IACjE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,gBAAmC;AAC/C,UAAM,UAAU,WAAW;AAC3B,QAAI,CAACC,YAAW,OAAO,EAAG,QAAO,CAAC;AAElC,QAAI;AACF,YAAM,UAAU,MAAMC,SAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,YAAM,SAAmB,CAAC;AAE1B,iBAAW,SAAS,SAAS;AAC3B,YAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,cAAM,SAASP,OAAK,KAAK,SAAS,MAAM,IAAI;AAC5C,cAAM,QAAQ,MAAMO,SAAQ,MAAM;AAElC,mBAAW,KAAK,OAAO;AACrB,cAAI,CAAC,EAAE,SAAS,OAAO,EAAG;AAC1B,cAAI;AACF,kBAAM,MAAM,MAAMH,WAASJ,OAAK,KAAK,QAAQ,CAAC,GAAG,OAAO;AACxD,kBAAM,MAAM,KAAK,MAAM,GAAG;AAE1B,gBAAI,YAAY,GAAG,GAAG;AACpB,qBAAO;AAAA,gBACL,GAAG,IAAI,KAAK,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,OAAOA,OAAK,SAAS,IAAI,IAAI,CAAC;AAAA,cACzE;AAAA,YACF;AAAA,UACF,SAAS,OAAO;AAEd,iBAAK,iBAAiB,GAAG,kBAAkB,8BAA8B,KAAK;AAAA,UAChF;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,iBAAiB,GAAG,kBAAkB,iBAAiB,KAAK;AACjE,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,mBAAgD;AAC5D,UAAM,aAAuB,CAAC;AAE9B,QAAI,KAAK,OAAO,WAAW,cAAc;AACvC,iBAAW,KAAKA,OAAK,QAAQ,KAAK,OAAO,WAAW,YAAY,CAAC;AAAA,IACnE;AAEA,eAAW,KAAKA,OAAK,KAAK,WAAW,GAAG,eAAe,CAAC;AAExD,QAAI,KAAK,yBAAyB;AAChC,iBAAW,KAAK,KAAK,uBAAuB;AAAA,IAC9C;AAEA,eAAW,YAAY,YAAY;AACjC,UAAI;AACF,cAAM,UAAU,MAAMI,WAAS,UAAU,OAAO;AAChD,cAAM,KAAK,YAAY,IAAI,SAAS,4BAA4B,QAAQ,EAAE;AAC1E,eAAO;AAAA,MACT,SAAS,OAAO;AAEd,aAAK,iBAAiB,GAAG,kBAAkB,oBAAoB,KAAK;AAAA,MACtE;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,iBAAiB,KAAuB,aAAoC;AACxF,QAAI,mBAAmB,GAAG,GAAG;AAC3B,YAAM,KAAK,iBAAiB,KAAK,WAAW;AAAA,IAC9C,WAAW,iBAAiB,GAAG,GAAG;AAChC,YAAM,KAAK,WAAW,KAAK,WAAW;AAAA,IACxC,WAAW,oBAAoB,GAAG,GAAG;AACnC,YAAM,KAAK,cAAc,KAAK,WAAW;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,iBAAiB,KAAuB,aAAoC;AACxF,QAAI,CAAC,mBAAmB,GAAG,EAAG;AAC9B,UAAM,UAAU,IAAI,SAAS;AAC7B,QAAI,CAAC,QAAS;AAEd,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,SAAS,cAAc,MAAM,UAAU;AAC/C,cAAM,KAAK,YAAY,IAAI,YAAY,MAAM,UAAU,EAAE,YAAY,CAAC;AAAA,MACxE;AACA,UAAI,MAAM,SAAS,UAAU,MAAM,MAAM;AACvC,cAAM,KAAK,YAAY,IAAI,QAAQ,MAAM,MAAM,EAAE,YAAY,CAAC;AAC9D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,WAAW,KAAuB,aAAoC;AAClF,QAAI,CAAC,iBAAiB,GAAG,EAAG;AAC5B,UAAM,WAAW,IAAI;AACrB,UAAM,QAAQ,SAAS,WAAW,OAAO;AACzC,UAAM,KAAK,YAAY;AAAA,MACrB,QAAQ,aAAa;AAAA,MACrB,QAAQ,WAAW,aAAa,QAAQ;AAAA,MACxC,EAAE,aAAa,MAAM,UAAU,OAAO,IAAI,MAAM;AAAA,IAClD;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,cAAc,KAAuB,aAAoC;AACrF,QAAI,CAAC,oBAAoB,GAAG,EAAG;AAC/B,UAAM,SAAS,IAAI,UAAU;AAC7B,UAAM,WAAW,4BAA4B,KAAK,MAAM;AACxD,UAAM,QAAQ,WAAW,CAAC;AAC1B,QAAI,OAAO;AACT,YAAM,KAAK,YAAY,IAAI,YAAY,qBAAqB,KAAK,IAAI;AAAA,QACnE;AAAA,QACA;AAAA,MACF,CAAC;AAaD,YAAM,aAAa,oBAAoB,KAAK,MAAM;AAClD,YAAM,YAAY,mBAAmB,KAAK,MAAM;AAChD,YAAM,cAAc,qBAAqB,KAAK,MAAM;AAEpD,YAAM,QAAQ,aAAa,CAAC,KAAK;AACjC,YAAM,OAAO,YAAY,CAAC,KAAK;AAC/B,YAAM,SAAS,cAAc,CAAC,KAAK;AAEnC,YAAM,KAAK,kBAAkB;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,OAAO,MAAM,GAAG,GAAG;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAACD,aAAY,WAAWA,UAAS,EAAE,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,uBACZ,WACA,OACe;AACf,eAAW,SAAS,WAAW;AAC7B,YAAM,SAAS,yBAAyB,KAAK;AAC7C,UAAI,CAAC,OAAQ;AACb,YAAM,KAAK,oBAAoB,OAAO,YAAY,OAAO,QAAQ,KAAK;AAAA,IACxE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,qBAAqB,WAAyC;AAC1E,QAAI,CAAC,KAAK,cAAe;AACzB,eAAW,SAAS,WAAW;AAC7B,UAAI,MAAM,SAAS,UAAW;AAC9B,YAAM,UAAU,kBAAkB,MAAM,KAAK,QAAQ,EAAE;AACvD,UAAI,CAAC,QAAS;AACd,cAAQ,QAAQ,MAAM;AAAA,QACpB,KAAK;AACH,eAAK,cAAc,KAAK,QAAQ,cAAc;AAAA,YAC5C,MAAM;AAAA,YACN,SAAS,QAAQ;AAAA,UACnB,CAAC;AACD;AAAA,QACF,KAAK;AACH,eAAK,cAAc,KAAK,QAAQ,cAAc;AAAA,YAC5C,MAAM;AAAA,YACN,QAAQ,QAAQ;AAAA,UAClB,CAAC;AACD;AAAA,QACF,KAAK;AACH,eAAK,cAAc,KAAK,QAAQ,cAAc,EAAE,MAAM,OAAO,CAAC;AAC9D;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,0BAA0B,WAAyC;AAC/E,QAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,cAAc,CAAC,KAAK,eAAgB;AAErE,eAAW,SAAS,WAAW;AAC7B,UAAI,MAAM,SAAS,UAAW;AAC9B,YAAM,OAAO,MAAM,KAAK,QAAQ;AAChC,YAAM,SAAS,uBAAuB,IAAI;AAC1C,UAAI,CAAC,OAAQ;AAEb,UAAI;AACF,cAAM,eAA2D;AAAA,UAC/D,WAAW,OAAO;AAAA,UAClB,oBAAoB,OAAO;AAAA,UAC3B,UAAU,KAAK;AAAA,UACf,YAAY,KAAK;AAAA,UACjB,YAAY,KAAK;AAAA,UACjB,OAAO;AAAA,QACT;AACA,YAAI,OAAO,eAAe,QAAW;AACnC,uBAAa,aAAa,OAAO;AAAA,QACnC;AACA,cAAM,SAAS,MAAM,qBAAqB,YAAY;AAEtD,cAAM,KAAK,YAAY;AAAA,UACrB;AAAA,UACA,sCAAsC,OAAO,YAAY;AAAA,UACzD;AAAA,YACE,cAAc,OAAO;AAAA,YACrB,WAAW,OAAO;AAAA,UACpB;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAM,KAAK,YAAY,IAAI,SAAS,qCAAqC,GAAG,EAAE;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,oBACZ,YACA,QACA,OACe;AACf,QAAI,KAAK,oBAAoB,IAAI,UAAU,EAAG;AAE9C,UAAM,kBAAkB,MAAM,MAAM,WAAW,UAAU;AACzD,QAAI,iBAAiB;AACnB,WAAK,oBAAoB,IAAI,UAAU;AACvC;AAAA,IACF;AAEA,QAAI;AACF,YAAM,MAAM,OAAO,YAAY,MAAM;AACrC,WAAK,oBAAoB,IAAI,UAAU;AACvC,YAAM,KAAK,YAAY,IAAI,SAAS,sBAAsB,UAAU,IAAI;AAAA,QACtE;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,UAAI,IAAI,SAAS,kBAAkB,GAAG;AACpC,aAAK,oBAAoB,IAAI,UAAU;AAAA,MACzC,OAAO;AACL,cAAM,KAAK,YAAY,IAAI,SAAS,6BAA6B,UAAU,KAAK,GAAG,IAAI;AAAA,UACrF;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAAiB,OAOrB;AACR,UAAM,UAAU,WAAW;AAC3B,QAAI,CAACG,YAAW,OAAO,EAAG,QAAO;AAEjC,QAAI;AACF,YAAM,UAAU,MAAMC,SAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAE9D,iBAAW,SAAS,SAAS;AAC3B,YAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,cAAM,SAASP,OAAK,KAAK,SAAS,MAAM,IAAI;AAC5C,cAAM,UAAUA,OAAK,KAAK,QAAQ,GAAG,KAAK,OAAO;AAEjD,YAAIM,YAAW,OAAO,GAAG;AACvB,gBAAM,MAAM,MAAMF,WAAS,SAAS,OAAO;AAC3C,gBAAM,MAAM,KAAK,MAAM,GAAG;AAG1B,gBAAM,eAAe,OAAO,OAAO,IAAI,KAAK,EAAE;AAAA,YAC5C,CAAC,KAAK,SAAS,OAAO,KAAK,WAAW;AAAA,YACtC;AAAA,UACF;AAGA,gBAAM,aAAa,IAAI,KAAK,IAAI,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,IAAI,SAAS,EAAE,QAAQ;AAGvF,gBAAM,iBAAiB,OAAO,OAAO,IAAI,KAAK,EAAE;AAAA,YAC9C,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW;AAAA,UAChD;AACA,gBAAM,WAAW,eAAe,eAAe,SAAS,CAAC;AACzD,gBAAM,SACJ,OAAO,UAAU,cAAc,WAAW,SAAS,UAAU,MAAM,GAAG,GAAI,IAAI;AAGhF,gBAAM,OAAO,IAAI,QAAQ,MAAM,GAAG,GAAG,KAAK;AAE1C,iBAAO;AAAA,YACL,QAAQ,IAAI;AAAA,YACZ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,cAAc,OAAO,KAAK,IAAI,KAAK,EAAE;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AAEd,WAAK,iBAAiB,GAAG,kBAAkB,oBAAoB,KAAK;AAAA,IACtE;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,iBAAiB,OAA8C;AAC3E,QAAI,CAAC,KAAK,eAAgB;AAE1B,QAAI;AAEF,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AACH,uCAA6B,MAAM,KAAK;AACxC;AAAA,QACF,KAAK;AACH,+BAAqB,MAAM,KAAK;AAChC;AAAA,QACF,KAAK;AACH,sCAA4B,MAAM,KAAK;AACvC;AAAA,QACF,KAAK;AACH,mCAAyB,MAAM,KAAK;AACpC;AAAA,QACF,KAAK;AACH,kCAAwB,MAAM,KAAK;AACnC;AAAA,QACF,KAAK;AACH,uCAA6B,MAAM,KAAK;AACxC;AAAA,QACF,KAAK;AACH,uCAA6B,MAAM,KAAK;AACxC;AAAA,MACJ;AAEA,YAAM,KAAK,eAAe,KAAK;AAAA,IACjC,SAAS,OAAO;AAEd,YAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,YAAM,KAAK,YAAY,IAAI,SAAS,kCAAkC,GAAG,IAAI;AAAA,QAC3E,WAAW,MAAM;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,wBAAuC;AACnD,UAAM,QAAgC;AAAA,MACpC,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,UAAM,KAAK,iBAAiB,KAAK;AAAA,EACnC;AAAA;AAAA,EAGA,MAAc,sBACZ,QACe;AACf,UAAM,QAAgC;AAAA,MACpC,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC;AAAA,IACF;AACA,UAAM,KAAK,iBAAiB,KAAK;AAAA,EACnC;AAAA;AAAA,EAGA,MAAc,uBAAuB,MAKnB;AAChB,UAAM,QAAwB;AAAA,MAC5B,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,iBAAiB,KAAK;AAAA,MACtB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,YAAY,KAAK;AAAA,MACjB,QAAQ;AAAA,QACN,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,MACjB;AAAA,IACF;AACA,UAAM,KAAK,iBAAiB,KAAK;AAAA,EACnC;AAAA;AAAA,EAGA,MAAc,kBAAkB,MAMd;AAChB,UAAM,QAA4B;AAAA,MAChC,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK,OAAO,MAAM,GAAG,GAAG;AAAA;AAAA,IAClC;AACA,UAAM,KAAK,iBAAiB,KAAK;AAAA,EACnC;AAAA;AAAA,EAGA,MAAc,iBAAiB,MAQb;AAChB,UAAM,QAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK,QAAQ,MAAM,GAAG,GAAI;AAAA;AAAA,MAClC,SAAS,KAAK;AAAA,MACd,YAAY,KAAK;AAAA,IACnB;AACA,UAAM,KAAK,iBAAiB,KAAK;AAGjC,QAAI,KAAK,WAAW,UAAU;AAC5B,UAAI;AACF,cAAM,SAAS,oBAAoB;AAAA,UACjC,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK,QAAQ;AAAA,UACnB,QAAQ,KAAK,UAAU;AAAA,UACvB,cAAc,KAAK,gBAAgB;AAAA,UACnC,SAAS,KAAK;AAAA,QAChB,CAAC;AACD,cAAM,mBAAmB,KAAK,eAAe,MAAM;AAAA,MACrD,SAAS,OAAO;AAEd,aAAK,iBAAiB,GAAG,kBAAkB,sBAAsB,KAAK;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,sBAAsB,MAIlB;AAChB,UAAM,QAAgC;AAAA,MACpC,MAAM;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,QAAQ;AAAA,IACV;AACA,UAAM,KAAK,iBAAiB,KAAK;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAAkC;AAC9C,QAAI;AACF,YAAM,WAAW,IAAI,SAAS;AAC9B,YAAM,YAAY,MAAM,SAAS,iBAAiB;AAElD,UAAI,UAAU,WAAW,EAAG;AAE5B,YAAM,KAAK,YAAY;AAAA,QACrB;AAAA,QACA,aAAa,UAAU,MAAM;AAAA,QAC7B,EAAE,QAAQ,UAAU,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE;AAAA,MAC1C;AAGA,iBAAW,OAAO,WAAW;AAC3B,cAAM,KAAK,sBAAsB;AAAA,UAC/B,OAAO,IAAI;AAAA,UACX,OAAO,IAAI;AAAA,UACX,MAAM,IAAI;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF,SAAS,OAAO;AAEd,YAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACjE,YAAM,KAAK,YAAY,IAAI,SAAS,8BAA8B,GAAG,EAAE;AAAA,IACzE;AAAA,EACF;AACF;AAMA,SAAS,yBACP,OAC+C;AAC/C,MAAI,MAAM,SAAS,UAAW,QAAO;AACrC,MAAI,CAAC,MAAM,KAAK,KAAM,QAAO;AAC7B,QAAM,OAAO,MAAM,KAAK,KAAK,KAAK;AAClC,QAAM,QAAQ,oCAAoC,KAAK,IAAI;AAC3D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,aAAa,MAAM,CAAC;AAC1B,QAAM,SAAS,MAAM,CAAC;AACtB,MAAI,CAAC,cAAc,CAAC,OAAQ,QAAO;AACnC,SAAO,EAAE,YAAY,OAAO;AAC9B;;;AUjsDA,SAAS,cAAAI,aAAY,uBAAuB;AAC5C,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,oBAA4E;AAGrF,IAAM,gBAAgB,OAAO;AAmBtB,IAAM,gBAAN,MAAoB;AAAA,EACjB,SAAwB;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAET,YAA2B,QAAQ,QAAQ;AAAA,EAEnD,YAAY,SAA+B;AACzC,SAAK,OAAO,QAAQ;AACpB,SAAK,SAAS,QAAQ;AACtB,SAAK,aAAa,QAAQ;AAC1B,SAAK,UAAU,QAAQ;AACvB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEA,MAAM,QAAuB;AAC3B,WAAO,IAAI,QAAc,CAACC,UAAS,WAAW;AAC5C,WAAK,SAAS,aAAa,CAAC,KAAK,QAAQ;AACvC,aAAK,cAAc,KAAK,GAAG,EAAE,MAAM,CAAC,QAAQ;AAC1C,eAAK,SAAS,KAAK,KAAK,EAAE,OAAO,yBAAyB,QAAQ,OAAO,GAAG,EAAE,CAAC;AAAA,QACjF,CAAC;AAAA,MACH,CAAC;AAED,WAAK,OAAO,GAAG,SAAS,MAAM;AAE9B,WAAK,OAAO,OAAO,KAAK,MAAM,MAAM;AAClC,QAAAA,SAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAsB;AAC1B,WAAO,IAAI,QAAc,CAACA,aAAY;AACpC,UAAI,CAAC,KAAK,QAAQ;AAChB,QAAAA,SAAQ;AACR;AAAA,MACF;AACA,WAAK,OAAO,MAAM,MAAMA,SAAQ,CAAC;AAAA,IACnC,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,cAAc,KAAsB,KAAoC;AACpF,UAAM,MAAM,IAAI,OAAO;AAEvB,QAAI,IAAI,WAAW,SAAS,QAAQ,WAAW;AAC7C,WAAK,SAAS,KAAK,KAAK,KAAK,UAAU,CAAC;AACxC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,UAAU,QAAQ,YAAY;AAC/C,YAAM,KAAK,cAAc,KAAK,GAAG;AACjC;AAAA,IACF;AAEA,SAAK,SAAS,KAAK,KAAK,EAAE,OAAO,YAAY,CAAC;AAAA,EAChD;AAAA,EAEA,MAAc,cAAc,KAAsB,KAAoC;AAEpF,UAAM,OAAO,MAAM,KAAK,SAAS,GAAG;AACpC,QAAI,SAAS,MAAM;AACjB,WAAK,SAAS,KAAK,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAChE;AAAA,IACF;AAGA,QAAI,KAAK,QAAQ;AACf,YAAM,YAAY,IAAI,QAAQ,iBAAiB;AAC/C,UAAI,CAAC,WAAW;AACd,aAAK,SAAS,KAAK,KAAK,EAAE,OAAO,iCAAiC,CAAC;AACnE;AAAA,MACF;AAEA,YAAM,WAAWF,YAAW,UAAU,KAAK,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;AAC5E,YAAM,cAAc,OAAO,KAAK,UAAU,OAAO;AACjD,YAAM,YAAY,OAAO,KAAK,WAAW,OAAO;AAChD,UAAI,YAAY,WAAW,UAAU,UAAU,CAAC,gBAAgB,aAAa,SAAS,GAAG;AACvF,aAAK,SAAS,KAAK,KAAK,EAAE,OAAO,oBAAoB,CAAC;AACtD;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AACN,WAAK,SAAS,KAAK,KAAK,EAAE,OAAO,eAAe,CAAC;AACjD;AAAA,IACF;AAEA,UAAM,QAA8B;AAAA,MAClC,IAAI,OAAO,OAAO,OAAO,WAAW,OAAO,KAAK;AAAA,MAChD,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;AAAA,MAC5D,OAAO,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAAA,MACzD,SAAU,OAAO,WAAmD;AAAA,MACpE,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC;AAIA,UAAM,KAAK,cAAc,YAAY;AACnC,YAAMC,YAAW,KAAK,YAAY,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM,OAAO;AAAA,IACzE,CAAC;AAGD,SAAK,QAAQ,KAAK;AAElB,SAAK,SAAS,KAAK,KAAK,EAAE,IAAI,MAAM,IAAI,MAAM,GAAG,CAAC;AAAA,EACpD;AAAA,EAEQ,SAAS,KAA8C;AAC7D,WAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,YAAM,SAAmB,CAAC;AAC1B,UAAI,OAAO;AAEX,UAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,gBAAQ,MAAM;AACd,YAAI,OAAO,eAAe;AACxB,UAAAA,SAAQ,IAAI;AACZ,cAAI,QAAQ;AACZ;AAAA,QACF;AACA,eAAO,KAAK,KAAK;AAAA,MACnB,CAAC;AAED,UAAI,GAAG,OAAO,MAAM;AAClB,QAAAA,SAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,OAAO,CAAC;AAAA,MACjD,CAAC;AAED,UAAI,GAAG,SAAS,MAAMA,SAAQ,IAAI,CAAC;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEQ,SAAS,KAAqB,QAAgB,MAAqB;AACzE,QAAI,UAAU,QAAQ,EAAE,gBAAgB,mBAAmB,CAAC;AAC5D,QAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAiB,IAAkC;AAE/D,UAAM,UAAU,KAAK;AACrB,QAAI,cAA0B,MAAM;AAAA,IAAC;AACrC,SAAK,YAAY,IAAI,QAAQ,CAAC,MAAM;AAClC,oBAAc;AAAA,IAChB,CAAC;AAED,QAAI;AAEF,YAAM;AACN,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AAEA,kBAAY;AAAA,IACd;AAAA,EACF;AACF;;;Ad1JO,IAAM,mBAAN,MAAuB;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT,gBAAsC;AAAA,EACtC,aAAgC;AAAA,EAChC,gBAAsC;AAAA,EACtC,cAAkC;AAAA,EAClC,gBAAsC;AAAA,EACtC,gBAAsC;AAAA,EACtC,YAAY;AAAA,EAEpB,YAAY,SAAkC;AAC5C,SAAK,OAAO,QAAQ;AACpB,SAAK,SAAS,QAAQ;AACtB,SAAK,MAAM,iBAAiB,QAAQ,IAAI;AACxC,SAAK,0BAA0B,QAAQ;AACvC,SAAK,aAAa,QAAQ;AAAA,EAC5B;AAAA,EAEA,MAAM,QAAuB;AAE3B,UAAMC,OAAM,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;AAGzC,UAAM,WAAWC,OAAK,KAAK,KAAK,KAAK,aAAa;AAClD,UAAM,KAAK,YAAY,QAAQ;AAG/B,UAAM,gBAAgB,MAAM,KAAK,UAAU;AAC3C,QAAI,eAAe,aAAa,cAAc,WAAW,WAAW;AAClE,WAAK,YAAY,cAAc;AAAA,IACjC,OAAO;AACL,WAAK,YAAYC,aAAW;AAAA,IAC9B;AAGA,SAAK,cAAc,IAAI,YAAY,KAAK,GAAG;AAG3C,SAAK,gBAAgB,IAAI,cAAc,2BAA2B,KAAK,IAAI,CAAC;AAG5E,SAAK,aAAa,IAAI,WAAW;AAAA,MAC/B,iBAAiB,KAAK,OAAO,WAAW;AAAA,IAC1C,CAAC;AAGD,UAAM,YAAYD,OAAK,KAAK,KAAK,KAAK,aAAa;AACnD,UAAM,aAAaA,OAAK,KAAK,KAAK,KAAK,cAAc;AACrD,UAAM,KAAK,WAAW,kBAAkB,WAAW,UAAU;AAG7D,UAAM,KAAK,WAAW,cAAc,WAAW,UAAU;AAGzD,SAAK,gBAAgB,IAAI,cAAc;AAAA,MACrC,MAAM,KAAK,OAAO,WAAW;AAAA,MAC7B,QAAQ,KAAK,OAAO,WAAW;AAAA,MAC/B;AAAA,MACA,SAAS,CAAC,UAAU;AAClB,aAAK,YAAY,KAAK,EAAE,MAAM,WAAW,MAAM,MAAM,CAAC;AAGtD,aAAK,qBAAqB,KAAK,EAAE,MAAM,CAAC,QAAQ;AAC9C,eAAK,aAAa;AAAA,YAChB;AAAA,YACA,qCAAqC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UACvF;AAAA,QACF,CAAC;AAID,aACG,MAAM,UAAU,sBAAsB,MAAM,UAAU,mBACvD,MAAM,SACN;AACA,gBAAM,QAAQ,OAAO,MAAM,QAAQ,UAAU,WAAW,MAAM,QAAQ,QAAQ;AAC9E,cAAI,OAAO;AACT,iBAAK,YAAY,KAAK;AAAA,cACpB,MAAM;AAAA,cACN;AAAA,cACA,WAAW,MAAM;AAAA,YACnB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,MACA,WAAW,MAAM,KAAK,cAAc;AAAA,IACtC,CAAC;AACD,UAAM,KAAK,cAAc,MAAM;AAG/B,UAAM,KAAK,WAAW;AAAA,MACpB,KAAK,QAAQ;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,MAAM,KAAK,OAAO,WAAW;AAAA,MAC7B,KAAKE,SAAQ;AAAA,MACb,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,eAAe,eAAe;AAAA,MAC9B,gBAAgB,eAAe,kBAAkB;AAAA,MACjD,cAAc,eAAe,gBAAgB;AAAA,MAC7C,cAAc,eAAe,gBAAgB;AAAA,MAC7C,eAAe,eAAe;AAAA,MAC9B,eAAe,eAAe,iBAAiB;AAAA,MAC/C,qBAAqB,eAAe,uBAAuB;AAAA,MAC3D,QAAQ;AAAA,MACR,4BAA4B,eAAe,8BAA8B;AAAA,MACzE,yBAAyB,eAAe,2BAA2B;AAAA,MACnE,4BAA4B,eAAe;AAAA,IAC7C,CAAC;AAGD,UAAM,WAAW,MAAM;AAErB,WAAK,KAAK,EAAE,MAAM,QAAQ,KAAK;AAAA,IACjC;AACA,YAAQ,GAAG,WAAW,QAAQ;AAC9B,YAAQ,GAAG,UAAU,QAAQ;AAE7B,UAAM,KAAK,YAAY;AAAA,MACrB;AAAA,MACA,eAAe,KAAK,IAAI,qBAAqB,KAAK,OAAO,WAAW,IAAI;AAAA,IAC1E;AAGA,SAAK,gBAAgB,IAAI,cAAc;AAAA,MACrC,WAAW,CAAC,YAAY;AACtB,aAAK,YAAY,KAAK;AAAA,UACpB,MAAM;AAAA,UACN;AAAA,UACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,MACA,kBAAkB,0BAA0B,KAAK,IAAI;AAAA,IACvD,CAAC;AAGD,UAAM,YAAYF,OAAK,KAAK,KAAK,KAAK,YAAY;AAClD,UAAM,iBAAiBA,OAAK,KAAK,KAAK,KAAK,kBAAkB;AAC7D,SAAK,gBAAgB,IAAI,cAAc;AAAA,MACrC,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,MACpB;AAAA,MACA,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB;AAAA,MACA,yBAAyB,KAAK;AAAA,MAC9B,eAAe,KAAK;AAAA,MACpB,YAAY,KAAK;AAAA,MACjB,gBAAgB,KAAK;AAAA,MACrB;AAAA,IACF,CAAC;AAED,UAAM,KAAK,cAAc,MAAM;AAAA,EACjC;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,eAAe,KAAK;AACzB,SAAK,YAAY,aAAa;AAE9B,QAAI,KAAK,eAAe;AACtB,YAAM,KAAK,cAAc,KAAK;AAAA,IAChC;AAGA,UAAM,QAAQ,MAAM,KAAK,UAAU;AACnC,QAAI,OAAO;AACT,YAAM,SAAS;AACf,YAAM,KAAK,WAAW,KAAK;AAAA,IAC7B;AAGA,UAAM,WAAWA,OAAK,KAAK,KAAK,KAAK,aAAa;AAClD,UAAMG,IAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAElC,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,IAAI,SAAS,eAAe,KAAK,IAAI,WAAW;AAAA,IACzE;AAAA,EACF;AAAA,EAEQ,gBAAyC;AAC/C,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,MAAM,KAAK;AAAA,MACX,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ,OAAO;AAAA,MACvB,WAAW,KAAK;AAAA,MAChB,MAAM,KAAK,OAAO,WAAW;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAc,YAAmD;AAC/D,UAAM,YAAYH,OAAK,KAAK,KAAK,KAAK,YAAY;AAClD,QAAI;AACF,YAAM,MAAM,MAAMI,WAAS,WAAW,OAAO;AAC7C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,YAAM,SAAS,4BAA4B,UAAU,MAAM;AAC3D,UAAI,CAAC,OAAO,SAAS;AACnB,gBAAQ,MAAM,4CAA4C,OAAO,MAAM,OAAO,EAAE;AAChF,eAAO;AAAA,MACT;AACA,aAAO,OAAO;AAAA,IAChB,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,4CAA4C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC9F;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,OAA6C;AACpE,UAAM,YAAYJ,OAAK,KAAK,KAAK,KAAK,YAAY;AAClD,UAAM,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC;AAG7C,UAAM,WAAW,GAAG,SAAS,IAAI,QAAQ,GAAG;AAC5C,UAAMK,WAAU,UAAU,SAAS,OAAO;AAC1C,UAAMC,QAAO,UAAU,SAAS;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,YAAY,UAAiC;AACzD,UAAM,aAAa,YAA8B;AAC/C,UAAI,SAAkD;AACtD,UAAI;AACF,iBAAS,MAAM;AAAA,UACb;AAAA,UACA,UAAU,WAAW,UAAU,UAAU,UAAU;AAAA,UACnD;AAAA,QACF;AACA,cAAM,OAAO,MAAM,OAAO,QAAQ,GAAG,GAAG,GAAG,OAAO;AAClD,cAAM,OAAO,MAAM;AACnB,iBAAS;AACT,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,YAAK,IAA8B,SAAS,UAAU;AACpD,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR,UAAE;AAEA,YAAI,QAAQ;AACV,gBAAM,OAAO,MAAM,EAAE,MAAM,CAAC,QAAQ;AAElC,oBAAQ,MAAM,8CAA8C,GAAG,EAAE;AAAA,UACnE,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM,WAAW,GAAG;AACtB;AAAA,IACF;AAGA,UAAM,UAAU,MAAM,KAAK,YAAY,QAAQ;AAC/C,QAAI,WAAW,eAAe,OAAO,GAAG;AACtC,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,IAAI,0BAA0B,OAAO;AAAA,MAC3D;AAAA,IACF;AAQA,UAAMH,IAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAGlC,QAAI,MAAM,WAAW,GAAG;AACtB;AAAA,IACF;AAGA,UAAM,WAAW,MAAM,KAAK,YAAY,QAAQ;AAChD,UAAM,IAAI;AAAA,MACR,eAAe,KAAK,IAAI,0BAA0B,YAAY,SAAS;AAAA,IACzE;AAAA,EACF;AAAA,EAEA,MAAc,YAAY,UAA0C;AAClE,QAAI;AACF,YAAM,MAAM,MAAMC,WAAS,UAAU,OAAO;AAC5C,YAAM,MAAM,OAAO,SAAS,IAAI,KAAK,GAAG,EAAE;AAC1C,aAAO,OAAO,MAAM,GAAG,IAAI,OAAO;AAAA,IACpC,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,mDAAmD,QAAQ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAClH;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,qBAAqB,OAA4C;AAC7E,QAAI,MAAM,UAAU,kBAAmB;AACvC,QAAI,CAAC,KAAK,iBAAiB,CAAC,MAAM,QAAS;AAE3C,UAAM,aACJ,OAAO,MAAM,QAAQ,eAAe,WAAW,MAAM,QAAQ,aAAa;AAC5E,UAAM,SAAS,OAAO,MAAM,QAAQ,WAAW,WAAW,MAAM,QAAQ,SAAS;AAEjF,QAAI,CAAC,cAAc,CAAC,QAAQ;AAC1B,YAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,gEAAgE,UAAU,aAAa,MAAM;AAAA,MAC/F;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,cAAc,OAAO,YAAY,MAAM;AAClD,YAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,YAAY,UAAU,2BAA2B,MAAM;AAAA,MACzD;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,6BAA6B,UAAU,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC9F;AAAA,IACF;AAAA,EACF;AACF;;;AevXA,SAAS,cAAAG,oBAAkB;;;ACA3B,SAAS,KAAAC,WAAS;AAIX,IAAM,uBAAuBA,IAAE,OAAO;AAAA,EAC3C,WAAWA,IAAE,OAAO;AAAA,EACpB,KAAKA,IAAE,QAAQ;AAAA,EACf,UAAUA,IAAE,OAAO;AACrB,CAAC;AAEM,IAAM,2BAA2BA,IAAE,OAAO;AAAA,EAC/C,SAASA,IAAE,OAAO;AAAA,EAClB,UAAUA,IAAE,MAAMA,IAAE,OAAO,CAAC,EAAE,IAAI,GAAG,yCAAyC;AAAA,EAC9E,QAAQA,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,iBAAiBA,IAAE,MAAM,oBAAoB;AAC/C,CAAC;AAEM,IAAM,0BAA0BA,IAAE,OAAO;AAAA,EAC9C,QAAQA,IAAE,OAAO;AAAA,EACjB,UAAUA,IAAE,OAAO;AAAA,EACnB,SAASA,IAAE,OAAO;AAAA,EAClB,SAASA,IAAE,KAAK,CAAC,OAAO,MAAM,CAAC;AACjC,CAAC;AAgBM,IAAM,2BAA2C;AAAA,EACtD,MAAM;AAAA,EACN,aACE;AAAA,EAEF,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,SAAS,EAAE,MAAM,UAAU,aAAa,wBAAwB;AAAA,MAChE,UAAU;AAAA,QACR,MAAM;AAAA,QACN,OAAO,EAAE,MAAM,SAAS;AAAA,QACxB,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA,QAAQ,EAAE,MAAM,UAAU,aAAa,4BAA4B;AAAA,MACnE,iBAAiB;AAAA,QACf,MAAM;AAAA,QACN,OAAO;AAAA,UACL,MAAM;AAAA,UACN,YAAY;AAAA,YACV,WAAW,EAAE,MAAM,SAAS;AAAA,YAC5B,KAAK,EAAE,MAAM,UAAU;AAAA,YACvB,UAAU,EAAE,MAAM,SAAS;AAAA,UAC7B;AAAA,UACA,UAAU,CAAC,aAAa,OAAO,UAAU;AAAA,QAC3C;AAAA,QACA,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,WAAW,YAAY,iBAAiB;AAAA,EACrD;AACF;AAEO,IAAM,0BAA0C;AAAA,EACrD,MAAM;AAAA,EACN,aACE;AAAA,EAEF,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,QAAQ,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,MAChE,UAAU,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,MACxE,SAAS,EAAE,MAAM,UAAU,aAAa,oCAAoC;AAAA,MAC5E,SAAS,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,MAAM,EAAE;AAAA,IACnD;AAAA,IACA,UAAU,CAAC,UAAU,YAAY,WAAW,SAAS;AAAA,EACvD;AACF;;;ADxDO,IAAM,cAAN,MAAkB;AAAA,EACN;AAAA,EACT,WAAW;AAAA,EACX,kBAA4B,CAAC;AAAA,EAErC,YAAY,SAA6B;AACvC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,cAAc,SAAuB;AACnC,SAAK,gBAAgB,KAAK,OAAO;AAAA,EACnC;AAAA;AAAA,EAGA,OAAa;AACX,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAA4B;AAChC,QAAI,KAAK,SAAU,QAAO;AAE1B,UAAM,EAAE,cAAc,WAAW,oBAAoB,SAAS,MAAM,IAAI,KAAK;AAE7E,UAAM,oBAAoB,MAAM,MAAM,aAAa,YAAY;AAC/D,QAAI,mBAAmB;AACrB,cAAQ,eAAe,EAAE,UAAU,UAAU,WAAW,kBAAkB,CAAC;AAAA,IAC7E;AAEA,UAAM,iBAAiB,MAAM,MAAM,kBAAkB,cAAc,EAAE;AACrE,UAAM,WAAW,KAAK,gBAAgB,OAAO,CAAC;AAE9C,UAAM,SAAS,mBAAmB;AAAA,MAChC;AAAA,MACA;AAAA,MACA,gBAAgB,eAAe,IAAI,CAAC,MAAM,EAAE,OAAO;AAAA,MACnD,iBAAiB;AAAA,IACnB,CAAC;AAED,UAAM,eAAe;AAAA,MACnB;AAAA,MACA,OAAO,CAAC,0BAA0B,uBAAuB;AAAA,MACzD,GAAI,KAAK,QAAQ,iBAAiB,UAAa,EAAE,cAAc,KAAK,QAAQ,aAAa;AAAA,IAC3F;AAEA,qBAAiB,WAAW,QAAQ,MAAM,YAAY,GAAG;AACvD,YAAM,SAAS,QAAQ,iBAAiB;AACxC,UAAI,QAAQ,aAAa,UAAU;AACjC,cAAM,MAAM,cAAc,cAAc,OAAO,SAAS;AAAA,MAC1D;AAEA,UAAI,QAAQ,SAAS,YAAY;AAC/B,cAAM,WAAW,MAAM,KAAK,cAAc,QAAQ,UAAU,QAAQ,SAAS;AAC7E,YAAI,SAAU,QAAO;AAAA,MACvB,WAAW,QAAQ,SAAS,UAAU,QAAQ,MAAM;AAClD,cAAM,MAAM,eAAe,cAAc;AAAA,UACvC,IAAIC,aAAW;AAAA,UACf,MAAM;AAAA,UACN,SAAS,QAAQ,KAAK,MAAM,GAAG,GAAG;AAAA,UAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,KAAK,QAAQ,WAAW,iBAAiB,CAAC;AAChD,WAAO,CAAC,KAAK;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAqB;AACzB,UAAM,SAAS,KAAK,QAAQ,kBAAkB;AAE9C,WAAO,CAAC,KAAK,UAAU;AACrB,YAAM,iBAAiB,MAAM,KAAK,QAAQ;AAC1C,UAAI,CAAC,eAAgB;AACrB,UAAI,SAAS,EAAG,OAAM,MAAM,MAAM;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,MAAc,cAAc,UAA8B,WAAsC;AAC9F,UAAM,EAAE,cAAc,MAAM,IAAI,KAAK;AAErC,QAAI,aAAa,uBAAuB;AACtC,YAAM,SAAS,yBAAyB,UAAU,SAAS;AAC3D,UAAI,OAAO,SAAS;AAClB,cAAM,MAAM,eAAe,cAAc;AAAA,UACvC,IAAIA,aAAW;AAAA,UACf,MAAM;AAAA,UACN,SAAS,wBAAwB,OAAO,KAAK,OAAO;AAAA,UACpD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AACD,cAAM,KAAK,QAAQ,WAAW,OAAO,IAAI;AACzC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,aAAa,sBAAsB;AACrC,YAAM,SAAS,wBAAwB,UAAU,SAAS;AAC1D,UAAI,OAAO,SAAS;AAClB,cAAM,MAAM,eAAe,cAAc;AAAA,UACvC,IAAIA,aAAW;AAAA,UACf,MAAM;AAAA,UACN,SAAS,uBAAuB,OAAO,KAAK,MAAM;AAAA,UAClD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,CAAC;AACD,cAAM,KAAK,QAAQ,UAAU,OAAO,IAAI;AACxC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAIA,SAAS,mBAAmB,MAKjB;AACT,QAAM,WACJ,KAAK,mBAAmB,SAAS,IAC7B,KAAK,mBAAmB,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,IACtD;AAEN,QAAM,WACJ,KAAK,eAAe,SAAS,IACzB,KAAK,eAAe,MAAM,GAAG,EAAE,KAAK,IAAI,IACxC;AAEN,QAAM,WACJ,KAAK,gBAAgB,SAAS,IAC1B;AAAA;AAAA,EAAyC,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAAA,IACxE;AAEN,SAAO;AAAA,EACP,KAAK,SAAS;AAAA;AAAA;AAAA,EAGd,QAAQ;AAAA;AAAA;AAAA,EAGR,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAMV;;;AE/LA,SAAS,cAAAC,cAAY,gBAAAC,qBAAoB;AACzC,SAAS,WAAAC,UAAS,YAAAC,kBAAgB;AAClC,OAAOC,YAAU;AAWjB,IAAM,aAAa;AACnB,IAAMC,iBAAgB;AAMf,IAAM,eAAN,MAAmB;AAAA,EACf;AAAA,EACQ;AAAA,EACA;AAAA,EAEjB,YAAY,SAAiB;AAC3B,SAAK,UAAU;AACf,SAAK,YAAYC,OAAK,KAAK,SAAS,UAAU;AAC9C,SAAK,eAAeA,OAAK,KAAK,SAASD,cAAa;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAA8C;AAClD,QAAI;AACJ,QAAI;AACF,YAAM,MAAME,WAAS,KAAK,WAAW,OAAO;AAAA,IAC9C,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC1F;AACA,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,GAAG;AAAA,IACzB,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC1F;AACA,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,4BAA4B,UAAU,MAAM;AAC3D,QAAI,CAAC,OAAO,SAAS;AAEnB,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,OAAO;AAGtB,UAAM,YAAiF;AAAA,MACrF,SAAS;AAAA,MACT,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAGA,UAAM,iBAAiB,KAAK,cAAc,EAAE,OAAO,EAAE,CAAC;AAGtD,UAAM,iBAAiB,MAAM,KAAK,gBAAgB;AAElD,WAAO;AAAA,MACL,KAAK,OAAO;AAAA,MACZ,WAAW,OAAO;AAAA,MAClB,WAAW,OAAO;AAAA,MAClB,gBAAgB,OAAO;AAAA,MACvB,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,MACrB,QAAQ,UAAU,OAAO,MAAM;AAAA,MAC/B,eAAe,OAAO,iBAAiB,OAAO;AAAA,MAC9C;AAAA,MACA,uBAAuB,eAAe,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,KAAK,EAAE,OAAO,EAAE;AAAA,IAC7E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,UAAgC,CAAC,GAAoB;AACjE,UAAM,EAAE,QAAQ,IAAI,SAAS,GAAG,MAAM,OAAO,MAAM,IAAI;AAEvD,QAAI;AACJ,QAAI;AACF,gBAAUC,cAAa,KAAK,cAAc,OAAO;AAAA,IACnD,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC7F;AACA,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACvD,QAAI,UAA2B,CAAC;AAGhC,eAAW,QAAQ,OAAO;AACxB,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,cAAM,SAAS,oBAAoB,UAAU,MAAM;AACnD,YAAI,OAAO,SAAS;AAClB,kBAAQ,KAAK,OAAO,IAAI;AAAA,QAC1B;AAAA,MACF,SAAS,KAAK;AAEZ,gBAAQ;AAAA,UACN,oDAAoD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACtG;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM;AACR,gBAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,IACjD;AAGA,QAAI,OAAO;AACT,YAAM,YAAY,IAAI,KAAK,KAAK;AAChC,gBAAU,QAAQ,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,SAAS,KAAK,SAAS;AAAA,IACpE;AAEA,QAAI,OAAO;AACT,YAAM,YAAY,IAAI,KAAK,KAAK;AAChC,gBAAU,QAAQ,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,SAAS,KAAK,SAAS;AAAA,IACpE;AAGA,WAAO,QAAQ,MAAM,QAAQ,SAAS,KAAK;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBAAmC;AAC/C,UAAM,UAAU,WAAW;AAC3B,QAAI,CAACC,aAAW,OAAO,EAAG,QAAO;AAEjC,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,gBAAgB,OAAO;AACnD,UAAI,QAAQ;AACZ,iBAAW,YAAY,UAAU;AAC/B,YAAI,MAAM,KAAK,UAAU,QAAQ,EAAG;AAAA,MACtC;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,+CAA+C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACjG;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAAgB,SAAoC;AAChE,UAAM,UAAU,MAAMC,SAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,UAAM,YAAsB,CAAC;AAE7B,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,YAAY,GAAG;AACvB,cAAM,SAASJ,OAAK,KAAK,SAAS,MAAM,IAAI;AAC5C,cAAM,WAAW,MAAMI,SAAQ,MAAM;AACrC,mBAAW,KAAK,UAAU;AACxB,cAAI,KAAK,UAAU,CAAC,GAAG;AACrB,sBAAU,KAAKJ,OAAK,KAAK,QAAQ,CAAC,CAAC;AAAA,UACrC;AAAA,QACF;AAAA,MACF,WAAW,KAAK,UAAU,MAAM,IAAI,GAAG;AACrC,kBAAU,KAAKA,OAAK,KAAK,SAAS,MAAM,IAAI,CAAC;AAAA,MAC/C;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,UAA2B;AAC3C,WAAO,SAAS,SAAS,OAAO,KAAK,CAAC,SAAS,SAAS,gBAAgB;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,UAAU,UAAoC;AAC1D,QAAI;AACF,YAAM,UAAU,MAAMC,WAAS,UAAU,OAAO;AAChD,YAAM,MAAM,KAAK,MAAM,OAAO;AAC9B,aAAO,IAAI,WAAW;AAAA,IACxB,SAAS,KAAK;AAEZ,cAAQ;AAAA,QACN,0CAA0C,QAAQ,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACzG;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC7NA,SAAS,cAAAI,oBAAkB;AAC3B,SAAS,WAAAC,UAAS,YAAAC,YAAU,aAAAC,mBAAiB;AAC7C,OAAOC,YAAU;;;ACHjB,SAAS,KAAAC,WAAS;AAKX,IAAM,kCAAkCA,IAAE,OAAO;AAAA,EACtD,WAAWA,IAAE,OAAO,EAAE,IAAI,GAAG,uBAAuB;AAAA,EACpD,oBAAoBA,IAAE,MAAMA,IAAE,OAAO,CAAC,EAAE,IAAI,GAAG,4CAA4C;AAAA,EAC3F,YAAYA,IAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC7C,CAAC;AAMM,IAAM,8BAA8C;AAAA,EACzD,MAAM;AAAA,EACN,aACE;AAAA,EAGF,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,oBAAoB;AAAA,QAClB,MAAM;AAAA,QACN,OAAO,EAAE,MAAM,SAAS;AAAA,QACxB,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA,YAAY;AAAA,QACV,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,aAAa,oBAAoB;AAAA,EAC9C;AACF;;;ACzCA,SAAS,cAAAC,cAAY,SAAAC,QAAO,YAAAC,YAAU,aAAAC,mBAAiB;AACvD,OAAOC,YAAU;AAeV,IAAM,uBAAN,MAAsD;AAAA,EAC1C;AAAA;AAAA,EAET,YAA2B,QAAQ,QAAQ;AAAA,EAEnD,YAAY,SAAiB;AAC3B,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAiB,IAAkC;AAE/D,UAAM,UAAU,KAAK;AACrB,QAAI,cAA0B,MAAM;AAAA,IAAC;AACrC,SAAK,YAAY,IAAI,QAAQ,CAAC,MAAM;AAClC,oBAAc;AAAA,IAChB,CAAC;AAED,QAAI;AAEF,YAAM;AACN,aAAO,MAAM,GAAG;AAAA,IAClB,UAAE;AAEA,kBAAY;AAAA,IACd;AAAA,EACF;AAAA,EAEQ,cAAc,cAA8B;AAClD,WAAOA,OAAK,KAAK,KAAK,SAAS,YAAY;AAAA,EAC7C;AAAA,EAEA,MAAc,UAAU,cAAuC;AAC7D,UAAM,MAAM,KAAK,cAAc,YAAY;AAC3C,UAAMH,OAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,MAAM,aAAa,cAAmD;AACpE,UAAM,cAAcG,OAAK,KAAK,KAAK,cAAc,YAAY,GAAG,cAAc;AAC9E,QAAI;AACF,YAAM,MAAM,MAAMF,WAAS,aAAa,OAAO;AAC/C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,aAAO,OAAO;AAAA,IAChB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,cAAsB,WAAkC;AAC1E,UAAM,MAAM,MAAM,KAAK,UAAU,YAAY;AAC7C,UAAMC,YAAUC,OAAK,KAAK,KAAK,cAAc,GAAG,KAAK,UAAU,EAAE,UAAU,CAAC,GAAG,OAAO;AAAA,EACxF;AAAA;AAAA,EAIA,MAAM,eAAe,cAAsB,OAAqC;AAC9E,UAAM,MAAM,MAAM,KAAK,UAAU,YAAY;AAC7C,UAAM,KAAK,cAAc,YAAY;AACnC,YAAMJ,aAAWI,OAAK,KAAK,KAAK,gBAAgB,GAAG,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,GAAM,OAAO;AAAA,IAC1F,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,kBAAkB,cAAsB,QAAQ,IAA8B;AAClF,UAAM,eAAeA,OAAK,KAAK,KAAK,cAAc,YAAY,GAAG,gBAAgB;AACjF,QAAI;AACF,YAAM,MAAM,MAAMF,WAAS,cAAc,OAAO;AAChD,YAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AACnD,YAAM,OAAO,MAAM,MAAM,CAAC,KAAK;AAC/B,aAAO,KAAK,QAAQ,CAAC,SAAS;AAC5B,YAAI;AACF,iBAAO,CAAC,KAAK,MAAM,IAAI,CAAkB;AAAA,QAC3C,QAAQ;AACN,iBAAO,CAAC;AAAA,QACV;AAAA,MACF,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,SAAS,cAA8D;AAC3E,UAAM,YAAYE,OAAK,KAAK,KAAK,cAAc,YAAY,GAAG,YAAY;AAC1E,QAAI;AACF,YAAM,MAAM,MAAMF,WAAS,WAAW,OAAO;AAC7C,aAAO,KAAK,MAAM,GAAG;AAAA,IACvB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,cAAsB,OAA8C;AAClF,UAAM,MAAM,MAAM,KAAK,UAAU,YAAY;AAC7C,UAAMC,YAAUC,OAAK,KAAK,KAAK,YAAY,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,EACvF;AAAA;AAAA,EAIA,MAAM,WAAW,cAAsB,SAAgC;AACrE,UAAM,KAAK,cAAc,YAAY;AACnC,YAAM,UAAU,MAAM,KAAK,aAAa,YAAY;AACpD,YAAM,MAAM,MAAM,KAAK,UAAU,YAAY;AAC7C,YAAMD;AAAA,QACJC,OAAK,KAAK,KAAK,WAAW;AAAA,QAC1B,KAAK,UAAU,EAAE,cAAc,UAAU,QAAQ,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,cAAuC;AACxD,UAAM,WAAWA,OAAK,KAAK,KAAK,cAAc,YAAY,GAAG,WAAW;AACxE,QAAI;AACF,YAAM,MAAM,MAAMF,WAAS,UAAU,OAAO;AAC5C,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,aAAO,OAAO;AAAA,IAChB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC/IA,SAAS,cAAAG,oBAAkB;AAC3B,SAAS,SAAAC,SAAO,YAAAC,YAAU,aAAAC,mBAAiB;AAC3C,OAAOC,YAAU;AACjB,SAAS,KAAAC,WAAS;AAKX,IAAM,qBAAqBC,IAAE,OAAO;AAAA,EACzC,KAAKA,IAAE,OAAO,EAAE,IAAI;AAAA,EACpB,QAAQA,IAAE,MAAMA,IAAE,OAAO,CAAC,EAAE,SAAS;AAAA,EACrC,QAAQA,IAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,WAAWA,IAAE,OAAO,EAAE,QAAQ,GAAI;AAAA,EAClC,WAAWA,IAAE,OAAO,EAAE,QAAQ,OAAM,oBAAI,KAAK,GAAE,YAAY,CAAC;AAC9D,CAAC;AAOD,IAAM,uBAAuBA,IAAE,OAAO;AAAA,EACpC,UAAUA,IAAE,MAAM,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAMD,SAAS,wBAAgC;AACvC,SAAOC,OAAK,KAAK,WAAW,GAAG,eAAe;AAChD;AAIA,eAAe,qBAA8C;AAC3D,QAAM,aAAa,sBAAsB;AAEzC,MAAI,CAACC,aAAW,UAAU,GAAG;AAC3B,WAAO,EAAE,UAAU,CAAC,EAAE;AAAA,EACxB;AAEA,QAAM,MAAM,MAAMC,WAAS,YAAY,OAAO;AAC9C,QAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,SAAO,qBAAqB,MAAM,MAAM;AAC1C;AAEA,eAAe,mBAAmB,QAAuC;AACvE,QAAM,aAAa,sBAAsB;AACzC,QAAMC,QAAM,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAC7C,QAAMC,YAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AACtE;AAQA,eAAsB,WAAW,OAAiD;AAChF,QAAM,SAAS,MAAM,mBAAmB;AACxC,QAAM,QAAQ,mBAAmB,MAAM,KAAK;AAE5C,QAAM,WAAW,OAAO,SAAS,UAAU,CAAC,MAAM,EAAE,QAAQ,MAAM,GAAG;AACrE,MAAI,YAAY,GAAG;AACjB,WAAO,SAAS,QAAQ,IAAI;AAAA,EAC9B,OAAO;AACL,WAAO,SAAS,KAAK,KAAK;AAAA,EAC5B;AAEA,QAAM,mBAAmB,MAAM;AAC/B,SAAO;AACT;AAMA,eAAsB,cAAc,KAA+B;AACjE,QAAM,SAAS,MAAM,mBAAmB;AACxC,QAAM,gBAAgB,OAAO,SAAS;AAEtC,SAAO,WAAW,OAAO,SAAS,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG;AAE7D,MAAI,OAAO,SAAS,WAAW,eAAe;AAC5C,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,MAAM;AAC/B,SAAO;AACT;AAKA,eAAsB,eAAwC;AAC5D,QAAM,SAAS,MAAM,mBAAmB;AACxC,SAAO,OAAO;AAChB;AAwBA,eAAsB,eAA6C;AACjE,QAAM,WAAW,MAAM,aAAa;AAEpC,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,UAA8B;AAAA,IAClC,MAAM;AAAA,IACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,OAAO,QAAQ,KAAK,IAAI,CAAC;AAAA,IACzB,QAAQ;AAAA,IACR,SAAS;AAAA,EACX;AAEA,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,SAAS,IAAI,OAAO,YAAwC;AAC1D,YAAM,QAAQ,KAAK,IAAI;AACvB,YAAM,OAAO,KAAK,UAAU,OAAO;AAEnC,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,QAAQ,KAAK;AAAA,UACxC,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,UAClB;AAAA,UACA;AAAA,UACA,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AAAA,QAC/C,CAAC;AAED,eAAO;AAAA,UACL,KAAK,QAAQ;AAAA,UACb,SAAS,SAAS;AAAA,UAClB,YAAY,SAAS;AAAA,UACrB,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B;AAAA,MACF,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,KAAK,QAAQ;AAAA,UACb,SAAS;AAAA,UACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,UACtD,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;;;AC1KO,IAAM,UAAU;","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","resolve","mkdir","existsSync","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","path","mkdir","writeFile","existsSync","readdir","readFile","readFile","path","z","randomUUID","existsSync","path","path","resolve","mkdir","randomUUID","strategy","existsSync","readdir","readFile","randomUUID","appendFile","readFile","stat","path","randomUUID","mkdir","readFile","writeFile","path","randomUUID","mkdir","readFile","rename","rm","writeFile","homedir","path","randomUUID","appendFile","readFile","rename","stat","writeFile","path","z","z","path","randomUUID","appendFile","stat","readFile","writeFile","rename","watch","readFile","writeFile","resolve","randomUUID","existsSync","readdir","readFile","writeFile","homedir","path","randomUUID","existsSync","mkdirSync","createRequire","path","z","esmRequire","rowToEntry","query","randomUUID","existsSync","mkdirSync","appendFile","readFile","rename","writeFile","path","z","appendFile","path","z","appendFile","readFile","rename","stat","writeFile","path","path","readFile","readFile","writeFile","rename","appendFile","PRIORITY_ORDER","z","z","path","randomUUID","homedir","resolve","readFile","writeFile","existsSync","readdir","createHmac","appendFile","resolve","mkdir","path","randomUUID","homedir","rm","readFile","writeFile","rename","randomUUID","z","randomUUID","existsSync","readFileSync","readdir","readFile","path","ACTIVITY_FILE","path","readFile","readFileSync","existsSync","readdir","existsSync","readdir","readFile","writeFile","path","z","appendFile","mkdir","readFile","writeFile","path","existsSync","mkdir","readFile","writeFile","path","z","z","path","existsSync","readFile","mkdir","writeFile"]}