aisnitch 0.2.21 โ†’ 0.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/aider.ts","../src/core/engine/logger.ts","../src/core/session-identity.ts","../src/adapters/base.ts","../src/core/errors.ts","../src/core/circuit-breaker.ts","../src/core/events/schema.ts","../src/core/events/factory.ts","../src/adapters/claude-code.ts","../src/adapters/copilot-cli.ts","../src/adapters/codex.ts","../src/adapters/cursor.ts","../src/adapters/devin.ts","../src/adapters/gemini-cli.ts","../src/adapters/goose.ts","../src/adapters/kilo.ts","../src/adapters/openclaw.ts","../src/adapters/opencode.ts","../src/adapters/pi.ts","../src/adapters/zed.ts","../src/adapters/registry.ts","../src/adapters/generic-pty.ts","../src/core/engine/context-detector.ts","../src/adapters/index.ts","../src/core/config/schema.ts","../src/core/config/defaults.ts","../src/core/config/loader.ts","../src/core/engine/event-bus.ts","../src/core/engine/ring-buffer.ts","../src/core/engine/ws-server.ts","../src/package-info.ts","../src/core/engine/http-receiver.ts","../src/core/engine/uds-server.ts","../src/core/engine/pipeline.ts","../src/core/events/cesp.ts","../src/core/timeout.ts","../src/core/graceful-shutdown.ts","../src/core/result.ts","../src/core/retry.ts","../src/core/safety.ts","../src/tui/index.tsx","../src/tui/App.tsx","../src/tui/components/EventInspector.tsx","../src/tui/event-details.ts","../src/tui/theme.ts","../src/tui/event-inspector.ts","../src/tui/components/EventStream.tsx","../src/tui/components/EventLine.tsx","../src/tui/components/FilterBar.tsx","../src/tui/filters.ts","../src/tui/components/Header.tsx","../src/tui/components/GlobalBadge.tsx","../src/tui/components/HelpOverlay.tsx","../src/tui/components/Layout.tsx","../src/tui/components/SessionPanel.tsx","../src/tui/components/StatusBar.tsx","../src/tui/hooks/useEventStream.ts","../src/tui/hooks/useKeyBinds.ts","../src/tui/hooks/useSessions.ts","../src/tui/ManagedDaemonApp.tsx","../src/tui/types.ts","../src/tui/live-monitor.ts"],"sourcesContent":["import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\nimport pidCwd from 'pid-cwd';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n AISnitchEventType,\n ErrorType,\n EventData,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/aider.ts\n * @description Aider adapter combining passive markdown history parsing, notifications-command hooks, and active process discovery.\n * @functions\n * โ†’ parseAiderHistoryMarkdown\n * @exports AiderAdapter, AiderAdapterOptions, AiderHistoryObservation, AiderHistoryParseResult, parseAiderHistoryMarkdown\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/03_adapters-secondary_aider-pty_DONE.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst DEFAULT_AIDER_HISTORY_FILE = '.aider.chat.history.md';\nconst AIDER_ERROR_HINT =\n /failed|error|exception|keyboardinterrupt|did not conform|traceback/iu;\nconst AIDER_ASKING_USER_HINT =\n /\\b\\(Y(?:es)?\\/N(?:o)?\\)|\\bPress Enter\\b|\\bcontinue\\?\\b|\\bcontinue to exit\\b/iu;\nconst AIDER_FILE_COMMAND_HINT = /^\\/(?:add|drop|read-only)\\b/iu;\nconst AIDER_STARTUP_STATUS_HINT =\n /^(?:\\/.+\\/aider|Aider v|Main model:|Model:|Weak model:|Git repo:|Repo-map:)/u;\n\nexport interface AiderAdapterOptions extends AdapterRuntimeOptions {\n readonly cwdResolver?: (pid: number) => Promise<string | undefined>;\n readonly historyFileName?: string;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface AiderProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface AiderSessionRuntime {\n readonly cwd: string;\n readonly historyPath: string;\n readonly pids: readonly number[];\n readonly sessionId: string;\n readonly model?: string;\n}\n\ninterface AiderHistoryWatcher {\n readonly fingerprints: Set<string>;\n readonly watcher: FSWatcher;\n}\n\ninterface AiderHistoryParseOptions {\n readonly cwd: string;\n readonly historyPath: string;\n readonly initialModel?: string;\n}\n\nexport interface AiderHistoryObservation {\n readonly fingerprint: string;\n readonly type: AISnitchEventType;\n readonly data: Omit<EventData, 'state'>;\n}\n\nexport interface AiderHistoryParseResult {\n readonly lastModel?: string;\n readonly observations: readonly AiderHistoryObservation[];\n}\n\n/**\n * ๐Ÿ“– Aider's transcript is markdown, not a stable machine API. The parser\n * therefore sticks to high-signal structures: prompts, quoted status lines,\n * assistant prose, and SEARCH/REPLACE file blocks.\n */\nexport class AiderAdapter extends BaseAdapter {\n public override readonly displayName = 'Aider';\n\n public override readonly name = 'aider' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'log-watch',\n 'process-detect',\n ];\n\n private readonly cwdResolver: (pid: number) => Promise<string | undefined>;\n\n private readonly historyFileName: string;\n\n private readonly historySessions = new Map<string, AiderSessionRuntime>();\n\n private readonly historyWatchers = new Map<string, AiderHistoryWatcher>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: AiderAdapterOptions) {\n super(options);\n this.cwdResolver =\n options.cwdResolver ??\n (async (pid) => {\n return await pidCwd(pid);\n });\n this.historyFileName = options.historyFileName ?? DEFAULT_AIDER_HISTORY_FILE;\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', '(^|[ /])aider([ ]|$)']).then(\n (result) => result.stdout,\n ));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startProcessPolling();\n\n return Promise.resolve();\n }\n\n public override async stop(): Promise<void> {\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n for (const watcherHandle of this.historyWatchers.values()) {\n await watcherHandle.watcher.close();\n }\n\n this.historySessions.clear();\n this.historyWatchers.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload === null) {\n logger.debug({ payload }, 'Aider ignores non-normalized hook payloads');\n return;\n }\n\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs > 0) {\n this.processPoller = setInterval(() => {\n void this.pollAiderProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n }\n\n void this.pollAiderProcesses();\n }\n\n private async pollAiderProcesses(): Promise<void> {\n const processes = await listAiderProcesses(this.processListCommand);\n const nextSessions = new Map<string, AiderSessionRuntime>();\n\n for (const processInfo of processes) {\n const cwd = await this.cwdResolver(processInfo.pid);\n\n if (!cwd) {\n continue;\n }\n\n const historyPath = resolveAiderHistoryPath(\n cwd,\n processInfo.command,\n this.historyFileName,\n );\n const existingSession = nextSessions.get(historyPath);\n\n if (existingSession) {\n nextSessions.set(historyPath, {\n ...existingSession,\n pids: [...existingSession.pids, processInfo.pid],\n });\n continue;\n }\n\n const previousSession = this.historySessions.get(historyPath);\n const sessionId =\n previousSession?.sessionId ??\n resolveSessionId({\n cwd,\n tool: this.name,\n transcriptPath: historyPath,\n });\n\n nextSessions.set(historyPath, {\n cwd,\n historyPath,\n model: previousSession?.model,\n pids: [processInfo.pid],\n sessionId,\n });\n }\n\n for (const [historyPath, session] of nextSessions) {\n if (this.historySessions.has(historyPath)) {\n this.historySessions.set(historyPath, session);\n continue;\n }\n\n this.historySessions.set(historyPath, session);\n await this.ensureHistoryWatcher(session);\n await this.emitHistoryEvent(\n session,\n 'session.start',\n {\n project: basename(session.cwd) || session.cwd,\n projectPath: session.cwd,\n raw: {\n historyPath,\n pids: session.pids,\n source: 'process-detect',\n },\n },\n {\n pid: session.pids[0],\n source: 'aisnitch://adapters/aider/process-detect',\n },\n );\n await this.emitHistoryEvent(\n session,\n 'agent.idle',\n {\n model: session.model,\n project: basename(session.cwd) || session.cwd,\n projectPath: session.cwd,\n raw: {\n historyPath,\n source: 'process-detect',\n },\n },\n {\n pid: session.pids[0],\n source: 'aisnitch://adapters/aider/process-detect',\n },\n );\n }\n\n for (const [historyPath, previousSession] of this.historySessions) {\n if (nextSessions.has(historyPath)) {\n continue;\n }\n\n await this.emitHistoryEvent(\n previousSession,\n 'session.end',\n {\n model: previousSession.model,\n project: basename(previousSession.cwd) || previousSession.cwd,\n projectPath: previousSession.cwd,\n raw: {\n historyPath,\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n pid: previousSession.pids[0],\n source: 'aisnitch://adapters/aider/process-detect',\n },\n );\n await this.releaseHistoryWatcher(historyPath);\n this.historySessions.delete(historyPath);\n }\n }\n\n private async ensureHistoryWatcher(\n session: AiderSessionRuntime,\n ): Promise<void> {\n if (this.historyWatchers.has(session.historyPath)) {\n return;\n }\n\n const fingerprintSet = new Set<string>();\n const seedResult = await readOptionalAiderHistory(session);\n\n if (seedResult !== null) {\n for (const observation of seedResult.observations) {\n fingerprintSet.add(observation.fingerprint);\n }\n\n if (seedResult.lastModel) {\n this.historySessions.set(session.historyPath, {\n ...session,\n model: seedResult.lastModel,\n });\n }\n }\n\n const watcher = this.watcherFactory(session.historyPath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n watcher.on('add', () => {\n void this.processHistoryUpdate(session.historyPath);\n });\n watcher.on('change', () => {\n void this.processHistoryUpdate(session.historyPath);\n });\n watcher.on('error', (error) => {\n logger.warn(\n {\n error,\n historyPath: session.historyPath,\n },\n 'Aider history watcher error',\n );\n });\n\n this.historyWatchers.set(session.historyPath, {\n fingerprints: fingerprintSet,\n watcher,\n });\n }\n\n private async processHistoryUpdate(historyPath: string): Promise<void> {\n const session = this.historySessions.get(historyPath);\n const watcherHandle = this.historyWatchers.get(historyPath);\n\n if (!session || !watcherHandle) {\n return;\n }\n\n const parseResult = await readOptionalAiderHistory(session);\n\n if (parseResult === null) {\n return;\n }\n\n if (parseResult.lastModel !== session.model) {\n this.historySessions.set(historyPath, {\n ...session,\n model: parseResult.lastModel,\n });\n }\n\n for (const observation of parseResult.observations) {\n if (watcherHandle.fingerprints.has(observation.fingerprint)) {\n continue;\n }\n\n watcherHandle.fingerprints.add(observation.fingerprint);\n await this.emitHistoryEvent(\n this.historySessions.get(historyPath) ?? session,\n observation.type,\n observation.data,\n {\n pid: session.pids[0],\n source: 'aisnitch://adapters/aider/history',\n },\n );\n }\n }\n\n private async emitHistoryEvent(\n session: AiderSessionRuntime,\n type: AISnitchEventType,\n data: Omit<EventData, 'state'>,\n context: Omit<AdapterPublishContext, 'sessionId' | 'cwd' | 'transcriptPath'>,\n ): Promise<void> {\n await this.emitStateChange(\n type,\n {\n cwd: session.cwd,\n model: data.model ?? session.model,\n project: data.project ?? (basename(session.cwd) || session.cwd),\n projectPath: data.projectPath ?? session.cwd,\n ...data,\n },\n {\n ...context,\n cwd: session.cwd,\n sessionId: session.sessionId,\n transcriptPath: session.historyPath,\n },\n );\n }\n\n private async releaseHistoryWatcher(historyPath: string): Promise<void> {\n const watcherHandle = this.historyWatchers.get(historyPath);\n\n if (!watcherHandle) {\n return;\n }\n\n await watcherHandle.watcher.close();\n this.historyWatchers.delete(historyPath);\n }\n}\n\n/**\n * Parses an aider markdown history file into normalized AISnitch observations.\n */\nexport function parseAiderHistoryMarkdown(\n markdown: string,\n options: AiderHistoryParseOptions,\n): AiderHistoryParseResult {\n const observations: AiderHistoryObservation[] = [];\n const lines = markdown.split(/\\r?\\n/u);\n let model = options.initialModel;\n\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index] ?? '';\n\n if (line.startsWith('# aider chat started at ')) {\n continue;\n }\n\n if (line.startsWith('#### ')) {\n const prompt = line.slice(5).trim();\n\n if (prompt.length === 0) {\n continue;\n }\n\n observations.push(createPromptObservation(prompt, index, {\n cwd: options.cwd,\n historyPath: options.historyPath,\n model,\n }));\n continue;\n }\n\n if (line.startsWith('>')) {\n const block = collectQuotedBlock(lines, index);\n const parsedBlock = parseQuotedOutputBlock(block.lines, {\n cwd: options.cwd,\n historyPath: options.historyPath,\n lineIndex: index,\n model,\n });\n\n observations.push(...parsedBlock.observations);\n model = parsedBlock.lastModel ?? model;\n index = block.nextIndex - 1;\n continue;\n }\n\n if (isAiderPatchBlockStart(lines, index)) {\n const patchBlock = collectPatchBlock(lines, index);\n observations.push(\n createCodingObservation(\n patchBlock.activeFile,\n patchBlock.body,\n index,\n {\n cwd: options.cwd,\n historyPath: options.historyPath,\n model,\n },\n ),\n );\n index = patchBlock.nextIndex - 1;\n continue;\n }\n\n if (line.trim().length === 0) {\n continue;\n }\n\n const proseBlock = collectProseBlock(lines, index);\n\n if (proseBlock.body.length > 0) {\n observations.push(\n createStreamingObservation(proseBlock.body, index, {\n cwd: options.cwd,\n historyPath: options.historyPath,\n model,\n }),\n );\n }\n\n index = proseBlock.nextIndex - 1;\n }\n\n return {\n lastModel: model,\n observations,\n };\n}\n\nasync function readOptionalAiderHistory(\n session: AiderSessionRuntime,\n): Promise<AiderHistoryParseResult | null> {\n try {\n const content = await readFile(session.historyPath, 'utf8');\n\n return parseAiderHistoryMarkdown(content, {\n cwd: session.cwd,\n historyPath: session.historyPath,\n initialModel: session.model,\n });\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return null;\n }\n\n throw error;\n }\n}\n\nfunction createPromptObservation(\n prompt: string,\n lineIndex: number,\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly model?: string;\n },\n): AiderHistoryObservation {\n if (prompt.startsWith('/')) {\n const slashCommand = parseAiderSlashCommand(prompt);\n\n return {\n data: {\n activeFile: slashCommand.filePath,\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n prompt,\n source: 'history-markdown',\n },\n toolInput: slashCommand.filePath\n ? {\n filePath: slashCommand.filePath,\n }\n : {\n command: prompt,\n },\n toolName: `aider:${slashCommand.name}`,\n },\n fingerprint: createHistoryFingerprint(\n 'agent.tool_call',\n lineIndex,\n prompt,\n slashCommand.filePath,\n ),\n type: 'agent.tool_call',\n };\n }\n\n return {\n data: {\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n prompt,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint('task.start', lineIndex, prompt),\n type: 'task.start',\n };\n}\n\nfunction parseQuotedOutputBlock(\n quotedLines: readonly string[],\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly lineIndex: number;\n readonly model?: string;\n },\n): AiderHistoryParseResult {\n const observations: AiderHistoryObservation[] = [];\n let lastModel = context.model;\n const leftoverLines: string[] = [];\n\n for (let offset = 0; offset < quotedLines.length; offset += 1) {\n const rawLine = quotedLines[offset] ?? '';\n const line = rawLine.trim();\n\n if (line.length === 0) {\n continue;\n }\n\n const parsedModel = parseAiderModelLine(line);\n\n if (parsedModel) {\n lastModel = parsedModel;\n continue;\n }\n\n if (AIDER_STARTUP_STATUS_HINT.test(line)) {\n continue;\n }\n\n const tokenCount = parseAiderTokenUsage(line);\n\n if (tokenCount !== undefined) {\n observations.push({\n data: {\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n tokensUsed: tokenCount,\n },\n fingerprint: createHistoryFingerprint(\n 'agent.thinking',\n context.lineIndex + offset,\n line,\n ),\n type: 'agent.thinking',\n });\n continue;\n }\n\n const addedFileMatch = line.match(/^Added\\s+(.+?)\\s+to the chat$/u);\n\n if (addedFileMatch) {\n const addedFile = addedFileMatch[1]?.trim();\n\n if (addedFile) {\n observations.push({\n data: {\n activeFile: addedFile,\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n toolInput: {\n filePath: addedFile,\n },\n toolName: 'aider:/add',\n },\n fingerprint: createHistoryFingerprint(\n 'agent.tool_call',\n context.lineIndex + offset,\n line,\n addedFile,\n ),\n type: 'agent.tool_call',\n });\n continue;\n }\n }\n\n const appliedEditMatch = line.match(\n /^(?:Applied|Updated|Edited|Created|Wrote)\\s+(.+?)$/u,\n );\n\n if (appliedEditMatch) {\n const activeFile = appliedEditMatch[1]?.trim();\n\n if (activeFile) {\n observations.push(createCodingObservation(activeFile, line, context.lineIndex + offset, {\n cwd: context.cwd,\n historyPath: context.historyPath,\n model: lastModel,\n }));\n continue;\n }\n }\n\n if (AIDER_ASKING_USER_HINT.test(line)) {\n observations.push({\n data: {\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint(\n 'agent.asking_user',\n context.lineIndex + offset,\n line,\n ),\n type: 'agent.asking_user',\n });\n continue;\n }\n\n if (AIDER_ERROR_HINT.test(line)) {\n observations.push({\n data: {\n errorMessage: line,\n errorType: classifyAiderErrorType(line),\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint(\n 'agent.error',\n context.lineIndex + offset,\n line,\n ),\n type: 'agent.error',\n });\n continue;\n }\n\n leftoverLines.push(line);\n }\n\n if (leftoverLines.length > 0) {\n const body = leftoverLines.join('\\n').trim();\n\n observations.push({\n data: {\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: body,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint(\n 'agent.thinking',\n context.lineIndex,\n body,\n ),\n type: 'agent.thinking',\n });\n }\n\n return {\n lastModel,\n observations,\n };\n}\n\nfunction createStreamingObservation(\n body: string,\n lineIndex: number,\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly model?: string;\n },\n): AiderHistoryObservation {\n return {\n data: {\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n output: body,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint('agent.streaming', lineIndex, body),\n type: 'agent.streaming',\n };\n}\n\nfunction createCodingObservation(\n activeFile: string,\n body: string,\n lineIndex: number,\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly model?: string;\n },\n): AiderHistoryObservation {\n return {\n data: {\n activeFile,\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n output: body,\n source: 'history-markdown',\n },\n toolInput: {\n filePath: activeFile,\n },\n toolName: 'search-replace',\n },\n fingerprint: createHistoryFingerprint(\n 'agent.coding',\n lineIndex,\n body,\n activeFile,\n ),\n type: 'agent.coding',\n };\n}\n\nfunction collectQuotedBlock(\n lines: readonly string[],\n startIndex: number,\n): {\n readonly lines: readonly string[];\n readonly nextIndex: number;\n} {\n const blockLines: string[] = [];\n let index = startIndex;\n\n while (index < lines.length) {\n const currentLine = lines[index];\n\n if (!currentLine?.startsWith('>')) {\n break;\n }\n\n blockLines.push(currentLine.replace(/^>\\s?/u, ''));\n index += 1;\n }\n\n return {\n lines: blockLines,\n nextIndex: index,\n };\n}\n\nfunction collectProseBlock(\n lines: readonly string[],\n startIndex: number,\n): {\n readonly body: string;\n readonly nextIndex: number;\n} {\n const proseLines: string[] = [];\n let index = startIndex;\n\n while (index < lines.length) {\n const currentLine = lines[index] ?? '';\n\n if (\n currentLine.trim().length === 0 ||\n currentLine.startsWith('# aider chat started at ') ||\n currentLine.startsWith('#### ') ||\n currentLine.startsWith('>') ||\n isAiderPatchBlockStart(lines, index)\n ) {\n break;\n }\n\n proseLines.push(currentLine);\n index += 1;\n }\n\n return {\n body: proseLines.join('\\n').trim(),\n nextIndex: index,\n };\n}\n\nfunction collectPatchBlock(\n lines: readonly string[],\n startIndex: number,\n): {\n readonly activeFile: string;\n readonly body: string;\n readonly nextIndex: number;\n} {\n const activeFile = (lines[startIndex] ?? '').trim();\n const blockLines = [activeFile];\n let index = startIndex + 1;\n\n while (index < lines.length) {\n const currentLine = lines[index] ?? '';\n\n if (\n currentLine.startsWith('#### ') ||\n currentLine.startsWith('# aider chat started at ') ||\n currentLine.startsWith('> ')\n ) {\n break;\n }\n\n if (\n currentLine.trim().length === 0 &&\n !looksLikePatchMarker(lines[index + 1] ?? '')\n ) {\n blockLines.push(currentLine);\n index += 1;\n break;\n }\n\n blockLines.push(currentLine);\n index += 1;\n }\n\n return {\n activeFile,\n body: blockLines.join('\\n').trim(),\n nextIndex: index,\n };\n}\n\nfunction isAiderPatchBlockStart(\n lines: readonly string[],\n index: number,\n): boolean {\n const currentLine = (lines[index] ?? '').trim();\n const nextLine = lines[index + 1] ?? '';\n\n if (\n currentLine.length === 0 ||\n currentLine.startsWith('#') ||\n currentLine.startsWith('>') ||\n currentLine.startsWith('#### ')\n ) {\n return false;\n }\n\n return looksLikePatchMarker(nextLine);\n}\n\nfunction looksLikePatchMarker(line: string): boolean {\n const trimmedLine = line.trim();\n\n return (\n trimmedLine.startsWith('<<<<<<< ') ||\n trimmedLine.startsWith('=======') ||\n trimmedLine.startsWith('>>>>>>> ')\n );\n}\n\nfunction parseAiderModelLine(line: string): string | undefined {\n const modelMatch = line.match(/^(?:Main model|Model):\\s*(.+?)(?:\\s+with\\s+|$)/u);\n\n return modelMatch?.[1]?.trim() || undefined;\n}\n\nfunction parseAiderTokenUsage(line: string): number | undefined {\n const tokenMatch = line.match(\n /Tokens:\\s+([0-9.]+[kKmM]?)\\s+sent,\\s+([0-9.]+[kKmM]?)\\s+received/u,\n );\n\n if (!tokenMatch) {\n return undefined;\n }\n\n const sentTokens = parseHumanTokenCount(tokenMatch[1]);\n const receivedTokens = parseHumanTokenCount(tokenMatch[2]);\n\n if (sentTokens === undefined || receivedTokens === undefined) {\n return undefined;\n }\n\n return sentTokens + receivedTokens;\n}\n\nfunction parseHumanTokenCount(rawValue: string | undefined): number | undefined {\n if (!rawValue) {\n return undefined;\n }\n\n const match = rawValue.trim().match(/^([0-9]+(?:\\.[0-9]+)?)([kKmM])?$/u);\n\n if (!match) {\n return undefined;\n }\n\n const numericValue = Number.parseFloat(match[1] ?? '');\n\n if (!Number.isFinite(numericValue)) {\n return undefined;\n }\n\n const suffix = match[2]?.toLowerCase();\n\n if (suffix === 'k') {\n return Math.round(numericValue * 1_000);\n }\n\n if (suffix === 'm') {\n return Math.round(numericValue * 1_000_000);\n }\n\n return Math.round(numericValue);\n}\n\nfunction parseAiderSlashCommand(prompt: string): {\n readonly filePath?: string;\n readonly name: string;\n} {\n const normalizedPrompt = prompt.trim();\n const commandName = normalizedPrompt\n .slice(1)\n .split(/\\s+/u)[0]\n ?.toLowerCase();\n const filePath = AIDER_FILE_COMMAND_HINT.test(normalizedPrompt)\n ? normalizedPrompt.split(/\\s+/u).slice(1).join(' ').trim() || undefined\n : undefined;\n\n return {\n filePath,\n name: commandName ?? 'command',\n };\n}\n\nfunction createHistoryFingerprint(\n type: AISnitchEventType,\n lineIndex: number,\n text: string,\n activeFile?: string,\n): string {\n return [\n type,\n String(lineIndex),\n activeFile ?? '',\n text.trim().replace(/\\s+/gu, ' ').slice(0, 240),\n ].join('::');\n}\n\nfunction classifyAiderErrorType(message: string): ErrorType {\n if (/rate limit|quota|too many requests/iu.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|context window/iu.test(message)) {\n return 'context_overflow';\n }\n\n if (/search\\/replace|edit format|apply|patch|write/iu.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nfunction resolveAiderHistoryPath(\n cwd: string,\n command: string,\n fallbackHistoryFileName: string,\n): string {\n const configuredHistoryPath =\n extractCommandOptionValue(command, 'chat-history-file') ??\n extractCommandOptionValue(command, 'chat_history_file');\n\n if (!configuredHistoryPath) {\n return join(cwd, fallbackHistoryFileName);\n }\n\n return configuredHistoryPath.startsWith('/')\n ? configuredHistoryPath\n : join(cwd, configuredHistoryPath);\n}\n\nfunction extractCommandOptionValue(\n command: string,\n optionName: string,\n): string | undefined {\n const matcher = new RegExp(\n `(?:^|\\\\s)--${escapeForRegExp(optionName)}(?:=|\\\\s+)(\"([^\"]+)\"|'([^']+)'|(\\\\S+))`,\n 'u',\n );\n const match = command.match(matcher);\n\n return match?.[2] ?? match?.[3] ?? match?.[4] ?? undefined;\n}\n\nfunction escapeForRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n}\n\nasync function listAiderProcesses(\n processListCommand: () => Promise<string>,\n): Promise<readonly AiderProcessInfo[]> {\n try {\n const output = await processListCommand();\n\n return output\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pid = Number.parseInt(match[1] ?? '', 10);\n const command = match[2]?.trim();\n\n if (!Number.isInteger(pid) || pid <= 0 || !command) {\n return null;\n }\n\n return {\n command,\n pid,\n } satisfies AiderProcessInfo;\n })\n .filter((processInfo): processInfo is AiderProcessInfo => processInfo !== null);\n } catch (error: unknown) {\n logger.debug({ error }, 'Aider process discovery returned no matches');\n return [];\n }\n}\n","import pino from 'pino';\n\n/**\n * @file src/core/engine/logger.ts\n * @description Shared structured logger for the in-memory AISnitch runtime.\n * @functions\n * โ†’ setLoggerLevel\n * @exports AISnitchLoggerLevel, logger, setLoggerLevel\n */\n\n/**\n * Supported logger levels for internal runtime usage.\n */\nexport type AISnitchLoggerLevel =\n | 'debug'\n | 'info'\n | 'warn'\n | 'error'\n | 'silent';\n\n/**\n * ๐Ÿ“– The logger writes to stdout only. The project is memory-only for runtime\n * data, so logging to files here would quietly violate that design.\n */\nexport const logger = pino({\n name: 'aisnitch',\n level: 'info',\n base: {\n service: 'aisnitch',\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n});\n\n/**\n * Updates the shared logger level at runtime.\n */\nexport function setLoggerLevel(level: AISnitchLoggerLevel): void {\n logger.level = level;\n}\n","import { basename, dirname, extname } from 'node:path';\n\nimport type { AISnitchEvent, ToolName } from './events/types.js';\n\n/**\n * @file src/core/session-identity.ts\n * @description Shared helpers for deriving stable session ids and readable session labels from partial runtime metadata.\n * @functions\n * โ†’ isGenericSessionId\n * โ†’ resolveSessionId\n * โ†’ formatSessionLabel\n * โ†’ formatSessionShortId\n * โ†’ formatSessionLabelFromEvent\n * @exports SessionIdentityInput, isGenericSessionId, resolveSessionId, formatSessionLabel, formatSessionShortId, formatSessionLabelFromEvent\n * @see ./engine/pipeline.ts\n * @see ../adapters/base.ts\n * @see ../tui/components/SessionPanel.tsx\n */\n\n/**\n * Shared metadata used to derive or display one session identity.\n */\nexport interface SessionIdentityInput {\n readonly activeFile?: string;\n readonly cwd?: string;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n readonly pid?: number;\n readonly project?: string;\n readonly projectPath?: string;\n readonly sessionId?: string;\n readonly tool: ToolName;\n readonly transcriptPath?: string;\n}\n\nconst GENERIC_SESSION_SUFFIXES = new Set([\n 'default',\n 'hook',\n 'hook-session',\n 'process',\n 'session',\n 'unknown',\n]);\n\n/**\n * ๐Ÿ“– Some tool hooks only expose a placeholder session id such as\n * `opencode-session` or `codex:hook-session`. Treating those as canonical\n * collapses unrelated runs together, so AISnitch upgrades them when richer\n * metadata exists.\n */\nexport function isGenericSessionId(\n tool: ToolName,\n sessionId: string,\n): boolean {\n const normalizedSessionId = sessionId.trim().toLowerCase();\n const normalizedTool = tool.toLowerCase();\n\n if (normalizedSessionId.length === 0) {\n return true;\n }\n\n if (\n normalizedSessionId === 'hook-session' ||\n normalizedSessionId === 'session'\n ) {\n return true;\n }\n\n for (const suffix of GENERIC_SESSION_SUFFIXES) {\n if (\n normalizedSessionId === `${normalizedTool}:${suffix}` ||\n normalizedSessionId === `${normalizedTool}-${suffix}`\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Returns the best-effort stable session id for one event source.\n */\nexport function resolveSessionId(input: SessionIdentityInput): string {\n if (input.sessionId && !isGenericSessionId(input.tool, input.sessionId)) {\n return input.sessionId;\n }\n\n const scopeToken = sanitizeToken(\n input.project ??\n getPathTail(input.projectPath) ??\n getPathTail(input.cwd) ??\n getPathTail(input.activeFile) ??\n getPathTail(input.transcriptPath ? dirname(input.transcriptPath) : undefined),\n );\n const transcriptToken = sanitizeToken(\n input.transcriptPath\n ? basename(input.transcriptPath, extname(input.transcriptPath))\n : undefined,\n );\n const pidToken = input.pid ? `p${input.pid}` : undefined;\n const parts = [\n input.tool,\n scopeToken,\n transcriptToken && transcriptToken !== scopeToken ? transcriptToken : undefined,\n pidToken,\n ].filter((value): value is string => typeof value === 'string' && value.length > 0);\n\n if (parts.length > 1) {\n return parts.join(':');\n }\n\n return input.sessionId ?? `${input.tool}:session`;\n}\n\n/**\n * Formats a compact human-readable label for logs and the TUI.\n */\nexport function formatSessionLabel(input: SessionIdentityInput): string {\n const scopeLabel =\n input.project ??\n getPathTail(input.projectPath) ??\n getPathTail(input.cwd) ??\n getPathTail(input.activeFile);\n const parts = [\n scopeLabel,\n input.instanceTotal && input.instanceTotal > 1\n ? `#${input.instanceIndex ?? 1}/${input.instanceTotal}`\n : undefined,\n input.pid ? `pid ${input.pid}` : formatSessionShortId(input.tool, input.sessionId),\n ].filter((value): value is string => typeof value === 'string' && value.length > 0);\n\n return parts.length > 0 ? parts.join(' ยท ') : input.tool;\n}\n\n/**\n * Formats a short session-id fragment for UI display without losing all entropy.\n */\nexport function formatSessionShortId(\n tool: ToolName,\n sessionId: string | undefined,\n): string | undefined {\n if (!sessionId || isGenericSessionId(tool, sessionId)) {\n return undefined;\n }\n\n const withoutToolPrefix = sessionId.startsWith(`${tool}:`)\n ? sessionId.slice(tool.length + 1)\n : sessionId;\n\n if (withoutToolPrefix.length <= 16) {\n return withoutToolPrefix;\n }\n\n return `${withoutToolPrefix.slice(0, 6)}โ€ฆ${withoutToolPrefix.slice(-4)}`;\n}\n\n/**\n * Builds a display label directly from a normalized AISnitch event.\n */\nexport function formatSessionLabelFromEvent(event: AISnitchEvent): string {\n return formatSessionLabel({\n activeFile: event.data.activeFile,\n cwd: event.data.cwd,\n instanceIndex: event.data.instanceIndex,\n instanceTotal: event.data.instanceTotal,\n pid: event.data.pid,\n project: event.data.project,\n projectPath: event.data.projectPath,\n sessionId: event['aisnitch.sessionid'],\n tool: event['aisnitch.tool'],\n });\n}\n\nfunction getPathTail(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const pathParts = value.split(/[\\\\/]+/u).filter((part) => part.length > 0);\n\n return pathParts.at(-1);\n}\n\nfunction sanitizeToken(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const normalizedToken = value\n .trim()\n .replace(/[\\\\/]+/gu, '-')\n .replace(/[^A-Za-z0-9._-]+/gu, '-')\n .replace(/-+/gu, '-')\n .replace(/^[-_.]+|[-_.]+$/gu, '');\n\n return normalizedToken.length > 0 ? normalizedToken : undefined;\n}\n","import { homedir } from 'node:os';\n\nimport { z } from 'zod';\n\nimport { logger } from '../core/engine/logger.js';\n\nimport { SHARED_BREAKERS } from '../core/circuit-breaker.js';\nimport type { AISnitchConfig } from '../core/config/schema.js';\nimport { createEvent } from '../core/events/factory.js';\nimport { EventDataSchema, createUuidV7 } from '../core/events/schema.js';\nimport type {\n AISnitchEvent,\n AISnitchEventType,\n EventData,\n ToolName,\n} from '../core/events/types.js';\n\n/**\n * @file src/adapters/base.ts\n * @description Shared adapter primitives for lifecycle management, normalized event emission, and idle/session tracking.\n * @functions\n * โ†’ none\n * @exports InterceptionStrategy, AdapterPublishContext, AdapterRuntimeOptions, AdapterStatus, NormalizedAdapterHookPayload, BaseAdapter\n * @see ./registry.ts\n * @see ./claude-code.ts\n * @see ./opencode.ts\n */\n\nconst NormalizedAdapterHookPayloadSchema = z.strictObject({\n type: z.string().min(1),\n source: z.string().min(1).optional(),\n sessionId: z.string().min(1).optional(),\n seqnum: z.number().int().min(1).optional(),\n data: EventDataSchema.partial().optional(),\n pid: z.number().int().positive().optional(),\n transcriptPath: z.string().min(1).optional(),\n cwd: z.string().min(1).optional(),\n env: z.record(z.string(), z.string()).optional(),\n hookPayload: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Capture strategies supported by built-in and future community adapters.\n */\nexport type InterceptionStrategy =\n | 'hooks'\n | 'jsonl-watch'\n | 'log-watch'\n | 'sqlite-watch'\n | 'stream-json'\n | 'process-detect'\n | 'pty-wrap'\n | 'api-client';\n\n/**\n * Extra context that adapters can provide alongside emitted events.\n */\nexport interface AdapterPublishContext {\n readonly cwd?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly hookPayload?: Record<string, unknown>;\n readonly pid?: number;\n readonly sessionId?: string;\n readonly source?: string;\n readonly transcriptPath?: string;\n}\n\n/**\n * Dependency injection contract shared by all adapters.\n */\nexport interface AdapterRuntimeOptions {\n readonly config: AISnitchConfig;\n readonly env?: NodeJS.ProcessEnv;\n readonly homeDirectory?: string;\n readonly publishEvent: (\n event: AISnitchEvent,\n context?: AdapterPublishContext,\n ) => Promise<boolean>;\n}\n\n/**\n * Observable adapter runtime state exposed to the registry and CLI.\n */\nexport interface AdapterStatus {\n readonly activeSessions: number;\n readonly displayName: string;\n readonly eventsEmitted: number;\n readonly name: ToolName;\n readonly running: boolean;\n readonly strategies: readonly InterceptionStrategy[];\n}\n\n/**\n * Best-effort normalized payload shape accepted from hook/plugin bridges.\n */\nexport type NormalizedAdapterHookPayload = z.infer<\n typeof NormalizedAdapterHookPayloadSchema\n>;\n\n/**\n * ๐Ÿ“– Every concrete adapter gets the same boring-but-essential plumbing here:\n * session ids, sequence numbers, idle timers, and validated event emission.\n */\nexport abstract class BaseAdapter {\n public abstract readonly displayName: string;\n\n public abstract readonly name: ToolName;\n\n public abstract readonly strategies: readonly InterceptionStrategy[];\n\n protected currentSessionId: string | null = null;\n\n protected readonly env: NodeJS.ProcessEnv | undefined;\n\n protected readonly homeDirectory: string;\n\n protected sequenceNumber = 0;\n\n private readonly activeSessions = new Set<string>();\n\n private eventsEmitted = 0;\n\n private idleTimer: NodeJS.Timeout | null = null;\n\n private readonly idleTimeoutMs: number;\n\n private readonly publishEventImplementation: AdapterRuntimeOptions['publishEvent'];\n\n private running = false;\n\n protected constructor(options: AdapterRuntimeOptions) {\n this.env = options.env;\n this.homeDirectory = options.homeDirectory ?? homedir();\n this.idleTimeoutMs = options.config.idleTimeoutMs;\n this.publishEventImplementation = options.publishEvent;\n }\n\n /**\n * Starts the adapter-specific watchers, pollers, or hook bridges.\n */\n public abstract start(): Promise<void>;\n\n /**\n * Stops adapter-specific resources and clears runtime state.\n */\n public abstract stop(): Promise<void>;\n\n /**\n * Hook-based adapters override this to transform tool-native payloads.\n */\n public handleHook(_payload: unknown): Promise<void> {\n return Promise.reject(\n new Error(`${this.name} does not support hook payloads.`),\n );\n }\n\n /**\n * Returns the current observable adapter status snapshot.\n */\n public getStatus(): AdapterStatus {\n return {\n activeSessions: this.activeSessions.size,\n displayName: this.displayName,\n eventsEmitted: this.eventsEmitted,\n name: this.name,\n running: this.running,\n strategies: this.strategies,\n };\n }\n\n /**\n * Accepts the normalized hook payload shape used by setup-installed bridges.\n */\n protected parseNormalizedHookPayload(\n payload: unknown,\n ): NormalizedAdapterHookPayload | null {\n const parsedPayload = NormalizedAdapterHookPayloadSchema.safeParse(payload);\n\n if (!parsedPayload.success) {\n return null;\n }\n\n return parsedPayload.data;\n }\n\n /**\n * Emits one already-normalized payload through the common adapter lifecycle.\n */\n protected async emitNormalizedPayload(\n payload: NormalizedAdapterHookPayload,\n ): Promise<boolean> {\n return await this.emit(payload.type as AISnitchEventType, payload.data, {\n cwd: payload.cwd,\n env: payload.env,\n hookPayload: payload.hookPayload,\n pid: payload.pid,\n sessionId: payload.sessionId,\n source: payload.source,\n transcriptPath: payload.transcriptPath,\n });\n }\n\n /**\n * Emits a fully normalized AISnitch event and updates idle/session tracking.\n */\n protected async emit(\n type: AISnitchEventType,\n data: Omit<EventData, 'state'> = {},\n context: AdapterPublishContext = {},\n ): Promise<boolean> {\n const sessionId = this.resolveSessionId(context.sessionId);\n\n this.sequenceNumber += 1;\n\n const event = createEvent({\n source: context.source ?? `aisnitch://adapters/${this.name}`,\n type,\n 'aisnitch.tool': this.name,\n 'aisnitch.sessionid': sessionId,\n 'aisnitch.seqnum': this.sequenceNumber,\n data: {\n ...data,\n cwd: data.cwd ?? context.cwd,\n },\n });\n\n /**\n * Publishes event through circuit breaker to prevent cascading failures.\n * If circuit is open, returns false immediately.\n */\n let published: boolean;\n\n try {\n published = await SHARED_BREAKERS.adapterEmit.execute(async () => {\n return await this.publishEventImplementation(event, {\n cwd: context.cwd,\n env: context.env,\n hookPayload: context.hookPayload,\n pid: context.pid,\n sessionId,\n source: context.source,\n transcriptPath: context.transcriptPath,\n });\n });\n } catch (error: unknown) {\n // CircuitOpenError or other error โ€” log and return false, never crash\n if (error instanceof Error && error.name === 'CircuitOpenError') {\n logger.warn(\n { error, eventType: type, adapter: this.name },\n '๐Ÿ“– Adapter emit blocked by open circuit โ€” event dropped',\n );\n } else {\n logger.error(\n { error, eventType: type, adapter: this.name, sessionId },\n '๐Ÿ“– Failed to publish event โ€” swallowing to prevent daemon crash',\n );\n }\n published = false;\n }\n\n if (published) {\n this.eventsEmitted += 1;\n }\n\n if (type === 'session.end') {\n this.activeSessions.delete(sessionId);\n\n if (this.currentSessionId === sessionId) {\n this.currentSessionId = null;\n }\n\n this.clearIdleTimer();\n\n return published;\n }\n\n if (type !== 'agent.idle') {\n this.resetIdleTimer();\n }\n\n return published;\n }\n\n /**\n * Shortcut for emitting a plain state transition without extra boilerplate.\n */\n protected async emitStateChange(\n type: AISnitchEventType,\n data: Omit<EventData, 'state'> = {},\n context: AdapterPublishContext = {},\n ): Promise<boolean> {\n return await this.emit(type, data, context);\n }\n\n /**\n * Updates the active session id while keeping sequence numbers monotonic per session.\n */\n protected setSessionId(sessionId: string | null): void {\n if (sessionId === null) {\n this.currentSessionId = null;\n this.clearIdleTimer();\n return;\n }\n\n if (this.currentSessionId !== sessionId) {\n this.sequenceNumber = 0;\n }\n\n this.currentSessionId = sessionId;\n this.activeSessions.add(sessionId);\n }\n\n /**\n * Marks the adapter runtime as active or stopped.\n */\n protected setRunning(running: boolean): void {\n this.running = running;\n\n if (!running) {\n this.clearIdleTimer();\n this.currentSessionId = null;\n this.sequenceNumber = 0;\n this.activeSessions.clear();\n }\n }\n\n /**\n * Shared helper for adapters that need a stable testable home directory.\n */\n protected getUserHomeDirectory(): string {\n return this.homeDirectory;\n }\n\n private clearIdleTimer(): void {\n if (this.idleTimer !== null) {\n clearTimeout(this.idleTimer);\n this.idleTimer = null;\n }\n }\n\n private resetIdleTimer(): void {\n if (!this.running || this.currentSessionId === null) {\n return;\n }\n\n this.clearIdleTimer();\n this.idleTimer = setTimeout(() => {\n if (this.currentSessionId === null) {\n return;\n }\n\n void this.emitStateChange('agent.idle');\n }, this.idleTimeoutMs);\n this.idleTimer.unref();\n }\n\n private resolveSessionId(sessionId?: string): string {\n if (sessionId !== undefined) {\n this.setSessionId(sessionId);\n\n return sessionId;\n }\n\n if (this.currentSessionId === null) {\n this.setSessionId(`${this.name}:${createUuidV7()}`);\n }\n\n if (this.currentSessionId === null) {\n throw new Error(`Adapter \"${this.name}\" failed to resolve a session id.`);\n }\n\n return this.currentSessionId;\n }\n}\n","/**\n * @file src/core/errors.ts\n * @description Centralized error hierarchy for AISnitch with typed error codes and context.\n *\n * This module provides a consistent error taxonomy across the entire application:\n * - `AISnitchError` โ€” base class for all AISnitch-specific errors\n * - `AdapterError` โ€” adapter lifecycle, parsing, or emission failures\n * - `PipelineError` โ€” pipeline orchestration, component startup, or shutdown failures\n * - `ValidationError` โ€” Zod parsing failures and schema violations\n * - `NetworkError` โ€” HTTP, WebSocket, or Unix Domain Socket failures\n * - `TimeoutError` โ€” async operations that exceed their deadline\n *\n * Each error carries a machine-readable `code` field for programmatic handling\n * and an optional `context` bag for debugging. Errors serialize cleanly to JSON\n * so they can be logged via pino without losing structure.\n *\n * @functions\n * โ†’ none\n * @exports AISnitchError, AdapterError, PipelineError, ValidationError, NetworkError, TimeoutError, isAISnitchError, isRetryableError\n * @see ./result.ts\n * @see ./retry.ts\n * @see ./timeout.ts\n */\n\n/**\n * Base class for all AISnitch-specific errors.\n *\n * @example\n * ```typescript\n * throw new AISnitchError(\n * 'Event validation failed',\n * 'EVENT_VALIDATION_ERROR',\n * { eventId: event.id, issues: parseResult.error.issues }\n * );\n * ```\n */\nexport class AISnitchError extends Error {\n /**\n * Machine-readable error code for programmatic handling.\n * Format: `SUBCATEGORY_SPECIFIC_DETAIL` (uppercase with underscores).\n */\n public readonly code: string;\n\n /**\n * Arbitrary context bag forwarded to the logger for structured debugging.\n */\n public readonly context?: Readonly<Record<string, unknown>>;\n\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message);\n this.name = 'AISnitchError';\n this.code = code;\n this.context = context;\n\n // Maintains proper stack trace in V8 engines (Node.js, Chrome, Edge)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AISnitchError);\n }\n }\n\n /**\n * Full error chain for logging: `[name] code โ€” message`.\n */\n public override toString(): string {\n return `${this.name} [${this.code}] โ€” ${this.message}`;\n }\n\n /**\n * JSON serialization friendly to pino serializers.\n */\n public toJSON(): object {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Errors originating from adapter lifecycle, payload parsing, or event emission.\n *\n * @example\n * ```typescript\n * throw new AdapterError(\n * 'Claude Code transcript read failed',\n * 'ADAPTER_CLAUDE_CODE_FILE_ERROR',\n * { filePath: transcriptPath, cause: error }\n * );\n * ```\n */\nexport class AdapterError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'AdapterError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AdapterError);\n }\n }\n\n /**\n * Factory for adapter-specific errors with auto-generated codes.\n */\n public static withAutoCode(\n message: string,\n tool: string,\n context?: Readonly<Record<string, unknown>>,\n ): AdapterError {\n const sanitizedTool = tool.replace(/[^a-z0-9]/gi, '_').toUpperCase();\n const code = `ADAPTER_${sanitizedTool}_ERROR`;\n\n return new AdapterError(message, code, { tool, ...context });\n }\n}\n\n/**\n * Errors originating from pipeline orchestration, component startup, or shutdown.\n *\n * @example\n * ```typescript\n * throw new PipelineError(\n * 'Failed to start WebSocket server',\n * 'PIPELINE_WS_START_FAILED',\n * { port: configuredPort, cause: error }\n * );\n * ```\n */\nexport class PipelineError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'PipelineError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, PipelineError);\n }\n }\n}\n\n/**\n * Errors from Zod schema parsing failures and data validation violations.\n *\n * @example\n * ```typescript\n * const result = EventDataSchema.safeParse(rawPayload);\n * if (!result.success) {\n * throw new ValidationError(\n * 'Invalid event data payload',\n * 'VALIDATION_EVENT_DATA_INVALID',\n * { issues: result.error.issues }\n * );\n * }\n * ```\n */\nexport class ValidationError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'ValidationError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ValidationError);\n }\n }\n}\n\n/**\n * Errors from network operations: HTTP requests, WebSocket connections, UDS.\n *\n * @example\n * ```typescript\n * throw new NetworkError(\n * 'Health endpoint unreachable',\n * 'NETWORK_HTTP_CONNECT_FAILED',\n * { host: '127.0.0.1', port: 4821, cause: error }\n * );\n * ```\n */\nexport class NetworkError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'NetworkError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, NetworkError);\n }\n }\n}\n\n/**\n * Errors from async operations that exceed their configured deadline.\n *\n * @example\n * ```typescript\n * throw new TimeoutError(\n * 'Adapter stop timed out after 5 seconds',\n * 'TIMEOUT_SHUTDOWN',\n * { component: 'ClaudeCodeAdapter', timeoutMs: 5_000 }\n * );\n * ```\n */\nexport class TimeoutError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'TimeoutError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TimeoutError);\n }\n }\n}\n\n/**\n * Type guard to narrow any `unknown` error to an AISnitch error.\n *\n * @example\n * ```typescript\n * } catch (error: unknown) {\n * if (isAISnitchError(error)) {\n * console.error(`AISnitch error ${error.code}: ${error.message}`);\n * } else {\n * console.error('Unexpected error', error);\n * }\n * }\n * ```\n */\nexport function isAISnitchError(error: unknown): error is AISnitchError {\n return error instanceof AISnitchError;\n}\n\n/**\n * Determines whether an error is safe to retry (transient vs. permanent).\n *\n * Returns `true` for network timeouts, connection reset, and rate-limit errors.\n * Returns `false` for validation errors, authentication failures, and programming bugs.\n *\n * @example\n * ```typescript\n * try {\n * return await operation();\n * } catch (error: unknown) {\n * if (isRetryableError(error)) {\n * throw error; // let retry logic handle it\n * }\n * throw error; // propagate as-is (non-retryable)\n * }\n * ```\n */\nexport function isRetryableError(error: unknown): boolean {\n if (!isAISnitchError(error)) {\n // Native JS errors: network failures, ECONNREFUSED, ETIMEDOUT are retryable\n if (error instanceof Error) {\n const code = (error as NodeJS.ErrnoException).code;\n const retryableCodes = new Set([\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'ENOTFOUND',\n 'EHOSTUNREACH',\n 'EPIPE',\n 'EPERM', // sometimes transient on macOS file locks\n ]);\n\n if (typeof code === 'string' && retryableCodes.has(code)) {\n return true;\n }\n }\n\n return false;\n }\n\n // AISnitch errors: timeout and network errors are retryable\n const retryableCategories = new Set(['TIMEOUT', 'NETWORK']);\n\n for (const category of retryableCategories) {\n if (error.code.startsWith(category)) {\n return true;\n }\n }\n\n // Adapter errors with specific patterns\n const retryablePatterns = [\n /^ADAPTER_.*_(FILE_IO|NETWORK|PROCESS_DETECT)_ERROR$/,\n /^PIPELINE_.*_(RETRY|RECONNECT)_ERROR$/,\n ];\n\n for (const pattern of retryablePatterns) {\n if (pattern.test(error.code)) {\n return true;\n }\n }\n\n return false;\n}\n","/**\n * @file src/core/circuit-breaker.ts\n * @description Circuit breaker pattern implementation for resilient adapter operation.\n *\n * The circuit breaker prevents cascading failures when an adapter repeatedly fails:\n *\n * ```\n * CLOSED (normal) โ”€โ”€[N failures]โ”€โ”€โ†’ OPEN (failing fast)\n * โ†‘ โ”‚\n * โ”‚ [half-open after timeout]\n * โ”‚ โ†“\n * โ””โ”€โ”€โ”€โ”€โ”€โ”€[success]โ”€โ”€โ”€โ”€ HALF-OPEN (testing recovery)\n * ```\n *\n * When an adapter fails `threshold` times within `windowMs`, the breaker opens:\n * - Subsequent calls fail immediately with `CircuitOpenError` (no network round-trips)\n * - After `halfOpenAfterMs`, one test call is allowed to check recovery\n * - If it succeeds โ†’ close the circuit (back to normal operation)\n * - If it fails โ†’ reopen and wait again\n *\n * ## When to use this\n *\n * - Adapter `emit()` calls that can fail repeatedly (file system errors, hook timeouts)\n * - Network operations with unreliable backends\n * - Any operation where persistent failure is worse than temporary unavailability\n *\n * ## When NOT to use this\n *\n * - One-off errors that are unlikely to repeat\n * - Validation failures (these indicate a programming bug, not a transient fault)\n * - Operations that are already idempotent with built-in retry (prefer `withRetry`)\n *\n * @functions\n * โ†’ none\n * @exports CircuitState, CircuitOpenError, CircuitBreaker\n * @see ./errors.ts\n * @see ./retry.ts\n * @see ./timeout.ts\n */\n\nimport { AISnitchError, isRetryableError } from './errors.js';\nimport { logger } from './engine/logger.js';\n\n/**\n * Observable state of a circuit breaker.\n */\nexport interface CircuitState {\n /**\n * Number of consecutive failures since last success.\n */\n readonly failures: number;\n /**\n * Timestamp of the last failure (ms since epoch), or null if never failed.\n */\n readonly lastFailureAt: number | null;\n /**\n * Current state of the circuit.\n * - `closed`: Normal operation, requests pass through\n * - `open`: Failing fast, requests are rejected immediately\n * - `half-open`: Testing recovery, one request is allowed through\n */\n readonly state: 'closed' | 'open' | 'half-open';\n}\n\n/**\n * Error thrown when a circuit is open and the operation is rejected.\n */\nexport class CircuitOpenError extends AISnitchError {\n public constructor(\n public readonly circuitId: string,\n public readonly state: CircuitState,\n ) {\n super(\n `Circuit \"${circuitId}\" is OPEN โ€” operation rejected`,\n 'CIRCUIT_OPEN',\n { circuitId, failures: state.failures, lastFailureAt: state.lastFailureAt },\n );\n this.name = 'CircuitOpenError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CircuitOpenError);\n }\n }\n\n public override toString(): string {\n return `${this.name} [${this.code}] \"${this.circuitId}\" โ€” failures=${this.state.failures}`;\n }\n}\n\n/**\n * Configuration for a circuit breaker instance.\n */\nexport interface CircuitBreakerOptions {\n /**\n * Number of consecutive failures before opening the circuit.\n * @default 5\n */\n readonly failureThreshold?: number;\n /**\n * Time window in milliseconds to count failures within.\n * @default 60_000 (1 minute)\n */\n readonly windowMs?: number;\n /**\n * Time to wait before transitioning from OPEN to HALF-OPEN.\n * @default 30_000 (30 seconds)\n */\n readonly halfOpenAfterMs?: number;\n /**\n * Human-readable identifier for this circuit (shown in logs).\n * @default 'unnamed'\n */\n readonly id?: string;\n /**\n * Optional predicate to decide which errors count toward the threshold.\n * Return `true` to count as a failure, `false` to ignore (success-like failure).\n * @default isRetryableError\n */\n readonly shouldCountAsFailure?: (error: unknown) => boolean;\n /**\n * Set to `true` to reset the failure counter after any success in CLOSED state.\n * Set to `false` to only reset after `failureThreshold` successes.\n * @default true\n */\n readonly resetOnSuccess?: boolean;\n}\n\nconst DEFAULT_OPTIONS: Required<CircuitBreakerOptions> = {\n failureThreshold: 5,\n halfOpenAfterMs: 30_000,\n id: 'unnamed',\n resetOnSuccess: true,\n shouldCountAsFailure: isRetryableError,\n windowMs: 60_000,\n};\n\n/**\n * Circuit breaker state machine.\n *\n * ## State transitions\n *\n * ```\n * CLOSED โ”€โ”€[failure + threshold reached]โ”€โ”€โ†’ OPEN\n * โ–ฒ โ”‚\n * โ”‚ [halfOpenAfterMs elapsed]\n * โ”‚ โ†“\n * โ”‚ HALF-OPEN\n * โ”‚ โ”‚\n * โ”‚ [test call succeeds]\n * โ”‚ โ†“\n * โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€[reset]โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n * ```\n *\n * ## Usage\n *\n * ```typescript\n * const breaker = new CircuitBreaker({\n * id: 'claude-code.emit',\n * failureThreshold: 3,\n * windowMs: 60_000,\n * });\n *\n * async function safeEmit(event: AISnitchEvent) {\n * return breaker.execute(() => adapter.emit(event));\n * }\n * ```\n */\nexport class CircuitBreaker {\n private failures = 0;\n private lastFailureAt: number | null = null;\n private state: CircuitState['state'] = 'closed';\n private halfOpenTestStartedAt: number | null = null;\n\n private readonly options: Required<CircuitBreakerOptions>;\n\n public constructor(options: CircuitBreakerOptions = {}) {\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n // Re-spread to ensure all fields have defaults\n failureThreshold: options.failureThreshold ?? DEFAULT_OPTIONS.failureThreshold,\n halfOpenAfterMs: options.halfOpenAfterMs ?? DEFAULT_OPTIONS.halfOpenAfterMs,\n id: options.id ?? DEFAULT_OPTIONS.id,\n resetOnSuccess: options.resetOnSuccess ?? DEFAULT_OPTIONS.resetOnSuccess,\n shouldCountAsFailure: options.shouldCountAsFailure ?? DEFAULT_OPTIONS.shouldCountAsFailure,\n windowMs: options.windowMs ?? DEFAULT_OPTIONS.windowMs,\n };\n }\n\n /**\n * Executes an async operation through the circuit breaker.\n *\n * - If the circuit is CLOSED โ†’ runs `fn` and updates state based on result\n * - If the circuit is HALF-OPEN โ†’ runs `fn` once to test recovery\n * - If the circuit is OPEN โ†’ throws `CircuitOpenError` immediately (no call)\n *\n * @param fn - The async operation to protect\n * @returns The result of `fn` if successful\n * @throws CircuitOpenError if the circuit is OPEN\n * @throws The error from `fn` if it throws (and `shouldCountAsFailure` returns true)\n */\n public async execute<T>(fn: () => Promise<T>): Promise<T> {\n switch (this.state) {\n case 'closed':\n return this.executeClosed(fn);\n case 'half-open':\n return this.executeHalfOpen(fn);\n case 'open':\n if (this.shouldTransitionToHalfOpen()) {\n this.transitionToHalfOpen();\n return this.executeHalfOpen(fn);\n }\n throw new CircuitOpenError(this.options.id, this.getState());\n // no default\n }\n }\n\n /**\n * Returns the current observable circuit state.\n */\n public getState(): CircuitState {\n return {\n failures: this.failures,\n lastFailureAt: this.lastFailureAt,\n state: this.state,\n };\n }\n\n /**\n * Forces the circuit to CLOSED (resets failure count and state).\n * Useful for manual recovery after a known-fix or after a maintenance window.\n */\n public reset(): void {\n this.failures = 0;\n this.lastFailureAt = null;\n this.state = 'closed';\n this.halfOpenTestStartedAt = null;\n\n logger.debug({ circuitId: this.options.id }, 'Circuit breaker manually reset');\n }\n\n /**\n * Pre-warms the circuit by performing one test call in HALF-OPEN state.\n * If the circuit is already HALF-OPEN, this does nothing.\n * If the circuit is CLOSED, this does nothing.\n */\n public async preWarm(fn: () => Promise<void>): Promise<void> {\n if (this.state !== 'open') {\n return;\n }\n\n this.transitionToHalfOpen();\n\n try {\n await fn();\n this.transitionToClosed();\n } catch {\n this.transitionToOpen();\n }\n }\n\n // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n // Private methods\n // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n private async executeClosed<T>(fn: () => Promise<T>): Promise<T> {\n try {\n const result = await fn();\n\n this.onSuccess();\n return result;\n } catch (error) {\n this.onFailure(error);\n throw error;\n }\n }\n\n private async executeHalfOpen<T>(fn: () => Promise<T>): Promise<T> {\n this.halfOpenTestStartedAt = Date.now();\n\n try {\n const result = await fn();\n\n this.transitionToClosed();\n return result;\n } catch (error) {\n this.transitionToOpen();\n throw error;\n }\n }\n\n private onSuccess(): void {\n if (this.options.resetOnSuccess) {\n // Immediately reset failure count on any success\n this.failures = 0;\n this.lastFailureAt = null;\n } else {\n // Decrement counter but don't go below zero\n this.failures = Math.max(0, this.failures - 1);\n\n if (this.failures === 0) {\n this.lastFailureAt = null;\n }\n }\n\n logger.debug(\n {\n circuitId: this.options.id,\n failures: this.failures,\n },\n 'Circuit breaker operation succeeded',\n );\n }\n\n private onFailure(error: unknown): void {\n if (!this.options.shouldCountAsFailure(error)) {\n // Error is not counted as a failure (e.g., validation error)\n logger.debug(\n { circuitId: this.options.id, error },\n 'Circuit breaker operation failed but error is not counted as failure',\n );\n return;\n }\n\n this.failures += 1;\n this.lastFailureAt = Date.now();\n\n // Check if we've exceeded the threshold\n if (this.failures >= this.options.failureThreshold) {\n this.transitionToOpen();\n } else {\n logger.debug(\n {\n circuitId: this.options.id,\n failures: this.failures,\n threshold: this.options.failureThreshold,\n },\n 'Circuit breaker recorded failure',\n );\n }\n }\n\n private transitionToOpen(): void {\n if (this.state === 'open') {\n return; // Already open, no transition needed\n }\n\n this.state = 'open';\n this.halfOpenTestStartedAt = null;\n\n logger.warn(\n {\n circuitId: this.options.id,\n failures: this.failures,\n windowMs: this.options.windowMs,\n },\n '๐Ÿ”ด Circuit breaker OPEN โ€” blocking operations',\n );\n }\n\n private transitionToHalfOpen(): void {\n this.state = 'half-open';\n this.halfOpenTestStartedAt = Date.now();\n\n logger.info(\n { circuitId: this.options.id },\n '๐ŸŸก Circuit breaker HALF-OPEN โ€” testing recovery',\n );\n }\n\n private transitionToClosed(): void {\n this.state = 'closed';\n this.failures = 0;\n this.lastFailureAt = null;\n this.halfOpenTestStartedAt = null;\n\n logger.info(\n { circuitId: this.options.id },\n '๐ŸŸข Circuit breaker CLOSED โ€” recovery successful',\n );\n }\n\n private shouldTransitionToHalfOpen(): boolean {\n if (this.lastFailureAt === null) {\n // Never failed, should open immediately for testing\n return true;\n }\n\n const elapsed = Date.now() - this.lastFailureAt;\n return elapsed >= this.options.halfOpenAfterMs;\n }\n}\n\n/**\n * Shared circuit breaker instances for common AISnitch operations.\n * These are module-level singletons to avoid creating new breakers on every call.\n *\n * Usage:\n * ```typescript\n * import { SHARED_BREAKERS } from './circuit-breaker.js';\n *\n * // Wrap an adapter emit call\n * await SHARED_BREAKERS.adapterEmit.execute(() => adapter.emit(event));\n * ```\n */\nexport const SHARED_BREAKERS = Object.freeze({\n /**\n * Breaker for adapter event emission.\n * Threshold: 5 failures in 60s โ†’ open for 30s โ†’ half-open test.\n */\n adapterEmit: new CircuitBreaker({\n id: 'adapter.emit',\n failureThreshold: 5,\n halfOpenAfterMs: 30_000,\n shouldCountAsFailure: isRetryableError,\n windowMs: 60_000,\n }),\n\n /**\n * Breaker for file system operations (transcript reading, config loading).\n * More tolerant: 10 failures in 60s โ†’ open for 30s.\n */\n fileSystem: new CircuitBreaker({\n id: 'filesystem',\n failureThreshold: 10,\n halfOpenAfterMs: 30_000,\n windowMs: 60_000,\n }),\n\n /**\n * Breaker for HTTP/HTTPS requests.\n * Stricter: 3 failures in 30s โ†’ open for 15s.\n */\n httpRequest: new CircuitBreaker({\n id: 'http-request',\n failureThreshold: 3,\n halfOpenAfterMs: 15_000,\n windowMs: 30_000,\n }),\n\n /**\n * Breaker for process detection operations.\n * Most tolerant: 20 failures in 60s โ†’ open for 10s.\n */\n processDetection: new CircuitBreaker({\n id: 'process-detection',\n failureThreshold: 20,\n halfOpenAfterMs: 10_000,\n windowMs: 60_000,\n }),\n});\n","import { validate as isUuid, v7 as uuidv7, version as uuidVersion } from 'uuid';\nimport { z } from 'zod';\n\n/**\n * @file src/core/events/schema.ts\n * @description Runtime Zod schemas and constants for the AISnitch CloudEvents-based event contract.\n * @functions\n * โ†’ createUuidV7\n * @exports AISNITCH_EVENT_TYPES, TOOL_NAMES, ERROR_TYPES, CESP_CATEGORIES, ToolInputSchema, ToolCallNameSchema, ThinkingContentSchema, FinalMessageSchema, ToolResultSchema, MessageContentSchema, EventDataSchema, AISnitchEventTypeSchema, ToolNameSchema, ErrorTypeSchema, CESPCategorySchema, AISnitchEventSchema, createUuidV7\n * @see ./types.ts\n * @see ./cesp.ts\n * @see ./factory.ts\n */\n\n/**\n * ๐Ÿ“– AISnitch keeps the event-type list as a constant tuple so every schema,\n * inferred type, and mapping table stays aligned from one source of truth.\n */\nexport const AISNITCH_EVENT_TYPES = [\n 'session.start',\n 'session.end',\n 'task.start',\n 'task.complete',\n 'agent.thinking',\n 'agent.coding',\n 'agent.tool_call',\n 'agent.streaming',\n 'agent.asking_user',\n 'agent.idle',\n 'agent.error',\n 'agent.compact',\n] as const;\n\n/**\n * Supported AI tool identifiers recognized by AISnitch.\n */\nexport const TOOL_NAMES = [\n 'claude-code',\n 'opencode',\n 'gemini-cli',\n 'codex',\n 'goose',\n 'copilot-cli',\n 'cursor',\n 'aider',\n 'amp',\n 'cline',\n 'continue',\n 'windsurf',\n 'qwen-code',\n 'openclaw',\n 'openhands',\n 'kilo',\n 'devin',\n 'kiro',\n 'augment-code',\n 'mistral',\n 'zed',\n 'pi',\n 'unknown',\n] as const;\n\n/**\n * Normalized error categories attached to `agent.error` events.\n */\nexport const ERROR_TYPES = [\n 'rate_limit',\n 'context_overflow',\n 'tool_failure',\n 'api_error',\n] as const;\n\n/**\n * CESP-compatible categories used by the current mapping layer.\n */\nexport const CESP_CATEGORIES = [\n 'session.start',\n 'session.end',\n 'task.acknowledge',\n 'task.complete',\n 'input.required',\n 'task.error',\n 'resource.limit',\n] as const;\n\nconst ISO_TIMESTAMP_SCHEMA = z.string().datetime({ offset: true });\n\nfunction isUuidV7(value: string): boolean {\n return isUuid(value) && uuidVersion(value) === 7;\n}\n\nfunction isValidUriReference(value: string): boolean {\n if (value.trim().length === 0 || /\\s/u.test(value)) {\n return false;\n }\n\n try {\n new URL(value);\n return true;\n } catch {\n try {\n new URL(value, 'https://aisnitch.local');\n return true;\n } catch {\n return false;\n }\n }\n}\n\n/**\n * Generates a UUIDv7 value that matches the event schema contract.\n */\nexport function createUuidV7(): string {\n return uuidv7();\n}\n\n/**\n * Tool input metadata attached when an agent runs a concrete tool.\n */\nexport const ToolInputSchema = z\n .strictObject({\n filePath: z.string().min(1).max(4_096).optional(),\n command: z.string().min(1).max(10_000).optional(),\n })\n .refine(\n (value) => value.filePath !== undefined || value.command !== undefined,\n 'toolInput must include filePath or command',\n );\n\n/**\n * ๐Ÿ“– Thinking content extracted from AI model reasoning chains.\n * This field captures the internal \"thinking\" or reasoning output that\n * models like Claude produce before generating their final response.\n */\nexport const ThinkingContentSchema = z\n .string()\n .max(100_000)\n .describe('Raw thinking/reasoning content from the AI model');\n\n/**\n * ๐Ÿ“– Tool call name โ€” the specific tool being invoked.\n * Examples: \"Edit\", \"Bash\", \"Grep\", \"Read\", \"Write\", \"WebSearch\"\n * Different from `toolInput` which contains the tool's parameters.\n */\nexport const ToolCallNameSchema = z\n .string()\n .min(1)\n .max(100)\n .describe('Name of the tool being invoked (e.g., Edit, Bash, Grep)');\n\n/**\n * ๐Ÿ“– Final message shown at the end of an AI run.\n * This is typically a summary, completion message, or result text\n * displayed to the user after the agent finishes its work.\n */\nexport const FinalMessageSchema = z\n .string()\n .max(50_000)\n .describe('End-of-run summary or completion message');\n\n/**\n * ๐Ÿ“– Tool execution result โ€” short result from a tool call.\n * Can include success messages, error messages, or short outputs.\n */\nexport const ToolResultSchema = z\n .string()\n .max(10_000)\n .describe('Tool execution result or output');\n\n/**\n * ๐Ÿ“– Raw message content from AI responses.\n * Captures the actual text generated by the model before tool calls.\n */\nexport const MessageContentSchema = z\n .string()\n .max(100_000)\n .describe('Raw text content from AI messages');\n\n/**\n * Runtime schema for the supported tool names.\n */\nexport const ToolNameSchema = z.enum(TOOL_NAMES);\n\n/**\n * Runtime schema for AISnitch event types.\n */\nexport const AISnitchEventTypeSchema = z.enum(AISNITCH_EVENT_TYPES);\n\n/**\n * Runtime schema for normalized AISnitch error categories.\n */\nexport const ErrorTypeSchema = z.enum(ERROR_TYPES);\n\n/**\n * Runtime schema for CESP categories.\n */\nexport const CESPCategorySchema = z.enum(CESP_CATEGORIES);\n\n/**\n * ๐Ÿ“– `raw` remains intentionally permissive because adapters need a safe place\n * to stash source-native payload fragments without forcing them into the\n * normalized contract too early.\n */\nexport const EventDataSchema = z.strictObject({\n state: AISnitchEventTypeSchema,\n project: z.string().min(1).max(255).optional(),\n projectPath: z.string().min(1).max(4_096).optional(),\n duration: z.number().int().min(0).optional(),\n toolName: z.string().min(1).max(100).optional(),\n toolInput: ToolInputSchema.optional(),\n activeFile: z.string().min(1).max(4_096).optional(),\n model: z.string().min(1).max(200).optional(),\n tokensUsed: z.number().int().min(0).optional(),\n errorMessage: z.string().min(1).max(10_000).optional(),\n errorType: ErrorTypeSchema.optional(),\n raw: z.record(z.string(), z.unknown()).optional(),\n terminal: z.string().min(1).max(100).optional(),\n cwd: z.string().min(1).max(4_096).optional(),\n pid: z.number().int().positive().optional(),\n instanceId: z.string().min(1).max(255).optional(),\n instanceIndex: z.number().int().min(1).optional(),\n instanceTotal: z.number().int().min(1).optional(),\n // New fields for enhanced content capture\n thinkingContent: ThinkingContentSchema.optional(),\n toolCallName: ToolCallNameSchema.optional(),\n finalMessage: FinalMessageSchema.optional(),\n toolResult: ToolResultSchema.optional(),\n messageContent: MessageContentSchema.optional(),\n});\n\n/**\n * Runtime schema for the full normalized AISnitch event envelope.\n */\nexport const AISnitchEventSchema = z.strictObject({\n specversion: z.literal('1.0'),\n id: z.string().refine(isUuidV7, 'id must be a valid UUIDv7 string'),\n source: z\n .string()\n .max(2_000)\n .refine(\n isValidUriReference,\n 'source must be a valid non-empty CloudEvents URI-reference',\n ),\n type: AISnitchEventTypeSchema,\n time: ISO_TIMESTAMP_SCHEMA,\n 'aisnitch.tool': ToolNameSchema,\n 'aisnitch.sessionid': z.string().min(1).max(500),\n 'aisnitch.seqnum': z.number().int().min(1),\n data: EventDataSchema,\n});\n","import { AISnitchEventSchema, createUuidV7 } from './schema.js';\nimport type { AISnitchEvent, CreateEventInput } from './types.js';\n\n/**\n * @file src/core/events/factory.ts\n * @description Factory helpers for producing validated AISnitch events with generated CloudEvents fields.\n * @functions\n * โ†’ createEvent\n * @exports createEvent\n * @see ./schema.ts\n */\n\n/**\n * Builds a fully valid AISnitch event by attaching CloudEvents metadata and\n * validating the final payload before it leaves the factory.\n */\nexport function createEvent(input: CreateEventInput): AISnitchEvent {\n const eventCandidate = {\n ...input,\n specversion: '1.0' as const,\n id: createUuidV7(),\n time: new Date().toISOString(),\n data: {\n state: input.data?.state ?? input.type,\n ...input.data,\n },\n };\n\n /**\n * ๐Ÿ“– Parsing at the factory boundary gives every future adapter the same\n * guardrail: if it emits junk, it fails immediately and loudly.\n */\n return AISnitchEventSchema.parse(eventCandidate);\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n AISnitchEventType,\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/claude-code.ts\n * @description Claude Code adapter covering official hooks, transcript JSONL enrichment, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports ClaudeCodeAdapter, ClaudeCodeAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/04-adapters-priority/02_adapters-priority_claude-code.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst CLAUDE_CODE_CODING_TOOLS = new Set([\n 'Edit',\n 'MultiEdit',\n 'NotebookEdit',\n 'Write',\n]);\n\nconst ASKING_USER_NOTIFICATION_TYPES = new Set([\n 'elicitation_dialog',\n 'idle_prompt',\n 'permission_prompt',\n]);\n\n/**\n * The official Claude hooks reference currently documents 25 lifecycle events,\n * including newer events such as SessionEnd, PostCompact, and ElicitationResult.\n * AISnitch only maps the subset that materially improves live activity tracking.\n */\nexport interface ClaudeCodeAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly projectsDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface ClaudeProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface ClaudeTranscriptObservation {\n readonly context: AdapterPublishContext;\n readonly data: Omit<EventData, 'state'>;\n readonly type: AISnitchEventType;\n}\n\n/**\n * ๐Ÿ“– Claude Code is AISnitch's richest adapter: hooks give precise state\n * transitions, JSONL fills in thinking/streaming detail, and process polling\n * covers the ugly \"hooks were never installed\" case.\n */\nexport class ClaudeCodeAdapter extends BaseAdapter {\n public override readonly displayName = 'Claude Code';\n\n public override readonly name = 'claude-code' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'jsonl-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly projectsDirectory: string;\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: ClaudeCodeAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ?? (async () => await execFile('pgrep', ['-lf', 'claude']).then((result) => result.stdout));\n this.projectsDirectory =\n options.projectsDirectory ??\n join(this.getUserHomeDirectory(), '.claude', 'projects');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n const transcriptGlob = join(this.projectsDirectory, '**', '*.jsonl');\n this.watcher = this.watcherFactory(transcriptGlob, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processTranscriptUpdate(filePath, true);\n });\n this.watcher.on('change', (filePath) => {\n void this.processTranscriptUpdate(filePath, false);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Claude transcript watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Claude hook payload must be an object');\n return;\n }\n\n const hookEventName =\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hook_type');\n\n if (!hookEventName) {\n logger.warn({ payload }, 'Claude hook payload is missing its event name');\n return;\n }\n\n const sessionId = resolveSessionId({\n activeFile: extractActiveFile(payload),\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath:\n getString(payload, 'project_path') ??\n getString(payload, 'projectPath'),\n sessionId:\n getString(payload, 'session_id') ??\n getString(payload, 'sessionId'),\n tool: this.name,\n transcriptPath:\n getString(payload, 'transcript_path') ??\n getString(payload, 'transcriptPath'),\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n // ๐Ÿ“– Pass process.env so the context detector can detect the terminal\n // from TERM_PROGRAM, ITERM_SESSION_ID, etc. โ€” hooks don't carry env vars\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/claude-code',\n transcriptPath:\n getString(payload, 'transcript_path') ??\n getString(payload, 'transcriptPath'),\n };\n const sharedData = {\n activeFile: extractActiveFile(payload),\n cwd: context.cwd,\n model: getString(payload, 'model'),\n projectPath:\n getString(payload, 'project_path') ??\n getString(payload, 'projectPath'),\n raw: payload,\n toolInput: extractClaudeToolInput(payload),\n toolName:\n getString(payload, 'tool_name') ??\n getString(payload, 'toolName'),\n } satisfies Omit<EventData, 'state'>;\n\n switch (hookEventName) {\n case 'SessionStart': {\n this.fallbackProcessSessionId = null;\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'SessionEnd': {\n const finalMessage = extractFinalMessageFromPayload(payload);\n await this.emitStateChange('session.end', {\n ...sharedData,\n finalMessage,\n }, context);\n return;\n }\n case 'UserPromptSubmit':\n case 'TaskCreated':\n case 'SubagentStart': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'Stop':\n case 'TaskCompleted':\n case 'SubagentStop': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'PreToolUse': {\n const toolCallName = extractToolNameFromPayload(payload);\n await this.emitStateChange('agent.tool_call', {\n ...sharedData,\n toolCallName,\n }, context);\n return;\n }\n case 'PostToolUse': {\n const toolCallName = extractToolNameFromPayload(payload);\n const toolResult = extractToolResultFromPayload(payload);\n const emittedType = isClaudeCodingTool(sharedData.toolName)\n ? 'agent.coding'\n : 'agent.tool_call';\n await this.emitStateChange(emittedType, {\n ...sharedData,\n toolCallName,\n toolResult,\n }, context);\n return;\n }\n case 'PostToolUseFailure':\n case 'StopFailure': {\n await this.emitStateChange(\n 'agent.error',\n {\n ...sharedData,\n errorMessage:\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n 'Claude Code hook failure',\n errorType:\n getClaudeErrorType(payload) ??\n 'tool_failure',\n },\n context,\n );\n return;\n }\n case 'PermissionRequest': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n case 'Notification': {\n const notificationType =\n getString(payload, 'notification_type') ??\n getString(payload, 'type');\n\n if (notificationType && ASKING_USER_NOTIFICATION_TYPES.has(notificationType)) {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n }\n\n return;\n }\n case 'PreCompact':\n case 'PostCompact': {\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n case 'TeammateIdle': {\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n default: {\n logger.debug({ hookEventName }, 'Claude hook event ignored by adapter');\n }\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Claude transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ??\n (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Claude transcript line is not valid JSON');\n return;\n }\n\n const observations = extractClaudeTranscriptObservations(\n parsedLine,\n transcriptPath,\n );\n\n for (const observation of observations) {\n await this.emitStateChange(\n observation.type,\n observation.data,\n observation.context,\n );\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n const files = await collectFilesRecursively(this.projectsDirectory, '.jsonl');\n\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollClaudeProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollClaudeProcesses();\n }\n\n private async pollClaudeProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `claude-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/claude-code/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/claude-code/process-detect',\n },\n );\n }\n }\n}\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, {\n withFileTypes: true,\n });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractClaudeTranscriptObservations(\n payload: unknown,\n transcriptPath: string,\n): ClaudeTranscriptObservation[] {\n if (!isRecord(payload)) {\n return [];\n }\n\n const sessionId = resolveSessionId({\n sessionId:\n getString(payload, 'session_id') ??\n basename(transcriptPath, '.jsonl'),\n tool: 'claude-code',\n transcriptPath,\n });\n const contentParts = extractClaudeContentParts(payload);\n const model =\n getString(payload, 'model') ??\n getString(getRecord(payload.message), 'model');\n const tokensUsed = extractTokenUsage(payload);\n const rawPayload = payload;\n const sharedContext: AdapterPublishContext = {\n // ๐Ÿ“– Pass process.env so terminal detection works from transcript path too\n env: process.env,\n hookPayload: rawPayload,\n sessionId,\n source: 'aisnitch://adapters/claude-code/transcript',\n transcriptPath,\n };\n const sharedData = {\n model,\n raw: rawPayload,\n tokensUsed,\n } satisfies Omit<EventData, 'state'>;\n const observations: ClaudeTranscriptObservation[] = [];\n\n if (contentParts.some((part) => part.type === 'thinking')) {\n const thinkingParts = contentParts.filter((part) => part.type === 'thinking');\n // ๐Ÿ“– Extract thinking content from thinking-type content parts\n const thinkingText = thinkingParts\n .map((part) => {\n const text = part.text;\n return typeof text === 'string' ? text : undefined;\n })\n .filter((text): text is string => text !== undefined)\n .join('\\n');\n\n observations.push({\n context: sharedContext,\n data: {\n ...sharedData,\n thinkingContent: thinkingText.length > 0 ? thinkingText : undefined,\n },\n type: 'agent.thinking',\n });\n }\n\n if (\n contentParts.some(\n (part) =>\n part.type === 'text' &&\n typeof part.text === 'string' &&\n part.text.trim().length > 0,\n )\n ) {\n // ๐Ÿ“– Extract message content from text-type content parts\n const messageTexts = contentParts\n .filter((part) => part.type === 'text')\n .map((part) => part.text as string)\n .filter((text) => text.trim().length > 0);\n const messageContent = messageTexts.join('\\n');\n\n observations.push({\n context: sharedContext,\n data: {\n ...sharedData,\n messageContent: messageContent.length > 0 ? messageContent : undefined,\n },\n type: 'agent.streaming',\n });\n }\n\n // Check for tool_use observations (tool calls in transcript)\n const toolUseParts = contentParts.filter(\n (part) => part.type === 'tool_use' || part.type === 'toolUse',\n );\n if (toolUseParts.length > 0) {\n const toolName = getString(toolUseParts[0], 'name') ?? getString(toolUseParts[0], 'tool');\n if (toolName) {\n observations.push({\n context: sharedContext,\n data: {\n ...sharedData,\n toolCallName: toolName,\n },\n type: 'agent.tool_call',\n });\n }\n }\n\n return observations;\n}\n\nfunction extractClaudeContentParts(\n payload: Record<string, unknown>,\n): Array<Record<string, unknown>> {\n const message = getRecord(payload.message);\n const content = message?.content ?? payload.content;\n\n if (!Array.isArray(content)) {\n return [];\n }\n\n return content.filter(isRecord);\n}\n\nfunction extractTokenUsage(payload: Record<string, unknown>): number | undefined {\n const tokens = getNumber(payload, 'tokens');\n\n if (tokens !== undefined) {\n return tokens;\n }\n\n const usage = getRecord(payload.usage);\n\n if (!usage) {\n return undefined;\n }\n\n const totalTokens = getNumber(usage, 'total_tokens');\n\n if (totalTokens !== undefined) {\n return totalTokens;\n }\n\n const inputTokens = getNumber(usage, 'input_tokens') ?? 0;\n const outputTokens = getNumber(usage, 'output_tokens') ?? 0;\n const usageSum = inputTokens + outputTokens;\n\n return usageSum > 0 ? usageSum : undefined;\n}\n\nfunction extractClaudeToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);\n\n if (!toolInput) {\n return undefined;\n }\n\n const filePath =\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'path');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction extractActiveFile(payload: Record<string, unknown>): string | undefined {\n const toolInput = extractClaudeToolInput(payload);\n\n if (toolInput?.filePath) {\n return toolInput.filePath;\n }\n\n return (\n getString(payload, 'active_file') ??\n getString(payload, 'activeFile') ??\n getString(payload, 'file_path')\n );\n}\n\nfunction getClaudeErrorType(payload: Record<string, unknown>): ErrorType | undefined {\n const rawErrorType =\n getString(payload, 'error_type') ??\n getString(payload, 'errorType') ??\n getString(payload, 'stop_reason');\n\n switch (rawErrorType) {\n case 'rate_limit':\n return 'rate_limit';\n case 'max_output_tokens':\n case 'context_overflow':\n return 'context_overflow';\n case 'api_error':\n case 'server_error':\n case 'authentication_failed':\n case 'billing_error':\n case 'invalid_request':\n return 'api_error';\n default:\n return undefined;\n }\n}\n\nfunction isClaudeCodingTool(toolName?: string): boolean {\n return toolName !== undefined && CLAUDE_CODE_CODING_TOOLS.has(toolName);\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<ClaudeProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map(parseProcessLine)\n .filter((processInfo): processInfo is ClaudeProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode = isErrnoException(error) ? String(error.code) : '';\n\n if (isErrnoException(error) && (errorCode === 'ENOENT' || errorCode === '1')) {\n return [];\n }\n\n logger.debug({ error }, 'Claude process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): ClaudeProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException & { code?: string | number } {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the tool name from Claude hook payload.\n * Claude hooks use `tool_use` or `toolName` fields to identify the tool.\n * Common tool names: Edit, Bash, Grep, Read, Write, WebSearch, etc.\n */\nfunction extractToolNameFromPayload(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct tool name field\n const directToolName = getString(payload, 'tool_name') ?? getString(payload, 'toolName');\n\n if (directToolName) {\n return directToolName;\n }\n\n // From tool_use object\n const toolUse = getRecord(payload.tool_use) ?? getRecord(payload.toolUse);\n if (toolUse) {\n return getString(toolUse, 'name') ?? getString(toolUse, 'tool');\n }\n\n // From tool_input object (tool name might be in parent or type field)\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);\n if (toolInput) {\n return getString(toolInput, 'tool_name') ?? getString(toolInput, 'type');\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the tool execution result from Claude hook payload.\n * Contains success messages, error outputs, or short tool results.\n */\nfunction extractToolResultFromPayload(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct result field\n const directResult = getString(payload, 'result') ?? getString(payload, 'output');\n\n if (directResult) {\n return directResult;\n }\n\n // From tool_result object\n const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);\n if (toolResult) {\n return getString(toolResult, 'content') ?? getString(toolResult, 'output');\n }\n\n // From error field if PostToolUseFailure\n const errorField = getString(payload, 'error') ?? getString(payload, 'error_message');\n if (errorField) {\n return errorField;\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the final/completion message from Claude hook payload.\n * This is the summary text shown at the end of an AI run.\n */\nfunction extractFinalMessageFromPayload(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct final message fields\n const directMessage =\n getString(payload, 'final_message') ??\n getString(payload, 'finalMessage') ??\n getString(payload, 'summary') ??\n getString(payload, 'completion_message');\n\n if (directMessage) {\n return directMessage;\n }\n\n // From result or output fields\n const result =\n getString(payload, 'result') ??\n getString(payload, 'output') ??\n getString(payload, 'message');\n\n if (result) {\n return result;\n }\n\n // From session data or stats\n const stats = getRecord(payload.stats);\n if (stats) {\n return getString(stats, 'summary') ?? getString(stats, 'completion_summary');\n }\n\n return undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { ErrorType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/copilot-cli.ts\n * @description Copilot CLI adapter covering repository hooks, passive session-state JSONL watching, workspace metadata enrichment, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports CopilotCLIAdapter, CopilotCLIAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/02_adapters-secondary_goose-copilot_DONE.md\n */\n\nconst execFile = promisify(execFileCallback);\nconst COPILOT_CODING_TOOL_HINT =\n /apply|create|delete|edit|insert|move|patch|rename|replace|write/iu;\n\nexport interface CopilotCLIAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly sessionStateDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface CopilotProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface CopilotSessionMetadata {\n readonly branch?: string;\n readonly cwd?: string;\n readonly gitRoot?: string;\n readonly model?: string;\n readonly repository?: string;\n readonly sessionId: string;\n}\n\n/**\n * ๐Ÿ“– Copilot's local session-state files are rich enough that hooks become a\n * precision upgrade rather than the only usable signal. The adapter therefore\n * merges both paths instead of trusting just one.\n */\nexport class CopilotCLIAdapter extends BaseAdapter {\n public override readonly displayName = 'Copilot CLI';\n\n public override readonly name = 'copilot-cli' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'jsonl-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly observedEventIds = new Set<string>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionMetadata = new Map<string, CopilotSessionMetadata>();\n\n private readonly sessionStateDirectory: string;\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: CopilotCLIAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'copilot']).then(\n (result) => result.stdout,\n ));\n this.sessionStateDirectory =\n options.sessionStateDirectory ??\n join(this.getUserHomeDirectory(), '.copilot', 'session-state');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n const transcriptGlob = join(this.sessionStateDirectory, '**', '*.jsonl');\n this.watcher = this.watcherFactory(transcriptGlob, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processTranscriptUpdate(filePath, true);\n });\n this.watcher.on('change', (filePath) => {\n void this.processTranscriptUpdate(filePath, false);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Copilot session-state watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.observedEventIds.clear();\n this.sessionMetadata.clear();\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Copilot hook payload must be an object');\n return;\n }\n\n const hookEventName =\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hookEventName');\n\n if (!hookEventName) {\n logger.warn({ payload }, 'Copilot hook payload is missing its event name');\n return;\n }\n\n const sessionMetadata = await this.resolveSessionMetadata(\n this.resolveRawSessionId(payload) ?? 'copilot-hook-session',\n );\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd') ?? sessionMetadata.cwd,\n project: sessionMetadata.repository,\n projectPath: sessionMetadata.gitRoot ?? sessionMetadata.cwd,\n sessionId: this.resolveRawSessionId(payload),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd') ?? sessionMetadata.cwd,\n hookPayload: payload,\n sessionId,\n source: 'aisnitch://adapters/copilot-cli',\n };\n const toolInput = extractCopilotHookToolInput(payload);\n const toolName =\n getString(payload, 'toolName') ?? getString(payload, 'tool_name');\n const toolResult =\n getRecord(payload.toolResult) ?? getRecord(payload.tool_result);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: sessionMetadata.model,\n project: sessionMetadata.repository,\n projectPath: sessionMetadata.gitRoot ?? sessionMetadata.cwd,\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (hookEventName) {\n case 'sessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'userPromptSubmitted': {\n await this.emitStateChange(\n 'task.start',\n {\n ...sharedData,\n raw: {\n ...payload,\n prompt: getString(payload, 'prompt'),\n },\n },\n context,\n );\n return;\n }\n case 'preToolUse': {\n const emittedType = isCopilotCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'postToolUse': {\n const emittedType = isCopilotCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n const resultType =\n getString(toolResult, 'resultType') ??\n getString(toolResult, 'result_type');\n const resultText =\n getString(toolResult, 'textResultForLlm') ??\n getString(toolResult, 'text_result_for_llm') ??\n getString(toolResult, 'message');\n\n if (resultType === 'failure' || resultType === 'denied') {\n await this.emitStateChange(\n 'agent.error',\n {\n ...sharedData,\n errorMessage:\n resultText ??\n `Copilot tool ${toolName ?? 'unknown'} finished with ${resultType}.`,\n errorType: inferCopilotErrorType(resultText) ?? 'tool_failure',\n raw: payload,\n },\n context,\n );\n return;\n }\n\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'sessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'errorOccurred': {\n const errorPayload = getRecord(payload.error);\n const errorMessage =\n getString(errorPayload, 'message') ??\n getString(payload, 'message');\n\n await this.emitStateChange(\n 'agent.error',\n {\n ...sharedData,\n errorMessage,\n errorType: inferCopilotErrorType(errorMessage),\n raw: payload,\n },\n context,\n );\n return;\n }\n default:\n logger.debug({ hookEventName }, 'Copilot hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Copilot transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ??\n (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n filePath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, filePath }, 'Copilot transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n const rawSessionId = this.resolveRawSessionId(parsedLine) ?? inferSessionIdFromPath(filePath);\n\n if (!rawSessionId) {\n return;\n }\n\n const metadata = await this.resolveSessionMetadata(rawSessionId, parsedLine, filePath);\n const sessionId = resolveSessionId({\n cwd: metadata.cwd,\n project: metadata.repository,\n projectPath: metadata.gitRoot ?? metadata.cwd,\n sessionId: rawSessionId,\n tool: this.name,\n });\n const eventId = getString(parsedLine, 'id');\n const dedupeKey = eventId ? `${sessionId}:${eventId}` : undefined;\n\n if (dedupeKey) {\n if (this.observedEventIds.has(dedupeKey)) {\n return;\n }\n\n if (this.observedEventIds.size >= 4096) {\n this.observedEventIds.clear();\n }\n\n this.observedEventIds.add(dedupeKey);\n }\n\n const context: AdapterPublishContext = {\n cwd: metadata.cwd,\n sessionId,\n source: 'aisnitch://adapters/copilot-cli/session-state',\n transcriptPath: filePath,\n };\n const eventType = getString(parsedLine, 'type');\n const eventData = getRecord(parsedLine.data);\n\n switch (eventType) {\n case 'session.start': {\n await this.emitStateChange(\n 'session.start',\n buildCopilotEventData(metadata, {\n raw: parsedLine,\n }),\n context,\n );\n await this.emitStateChange(\n 'agent.idle',\n buildCopilotEventData(metadata, {\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'user.message': {\n await this.emitStateChange(\n 'task.start',\n buildCopilotEventData(metadata, {\n raw: {\n ...parsedLine,\n prompt: getString(eventData, 'content'),\n },\n }),\n context,\n );\n return;\n }\n case 'assistant.message': {\n await this.processAssistantMessage(parsedLine, metadata, context);\n return;\n }\n case 'tool.execution_start': {\n const toolName = getString(eventData, 'toolName');\n const toolInput = extractCopilotToolInput(eventData);\n const emittedType = isCopilotCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n\n await this.emitStateChange(\n emittedType,\n buildCopilotEventData(metadata, {\n activeFile: toolInput?.filePath,\n raw: parsedLine,\n toolInput,\n toolName,\n }),\n context,\n );\n return;\n }\n case 'tool.execution_complete': {\n if (getBoolean(eventData, 'success') !== false) {\n return;\n }\n\n await this.emitStateChange(\n 'agent.error',\n buildCopilotEventData(metadata, {\n errorMessage:\n extractLooseString(getRecord(eventData?.result), ['content']) ??\n 'Tool execution failed',\n errorType: 'tool_failure',\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.task_complete': {\n await this.emitStateChange(\n 'task.complete',\n buildCopilotEventData(metadata, {\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.error': {\n const errorMessage = getString(eventData, 'message');\n\n await this.emitStateChange(\n 'agent.error',\n buildCopilotEventData(metadata, {\n errorMessage,\n errorType: inferCopilotErrorType(errorMessage),\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.warning': {\n await this.emitStateChange(\n 'agent.asking_user',\n buildCopilotEventData(metadata, {\n errorMessage: getString(eventData, 'message'),\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'abort': {\n await this.emitStateChange(\n 'agent.error',\n buildCopilotEventData(metadata, {\n errorMessage: 'Session aborted',\n errorType: 'api_error',\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.model_change': {\n const model = getString(eventData, 'newModel');\n\n this.sessionMetadata.set(rawSessionId, {\n ...metadata,\n model: model ?? metadata.model,\n });\n return;\n }\n default:\n return;\n }\n }\n\n private async processAssistantMessage(\n payload: Record<string, unknown>,\n metadata: CopilotSessionMetadata,\n context: AdapterPublishContext,\n ): Promise<void> {\n const data = getRecord(payload.data);\n\n if (!data) {\n return;\n }\n\n const reasoningText = getString(data, 'reasoningText');\n const content = getString(data, 'content');\n\n if (reasoningText) {\n await this.emitStateChange(\n 'agent.thinking',\n buildCopilotEventData(metadata, {\n raw: {\n message: {\n content: [\n {\n thinking: reasoningText,\n type: 'thinking',\n },\n ],\n role: 'assistant',\n },\n source: payload,\n },\n }),\n context,\n );\n }\n\n if (content) {\n await this.emitStateChange(\n 'agent.streaming',\n buildCopilotEventData(metadata, {\n raw: {\n content,\n message: {\n content: [\n {\n text: content,\n type: 'text',\n },\n ],\n role: 'assistant',\n },\n source: payload,\n },\n }),\n context,\n );\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n const files = await collectFilesRecursively(\n this.sessionStateDirectory,\n '.jsonl',\n );\n\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollCopilotProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollCopilotProcesses();\n }\n\n private async pollCopilotProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `copilot-cli-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/copilot-cli/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/copilot-cli/process-detect',\n },\n );\n }\n }\n\n private resolveRawSessionId(payload: Record<string, unknown>): string | undefined {\n return (\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(getRecord(payload.data), 'sessionId') ??\n getString(getRecord(payload.data), 'session_id')\n );\n }\n\n private async resolveSessionMetadata(\n rawSessionId: string,\n payload?: Record<string, unknown>,\n filePath?: string,\n ): Promise<CopilotSessionMetadata> {\n const cachedMetadata = this.sessionMetadata.get(rawSessionId);\n const payloadMetadata = extractCopilotSessionMetadata(payload);\n\n if (payloadMetadata.cwd) {\n const mergedMetadata = {\n ...cachedMetadata,\n ...payloadMetadata,\n sessionId: rawSessionId,\n } satisfies CopilotSessionMetadata;\n\n this.sessionMetadata.set(rawSessionId, mergedMetadata);\n return mergedMetadata;\n }\n\n const fileMetadata = await readCopilotWorkspaceMetadata(\n this.sessionStateDirectory,\n rawSessionId,\n filePath,\n );\n const mergedMetadata = {\n ...cachedMetadata,\n ...fileMetadata,\n sessionId: rawSessionId,\n } satisfies CopilotSessionMetadata;\n\n this.sessionMetadata.set(rawSessionId, mergedMetadata);\n return mergedMetadata;\n }\n}\n\nfunction buildCopilotEventData(\n metadata: CopilotSessionMetadata,\n overrides: Partial<Omit<EventData, 'state'>> = {},\n): Omit<EventData, 'state'> {\n return {\n cwd: overrides.cwd ?? metadata.cwd,\n model: overrides.model ?? metadata.model,\n project: overrides.project ?? metadata.repository,\n projectPath: overrides.projectPath ?? metadata.gitRoot ?? metadata.cwd,\n raw: overrides.raw,\n ...overrides,\n };\n}\n\nfunction extractCopilotHookToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolArgsValue =\n getString(payload, 'toolArgs') ?? getString(payload, 'tool_args');\n const directArguments =\n getRecord(payload.arguments) ?? getRecord(payload.toolArgs);\n const parsedArguments =\n directArguments ?? parseJsonRecord(toolArgsValue);\n\n return extractCopilotToolInput(parsedArguments);\n}\n\nfunction extractCopilotToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const filePath = extractFirstString(payload, [\n 'file',\n 'file_path',\n 'filePath',\n 'path',\n 'target',\n 'target_path',\n 'targetPath',\n ]);\n const command = extractFirstString(payload, [\n 'cmd',\n 'command',\n 'script',\n ]);\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction isCopilotCodingTool(\n toolName: string | undefined,\n toolInput: ToolInput | undefined,\n): boolean {\n if (toolName && COPILOT_CODING_TOOL_HINT.test(toolName)) {\n return true;\n }\n\n const filePath = toolInput?.filePath;\n\n if (!filePath) {\n return false;\n }\n\n return !/glob|grep|list|read|search|view/iu.test(toolName ?? '');\n}\n\nfunction inferCopilotErrorType(\n errorMessage: string | undefined,\n): ErrorType | undefined {\n if (!errorMessage) {\n return undefined;\n }\n\n if (/quota|credit|rate limit|too many requests/iu.test(errorMessage)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|too long/iu.test(errorMessage)) {\n return 'context_overflow';\n }\n\n if (/tool/iu.test(errorMessage)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nfunction extractCopilotSessionMetadata(\n payload: Record<string, unknown> | undefined,\n): Partial<CopilotSessionMetadata> {\n const data = getRecord(payload?.data);\n const context = getRecord(data?.context);\n\n return {\n branch:\n getString(context, 'branch') ??\n getString(payload, 'branch'),\n cwd:\n getString(context, 'cwd') ??\n getString(payload, 'cwd'),\n gitRoot:\n getString(context, 'gitRoot') ??\n getString(payload, 'gitRoot'),\n repository:\n getString(context, 'repository') ??\n getString(payload, 'repository'),\n };\n}\n\nasync function readCopilotWorkspaceMetadata(\n sessionStateDirectory: string,\n rawSessionId: string,\n filePath?: string,\n): Promise<Partial<CopilotSessionMetadata>> {\n const sessionDirectory = inferSessionDirectory(\n sessionStateDirectory,\n rawSessionId,\n filePath,\n );\n const workspacePath = join(sessionDirectory, 'workspace.yaml');\n\n try {\n const fileContent = await readFile(workspacePath, 'utf8');\n\n return parseCopilotWorkspaceYaml(fileContent);\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return {};\n }\n\n logger.debug({ error, rawSessionId }, 'Copilot workspace metadata read skipped');\n return {};\n }\n}\n\nfunction parseCopilotWorkspaceYaml(\n fileContent: string,\n): Partial<CopilotSessionMetadata> {\n const metadata: {\n branch?: string;\n cwd?: string;\n gitRoot?: string;\n repository?: string;\n } = {};\n\n for (const line of fileContent.split(/\\r?\\n/u)) {\n const match = line.match(/^([a-z_]+):\\s*(.+)$/u);\n\n if (!match) {\n continue;\n }\n\n const key = match[1];\n const value = match[2]?.trim();\n\n if (!value) {\n continue;\n }\n\n switch (key) {\n case 'branch':\n metadata.branch = value;\n break;\n case 'cwd':\n metadata.cwd = value;\n break;\n case 'git_root':\n metadata.gitRoot = value;\n break;\n case 'repository':\n metadata.repository = value;\n break;\n default:\n break;\n }\n }\n\n return metadata;\n}\n\nfunction inferSessionDirectory(\n sessionStateDirectory: string,\n rawSessionId: string,\n filePath?: string,\n): string {\n if (filePath && basename(filePath) === 'events.jsonl') {\n return dirname(filePath);\n }\n\n return join(sessionStateDirectory, rawSessionId);\n}\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, {\n withFileTypes: true,\n });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nasync function listProcesses(\n processListCommand: () => Promise<string>,\n): Promise<CopilotProcessInfo[]> {\n try {\n const commandOutput = await processListCommand();\n\n return commandOutput\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const [pidPart, ...commandParts] = line.split(/\\s+/u);\n const pid = pidPart ? Number.parseInt(pidPart, 10) : Number.NaN;\n\n return {\n command: commandParts.join(' '),\n pid,\n } satisfies CopilotProcessInfo;\n })\n .filter((processInfo) => Number.isInteger(processInfo.pid));\n } catch (error) {\n logger.debug({ error }, 'Copilot process listing skipped');\n return [];\n }\n}\n\nfunction inferSessionIdFromPath(filePath: string): string | undefined {\n const fileName = basename(filePath);\n\n if (fileName === 'events.jsonl') {\n return basename(dirname(filePath));\n }\n\n return fileName.endsWith('.jsonl') ? basename(fileName, '.jsonl') : undefined;\n}\n\nfunction parseJsonRecord(\n value: string | undefined,\n): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n\n try {\n const parsedValue = JSON.parse(value) as unknown;\n\n return getRecord(parsedValue);\n } catch {\n return undefined;\n }\n}\n\nfunction extractLooseString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n\n const nestedValue = getString(getRecord(payload[key]), 'content');\n\n if (nestedValue) {\n return nestedValue;\n }\n }\n\n return undefined;\n}\n\nfunction extractFirstString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n }\n\n return undefined;\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction getBoolean(\n payload: Record<string, unknown> | undefined,\n key: string,\n): boolean | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { EventData } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/codex.ts\n * @description Codex adapter based on passive `codex-tui.log` parsing plus process fallback detection.\n * @functions\n * โ†’ none\n * @exports CodexAdapter, CodexAdapterOptions\n * @see ./base.ts\n * @see ../../tasks/06-adapters-secondary/01_adapters-secondary_gemini-codex.md\n */\n\nconst execFile = promisify(execFileCallback);\n\n/**\n * Codex documents `codex exec --json` for machine-readable automation, but the\n * passive observer path for AISnitch today is still the local TUI log file.\n */\nexport interface CodexAdapterOptions extends AdapterRuntimeOptions {\n readonly logPath?: string;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface CodexProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– The Codex log watcher deliberately parses only high-signal lines:\n * command executions, patch targets, model selection, and shutdown markers.\n * Anything more ambitious would be fake precision over an unstable text log.\n */\nexport class CodexAdapter extends BaseAdapter {\n public override readonly displayName = 'Codex';\n\n public override readonly name = 'codex' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'log-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private lastKnownCwd: string | undefined;\n\n private lastKnownModel: string | undefined;\n\n private readonly logPath: string;\n\n private logOffset = 0;\n\n private logRemainder = '';\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: CodexAdapterOptions) {\n super(options);\n this.logPath =\n options.logPath ??\n join(this.getUserHomeDirectory(), '.codex', 'log', 'codex-tui.log');\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'codex']).then((result) => result.stdout));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedLogOffset();\n\n this.watcher = this.watcherFactory(this.logPath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processLogUpdate(filePath, true);\n });\n this.watcher.on('change', (filePath) => {\n void this.processLogUpdate(filePath, false);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Codex log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.lastKnownCwd = undefined;\n this.lastKnownModel = undefined;\n this.logOffset = 0;\n this.logRemainder = '';\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload === null) {\n logger.debug({ payload }, 'Codex ignores non-normalized hook payloads');\n return;\n }\n\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n }\n\n private async processLogUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Codex log read skipped');\n return;\n }\n\n const previousOffset = readFromStart ? 0 : this.logOffset;\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.logRemainder) +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.logOffset = fileContent.byteLength;\n this.logRemainder = remainder;\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processLogLine(trimmedLine);\n }\n }\n\n private async processLogLine(line: string): Promise<void> {\n const modelMatch = line.match(/model:\\s*([^,]+),\\s*.*effort:\\s*([^\\s]+)$/u);\n\n if (modelMatch) {\n const parsedModel = modelMatch[1]?.trim();\n\n if (parsedModel) {\n this.lastKnownModel = parsedModel;\n\n const sessionId = this.resolveLogSessionId(this.lastKnownCwd);\n const context = this.createLogContext(sessionId, this.lastKnownCwd, line);\n\n await this.ensureObservedSession(\n sessionId,\n {\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n context,\n );\n }\n\n return;\n }\n\n const parsedCommand = parseCodexCommandLine(line);\n\n if (parsedCommand !== null) {\n this.lastKnownCwd = parsedCommand.workdir ?? this.lastKnownCwd;\n\n const sessionId = this.resolveLogSessionId(parsedCommand.workdir);\n const context = this.createLogContext(sessionId, parsedCommand.workdir, line);\n\n await this.ensureObservedSession(\n sessionId,\n {\n cwd: parsedCommand.workdir,\n model: this.lastKnownModel,\n raw: {\n command: parsedCommand,\n logLine: line,\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.tool_call',\n {\n cwd: parsedCommand.workdir,\n model: this.lastKnownModel,\n raw: {\n command: parsedCommand,\n logLine: line,\n },\n toolInput: {\n command: parsedCommand.command,\n },\n toolName: 'shell',\n },\n context,\n );\n return;\n }\n\n const patchFileMatch = line.match(/^\\*\\*\\*\\s+(?:Update|Add|Delete)\\s+File:\\s+(.+)$/u);\n\n if (patchFileMatch?.[1]) {\n const activeFile = patchFileMatch[1].trim();\n const sessionId = this.resolveLogSessionId(this.lastKnownCwd);\n const context = this.createLogContext(sessionId, this.lastKnownCwd, line);\n\n await this.ensureObservedSession(\n sessionId,\n {\n activeFile,\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.coding',\n {\n activeFile,\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n context,\n );\n return;\n }\n\n if (/Shutting down Codex/iu.test(line) && this.currentSessionId !== null) {\n await this.emitStateChange(\n 'session.end',\n {\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n this.createLogContext(this.currentSessionId, this.lastKnownCwd, line),\n );\n }\n }\n\n private createLogContext(\n sessionId: string,\n cwd: string | undefined,\n line: string,\n ): AdapterPublishContext {\n return {\n cwd,\n hookPayload: {\n logLine: line,\n },\n sessionId,\n source: 'aisnitch://adapters/codex/log-watch',\n };\n }\n\n private resolveLogSessionId(cwd: string | undefined): string {\n return resolveSessionId({\n cwd,\n projectPath: cwd,\n sessionId: `${this.name}:session`,\n tool: this.name,\n });\n }\n\n private async ensureObservedSession(\n sessionId: string,\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n if (this.currentSessionId === sessionId) {\n return;\n }\n\n await this.emitStateChange('session.start', data, context);\n await this.emitStateChange('agent.idle', data, context);\n }\n\n private async seedLogOffset(): Promise<void> {\n try {\n const fileStats = await stat(this.logPath);\n\n this.logOffset = fileStats.size;\n } catch {\n this.logOffset = 0;\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollCodexProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollCodexProcesses();\n }\n\n private async pollCodexProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `codex-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/codex/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/codex/process-detect',\n },\n );\n }\n }\n}\n\ninterface ParsedCodexCommand {\n readonly command: string;\n readonly workdir?: string;\n}\n\nfunction parseCodexCommandLine(line: string): ParsedCodexCommand | null {\n const jsonStart = line.indexOf('{');\n const jsonEnd = line.lastIndexOf('}');\n\n if (jsonStart < 0 || jsonEnd <= jsonStart) {\n return null;\n }\n\n try {\n const parsedJson = JSON.parse(line.slice(jsonStart, jsonEnd + 1)) as unknown;\n\n if (!isRecord(parsedJson)) {\n return null;\n }\n\n const command = getString(parsedJson, 'command');\n\n if (!command) {\n return null;\n }\n\n return {\n command,\n workdir: getString(parsedJson, 'workdir'),\n };\n } catch {\n return null;\n }\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<CodexProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map(parseProcessLine)\n .filter((processInfo): processInfo is CodexProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode = isErrnoException(error) ? String(error.code) : '';\n\n if (isErrnoException(error) && (errorCode === 'ENOENT' || errorCode === '1')) {\n return [];\n }\n\n logger.debug({ error }, 'Codex process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): CodexProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException & { code?: string | number } {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/cursor.ts\n * @description Cursor CLI adapter covering process detection, JSON output interception,\n * and log file watching for the Cursor agent terminal.\n * @functions\n * โ†’ none\n * @exports CursorAdapter, CursorAdapterOptions\n * @see ./base.ts\n * @see ../../docs/priority-adapters.md\n *\n * ๐Ÿ“– Cursor CLI is the command-line interface to Cursor's AI agent. It supports\n * structured JSON output (`--output-format json`), process detection for running\n * instances, and writes session logs to Library/Application Support/Cursor/.\n * Interception strategy: process-detect primary, JSON line watching as fallback.\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst CURSOR_CODING_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'NotebookEdit',\n 'CreateFile',\n 'DeleteFile',\n 'MoveFile',\n]);\n\nexport interface CursorAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly logDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface CursorProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– Cursor CLI lacks a formal hook system but emits structured logs via its\n * background process and supports JSON output mode. The adapter uses process\n * polling as the primary detection mechanism and log watching as secondary.\n */\nexport class CursorAdapter extends BaseAdapter {\n public override readonly displayName = 'Cursor CLI';\n\n public override readonly name = 'cursor' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'jsonl-watch',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly logDirectory: string;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: CursorAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () => {\n const results = await Promise.all([\n execFile('pgrep', ['-lf', 'cursor-agent']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'cursor']).catch(() => ({ stdout: '' })),\n ]);\n return results.map((r) => r.stdout).join('\\n');\n });\n this.logDirectory =\n options.logDirectory ??\n join(this.getUserHomeDirectory(), 'Library', 'Application Support', 'Cursor');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n // Watch for Cursor log files in various locations\n const logPatterns = [\n join(this.logDirectory, 'logs', '**', '*.jsonl'),\n join(this.logDirectory, 'agent', '**', '*.jsonl'),\n ];\n\n this.watcher = this.watcherFactory(logPatterns[0]!, {\n awaitWriteFinish: { stabilityThreshold: 200 },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => void this.processTranscriptUpdate(filePath, true));\n this.watcher.on('change', (filePath) => void this.processTranscriptUpdate(filePath, false));\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Cursor log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Cursor hook payload must be an object');\n return;\n }\n\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath: getString(payload, 'projectPath'),\n sessionId: getString(payload, 'sessionId') ?? getString(payload, 'session_id'),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/cursor',\n };\n const eventType = getString(payload, 'event') ?? getString(payload, 'type');\n const toolName = getString(payload, 'tool') ?? getString(payload, 'toolName');\n const toolInput = extractToolInput(payload);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: getString(payload, 'model'),\n projectPath: getString(payload, 'projectPath'),\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session_start':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session_end':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task_start':\n case 'TaskStart':\n case 'UserPromptSubmit': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task_complete':\n case 'TaskComplete':\n case 'TaskCompleted': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'tool_call':\n case 'PreToolUse': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'tool_result':\n case 'PostToolUse': {\n const emittedType = isCursorCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'streaming':\n case 'Streaming':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(payload, 'error') ?? getString(payload, 'message') ?? 'Cursor error',\n errorType: inferCursorErrorType(payload),\n }, context);\n return;\n }\n case 'asking_user':\n case 'PermissionRequest':\n case 'Notification': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n logger.debug({ eventType }, 'Cursor hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Cursor transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ?? (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') + newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Cursor transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n const sessionId = resolveSessionId({\n sessionId:\n getString(parsedLine, 'sessionId') ??\n getString(parsedLine, 'session_id') ??\n basename(transcriptPath, '.jsonl'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n env: process.env,\n hookPayload: parsedLine,\n sessionId,\n source: 'aisnitch://adapters/cursor/log',\n transcriptPath,\n };\n const eventType = getString(parsedLine, 'type') ?? getString(parsedLine, 'event');\n const data = getRecord(parsedLine.data) ?? parsedLine;\n const toolName = getString(data, 'toolName') ?? getString(data, 'tool');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n model: getString(data, 'model'),\n raw: parsedLine,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n // Map Cursor log types to AISnitch event types\n switch (eventType) {\n case 'session.start':\n case 'session_start': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'session_end': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'task_start': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'task_complete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'agent.thinking':\n case 'thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'agent.streaming':\n case 'streaming':\n case 'assistant.message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'agent.tool_call':\n case 'tool_use': {\n const emittedType = isCursorCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'agent.error':\n case 'error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(data, 'message'),\n errorType: inferCursorErrorType(data),\n }, context);\n return;\n }\n case 'agent.asking_user':\n case 'permission_required': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n return;\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n try {\n const files = await collectFilesRecursively(\n join(this.logDirectory, 'logs'),\n '.jsonl',\n );\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n } catch {\n // Logs directory may not exist yet on first run.\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollCursorProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollCursorProcesses();\n }\n\n private async pollCursorProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `cursor-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n { raw: { process: processInfo, source: 'process-detect' } },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/cursor/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n { raw: { reason: 'process-exit', source: 'process-detect' } },\n {\n sessionId,\n source: 'aisnitch://adapters/cursor/process-detect',\n },\n );\n }\n }\n}\n\n// โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput) ?? getRecord(payload.arguments);\n const filePath =\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'path');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return { command, filePath };\n}\n\nfunction isCursorCodingTool(toolName?: string): boolean {\n return toolName !== undefined && CURSOR_CODING_TOOLS.has(toolName);\n}\n\nfunction inferCursorErrorType(\n payload: Record<string, unknown> | undefined,\n): ErrorType {\n const message =\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n '';\n\n if (/rate.?limit|quota|credit/i.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token.?limit|too.?long/i.test(message)) {\n return 'context_overflow';\n }\n\n if (/tool|permission|denied/i.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<CursorProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && line.includes('cursor'))\n .map(parseProcessLine)\n .filter((processInfo): processInfo is CursorProcessInfo => processInfo !== null);\n } catch (error) {\n logger.debug({ error }, 'Cursor process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): CursorProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/devin.ts\n * @description Devin CLI adapter covering the cloud-connected AI software engineer agent.\n * @functions\n * โ†’ none\n * @exports DevinAdapter, DevinAdapterOptions\n * @see ./base.ts\n * @see ../../docs/priority-adapters.md\n *\n * ๐Ÿ“– Devin is Cognition Labs' AI software engineer CLI. It operates as a cloud-connected\n * agent with local session management. The adapter uses process detection to track when\n * the Devin CLI is running, and can receive webhook-style events if configured via the\n * Devin dashboard. Session data is stored locally in ~/.devin/.\n * Interception: process-detect primary, webhook hooks when available.\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst DEVIN_CODING_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'Create',\n 'Delete',\n 'Move',\n 'Read',\n 'Grep',\n 'Bash',\n 'WebSearch',\n]);\n\nexport interface DevinAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly sessionDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface DevinProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface DevinSessionMetadata {\n readonly cwd?: string;\n readonly model?: string;\n readonly sessionId: string;\n}\n\n/**\n * ๐Ÿ“– Devin CLI runs as a cloud-connected agent. It communicates with Cognition's\n * backend but also maintains local session state in ~/.devin/sessions/. The adapter\n * tracks process lifecycle and watches for local session data files.\n */\nexport class DevinAdapter extends BaseAdapter {\n public override readonly displayName = 'Devin CLI';\n\n public override readonly name = 'devin' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'hooks',\n 'jsonl-watch',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionDirectory: string;\n\n private readonly sessionMetadata = new Map<string, DevinSessionMetadata>();\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: DevinAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () => {\n // Devin CLI binary name varies โ€” try common patterns\n const results = await Promise.all([\n execFile('pgrep', ['-lf', 'devin']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'cognition']).catch(() => ({ stdout: '' })),\n ]);\n return results.map((r) => r.stdout).join('\\n');\n });\n this.sessionDirectory =\n options.sessionDirectory ?? join(this.getUserHomeDirectory(), '.devin');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n // Watch for Devin session logs\n this.watcher = this.watcherFactory(\n join(this.sessionDirectory, '**', '*.jsonl'),\n {\n awaitWriteFinish: { stabilityThreshold: 200 },\n ignoreInitial: true,\n },\n );\n\n this.watcher.on('add', (filePath) => void this.processTranscriptUpdate(filePath, true));\n this.watcher.on('change', (filePath) => void this.processTranscriptUpdate(filePath, false));\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Devin log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.sessionMetadata.clear();\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Devin hook payload must be an object');\n return;\n }\n\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath: getString(payload, 'projectPath'),\n sessionId:\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(payload, 'id') ??\n getString(getRecord(payload.data), 'sessionId'),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/devin',\n };\n const eventType = getString(payload, 'event') ?? getString(payload, 'type') ?? getString(payload, 'action');\n const data = getRecord(payload.data) ?? payload;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName') ?? getString(data, 'name');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: getString(data, 'model') ?? getString(payload, 'model'),\n projectPath: getString(data, 'projectPath') ?? getString(payload, 'projectPath'),\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.start':\n case 'sessionStart':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'sessionEnd':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'taskStart':\n case 'task_create':\n case 'TaskCreate': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'taskComplete':\n case 'TaskComplete':\n case 'task_done': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'tool.call':\n case 'toolCall':\n case 'ToolCall': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'tool.result':\n case 'toolResult':\n case 'ToolResult': {\n const emittedType = isDevinCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking':\n case 'reasoning': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'output':\n case 'streaming':\n case 'Output': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'error':\n case 'Error':\n case 'ErrorOccurred': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(payload, 'error') ?? 'Devin error',\n errorType: inferDevinErrorType(data),\n }, context);\n return;\n }\n case 'asking_user':\n case 'PermissionRequest':\n case 'user_input_required':\n case 'InputRequired': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n logger.debug({ eventType }, 'Devin hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Devin transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ?? (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') + newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Devin transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n const eventType = getString(parsedLine, 'type') ?? getString(parsedLine, 'event');\n const sessionId = resolveSessionId({\n sessionId:\n getString(parsedLine, 'sessionId') ??\n getString(parsedLine, 'session_id') ??\n getString(parsedLine, 'id') ??\n basename(transcriptPath, '.jsonl'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n env: process.env,\n hookPayload: parsedLine,\n sessionId,\n source: 'aisnitch://adapters/devin/log',\n transcriptPath,\n };\n const data = getRecord(parsedLine.data) ?? parsedLine;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: getString(data, 'cwd'),\n model: getString(data, 'model'),\n raw: parsedLine,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.start':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'TaskStart': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'TaskComplete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'output':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'tool_use':\n case 'ToolUse': {\n const emittedType = isDevinCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(data, 'message'),\n errorType: inferDevinErrorType(data),\n }, context);\n return;\n }\n case 'permission_request':\n case 'asking_user': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n return;\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n try {\n const files = await collectFilesRecursively(this.sessionDirectory, '.jsonl');\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n } catch {\n // Session directory may not exist yet on first run.\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollDevinProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollDevinProcesses();\n }\n\n private async pollDevinProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `devin-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n { raw: { process: processInfo, source: 'process-detect' } },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/devin/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n { raw: { reason: 'process-exit', source: 'process-detect' } },\n {\n sessionId,\n source: 'aisnitch://adapters/devin/process-detect',\n },\n );\n }\n }\n}\n\n// โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const toolInput =\n getRecord(payload.tool_input) ??\n getRecord(payload.toolInput) ??\n getRecord(payload.arguments) ??\n getRecord(payload.params);\n const filePath =\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'path') ??\n getString(toolInput, 'target');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd') ??\n getString(toolInput, 'script');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return { command, filePath };\n}\n\nfunction isDevinCodingTool(toolName?: string): boolean {\n return toolName !== undefined && DEVIN_CODING_TOOLS.has(toolName);\n}\n\nfunction inferDevinErrorType(\n payload: Record<string, unknown> | undefined,\n): ErrorType {\n const message =\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n '';\n\n if (/rate.?limit|quota|credit|api.?key/i.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token.?limit|too.?long|exceeded/i.test(message)) {\n return 'context_overflow';\n }\n\n if (/tool|permission|denied|access/i.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<DevinProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .filter(\n (line) =>\n line.includes('devin') || line.includes('cognition') || line.includes('swe'),\n )\n .map(parseProcessLine)\n .filter((processInfo): processInfo is DevinProcessInfo => processInfo !== null);\n } catch (error) {\n logger.debug({ error }, 'Devin process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): DevinProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/gemini-cli.ts\n * @description Gemini CLI adapter covering command hooks, best-effort local `logs.json` watching, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports GeminiCLIAdapter, GeminiCLIAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/01_adapters-secondary_gemini-codex.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst GEMINI_CODING_TOOLS = new Set([\n 'edit',\n 'replace',\n 'write',\n 'write_file',\n]);\n\n/**\n * Gemini CLI now documents synchronous lifecycle hooks in settings.json. The\n * passive fallback here reads the per-session `logs.json` files under\n * `~/.gemini/tmp/`, which appear to contain prompt history even when hooks\n * were never installed.\n */\nexport interface GeminiCLIAdapterOptions extends AdapterRuntimeOptions {\n readonly logsDirectory?: string;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface GeminiProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– Gemini gets the same three-layer treatment as Claude/OpenCode, but the\n * file fallback is intentionally narrower: it only emits what local logs can\n * prove, instead of pretending those logs expose the full agent loop.\n */\nexport class GeminiCLIAdapter extends BaseAdapter {\n public override readonly displayName = 'Gemini CLI';\n\n public override readonly name = 'gemini-cli' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'log-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly logsDirectory: string;\n\n private readonly observedLogMessageIds = new Map<string, Set<string>>();\n\n private readonly projectRootCache = new Map<string, string | undefined>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: GeminiCLIAdapterOptions) {\n super(options);\n this.logsDirectory =\n options.logsDirectory ??\n join(this.getUserHomeDirectory(), '.gemini', 'tmp');\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'gemini']).then((result) => result.stdout));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedObservedLogState();\n\n const logsGlob = join(this.logsDirectory, '**', 'logs.json');\n this.watcher = this.watcherFactory(logsGlob, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processLogsFile(filePath);\n });\n this.watcher.on('change', (filePath) => {\n void this.processLogsFile(filePath);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Gemini logs watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.observedLogMessageIds.clear();\n this.projectRootCache.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Gemini hook payload must be an object');\n return;\n }\n\n const hookEventName =\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hookEventName');\n\n if (!hookEventName) {\n logger.warn({ payload }, 'Gemini hook payload is missing its event name');\n return;\n }\n\n const cwd = getString(payload, 'cwd');\n const transcriptPath =\n getString(payload, 'transcript_path') ??\n getString(payload, 'transcriptPath');\n const sessionId = resolveSessionId({\n activeFile: extractGeminiActiveFile(payload),\n cwd,\n projectPath: cwd,\n sessionId:\n getString(payload, 'session_id') ??\n getString(payload, 'sessionId'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n cwd,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/gemini-cli',\n transcriptPath,\n };\n const sharedData = {\n activeFile: extractGeminiActiveFile(payload),\n cwd,\n errorMessage: extractGeminiErrorMessage(payload),\n errorType: extractGeminiErrorType(payload),\n model: extractGeminiModel(payload),\n projectPath: cwd,\n raw: payload,\n tokensUsed: extractGeminiTokens(payload),\n toolInput: extractGeminiToolInput(payload),\n toolName: extractGeminiToolName(payload),\n } satisfies Omit<EventData, 'state'>;\n\n switch (hookEventName) {\n case 'SessionStart': {\n this.fallbackProcessSessionId = null;\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'BeforeAgent': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'AfterAgent': {\n if (sharedData.errorMessage) {\n await this.emitStateChange('agent.error', sharedData, context);\n return;\n }\n\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'BeforeTool': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'AfterTool': {\n if (sharedData.errorMessage) {\n await this.emitStateChange('agent.error', sharedData, context);\n return;\n }\n\n const emittedType = isGeminiCodingTool(sharedData.toolName)\n ? 'agent.coding'\n : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'AfterModel': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'Notification': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n case 'PreCompress': {\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n default: {\n logger.debug({ hookEventName }, 'Gemini hook event ignored by adapter');\n }\n }\n }\n\n private async processLogsFile(filePath: string): Promise<void> {\n let fileContent: string;\n\n try {\n fileContent = await readFile(filePath, 'utf8');\n } catch (error) {\n logger.debug({ error, filePath }, 'Gemini logs read skipped');\n return;\n }\n\n let parsedContent: unknown;\n\n try {\n parsedContent = JSON.parse(fileContent) as unknown;\n } catch (error) {\n logger.warn({ error, filePath }, 'Gemini logs file is not valid JSON');\n return;\n }\n\n if (!Array.isArray(parsedContent)) {\n logger.warn({ filePath }, 'Gemini logs file does not contain an array');\n return;\n }\n\n const knownMessageIds = this.observedLogMessageIds.get(filePath) ?? new Set<string>();\n this.observedLogMessageIds.set(filePath, knownMessageIds);\n\n for (const entry of parsedContent) {\n if (!isRecord(entry)) {\n continue;\n }\n\n const messageId =\n getString(entry, 'messageId') ??\n getString(entry, 'message_id');\n\n if (!messageId || knownMessageIds.has(messageId)) {\n continue;\n }\n\n knownMessageIds.add(messageId);\n await this.processLogEntry(entry, filePath);\n }\n }\n\n private async processLogEntry(\n entry: Record<string, unknown>,\n filePath: string,\n ): Promise<void> {\n const messageType = getString(entry, 'type');\n const sessionId = resolveSessionId({\n cwd: await this.readProjectRoot(filePath),\n projectPath: await this.readProjectRoot(filePath),\n sessionId: getString(entry, 'sessionId') ?? `${this.name}:session`,\n tool: this.name,\n });\n const projectPath = await this.readProjectRoot(filePath);\n const context: AdapterPublishContext = {\n cwd: projectPath,\n hookPayload: entry,\n sessionId,\n source: 'aisnitch://adapters/gemini-cli/log-watch',\n };\n const sharedData = {\n cwd: projectPath,\n projectPath,\n raw: entry,\n } satisfies Omit<EventData, 'state'>;\n\n await this.ensureObservedSession(sessionId, sharedData, context);\n\n switch (messageType) {\n case 'user': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'model':\n case 'assistant': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n default: {\n logger.debug({ filePath, messageType }, 'Gemini log entry ignored by adapter');\n }\n }\n }\n\n private async ensureObservedSession(\n sessionId: string,\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n if (this.currentSessionId === sessionId) {\n return;\n }\n\n await this.emitStateChange('session.start', data, context);\n await this.emitStateChange('agent.idle', data, context);\n }\n\n private async readProjectRoot(filePath: string): Promise<string | undefined> {\n if (this.projectRootCache.has(filePath)) {\n return this.projectRootCache.get(filePath);\n }\n\n const rootPath = join(dirname(filePath), '.project_root');\n\n try {\n const projectRoot = (await readFile(rootPath, 'utf8')).trim();\n const normalizedRoot = projectRoot.length > 0 ? projectRoot : undefined;\n\n this.projectRootCache.set(filePath, normalizedRoot);\n return normalizedRoot;\n } catch {\n this.projectRootCache.set(filePath, undefined);\n return undefined;\n }\n }\n\n private async seedObservedLogState(): Promise<void> {\n const files = await collectFilesRecursively(this.logsDirectory, 'logs.json');\n\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n\n if (!fileStats.isFile()) {\n return;\n }\n\n const fileContent = await readFile(filePath, 'utf8');\n const parsedContent = JSON.parse(fileContent) as unknown;\n const messageIds = new Set<string>();\n\n if (Array.isArray(parsedContent)) {\n for (const entry of parsedContent) {\n if (!isRecord(entry)) {\n continue;\n }\n\n const messageId =\n getString(entry, 'messageId') ??\n getString(entry, 'message_id');\n\n if (messageId) {\n messageIds.add(messageId);\n }\n }\n }\n\n this.observedLogMessageIds.set(filePath, messageIds);\n } catch {\n // Ignore files that disappear or fail while seeding.\n }\n }),\n );\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollGeminiProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollGeminiProcesses();\n }\n\n private async pollGeminiProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `gemini-cli-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/gemini-cli/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/gemini-cli/process-detect',\n },\n );\n }\n }\n}\n\nasync function collectFilesRecursively(\n directoryPath: string,\n fileName: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, {\n withFileTypes: true,\n });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, fileName);\n }\n\n return entry.name === fileName ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractGeminiToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'tool_name') ??\n getString(payload, 'toolName')\n );\n}\n\nfunction extractGeminiToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);\n\n if (!toolInput) {\n return undefined;\n }\n\n const filePath =\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'path');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction extractGeminiActiveFile(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolInput = extractGeminiToolInput(payload);\n\n if (toolInput?.filePath) {\n return toolInput.filePath;\n }\n\n return (\n getString(payload, 'active_file') ??\n getString(payload, 'activeFile') ??\n getString(payload, 'file_path')\n );\n}\n\nfunction extractGeminiErrorMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolResponse = getRecord(payload.tool_response) ?? getRecord(payload.toolResponse);\n const llmResponse = getRecord(payload.llm_response) ?? getRecord(payload.llmResponse);\n\n return (\n getString(getRecord(toolResponse?.error), 'message') ??\n getString(payload, 'reason') ??\n getString(payload, 'message') ??\n getString(llmResponse, 'error')\n );\n}\n\nfunction extractGeminiErrorType(\n payload: Record<string, unknown>,\n): ErrorType | undefined {\n const rawType =\n getString(payload, 'error_type') ??\n getString(payload, 'errorType') ??\n getString(payload, 'stopReason');\n\n switch (rawType) {\n case 'rate_limit':\n return 'rate_limit';\n case 'max_output_tokens':\n case 'context_overflow':\n return 'context_overflow';\n case 'api_error':\n case 'provider_error':\n case 'invalid_request':\n return 'api_error';\n case 'tool_failure':\n return 'tool_failure';\n default:\n return undefined;\n }\n}\n\nfunction extractGeminiModel(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(getRecord(payload.llm_request), 'model') ??\n getString(payload, 'model')\n );\n}\n\nfunction extractGeminiTokens(\n payload: Record<string, unknown>,\n): number | undefined {\n const llmResponse = getRecord(payload.llm_response) ?? getRecord(payload.llmResponse);\n const usageMetadata = getRecord(llmResponse?.usageMetadata);\n const totalTokens =\n getNumber(usageMetadata, 'totalTokenCount') ??\n getNumber(usageMetadata, 'total_tokens');\n\n return totalTokens;\n}\n\nfunction isGeminiCodingTool(toolName?: string): boolean {\n return toolName !== undefined && GEMINI_CODING_TOOLS.has(toolName);\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<GeminiProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map(parseProcessLine)\n .filter((processInfo): processInfo is GeminiProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode = isErrnoException(error) ? String(error.code) : '';\n\n if (isErrnoException(error) && (errorCode === 'ENOENT' || errorCode === '1')) {\n return [];\n }\n\n logger.debug({ error }, 'Gemini process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): GeminiProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException & { code?: string | number } {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { ErrorType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/goose.ts\n * @description Goose adapter combining goosed session discovery, SSE event streaming, SQLite session watching, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports GooseAdapter, GooseAdapterOptions\n * @see ./base.ts\n * @see ../../tasks/06-adapters-secondary/02_adapters-secondary_goose-copilot_DONE.md\n */\n\nconst execFile = promisify(execFileCallback);\nconst DEFAULT_GOOSED_BASE_URL = 'http://127.0.0.1:8080';\nconst DEFAULT_SQLITE_QUERY = [\n 'SELECT',\n ' id,',\n ' name,',\n ' working_dir,',\n ' updated_at,',\n ' message_count,',\n ' provider_name,',\n ' accumulated_total_tokens,',\n ' total_tokens,',\n ' model_config',\n 'FROM sessions',\n 'ORDER BY updated_at DESC',\n 'LIMIT 24;',\n].join('\\n');\nconst MAX_STREAMED_SESSIONS = 6;\nconst GOOSE_CODING_TOOL_HINT = /apply|create|delete|edit|move|patch|rename|replace|write/iu;\nconst GOOSE_RATE_LIMIT_HINT = /credit|quota|rate limit|exhausted/iu;\n\nexport interface GooseAdapterOptions extends AdapterRuntimeOptions {\n readonly apiBaseUrl?: string;\n readonly apiKey?: string;\n readonly databasePath?: string;\n readonly fetchImplementation?: typeof fetch;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly sqliteQueryCommand?: (\n databasePath: string,\n query: string,\n ) => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface GooseProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface GooseSessionSnapshot {\n readonly gooseSessionId: string;\n readonly sessionId: string;\n readonly messageCount?: number;\n readonly model?: string;\n readonly name?: string;\n readonly providerName?: string;\n readonly totalTokens?: number;\n readonly updatedAt?: string;\n readonly workingDir?: string;\n}\n\ninterface GooseStreamHandle {\n readonly abortController: AbortController;\n readonly promise: Promise<void>;\n}\n\ninterface GooseSessionsResponse {\n readonly sessions?: unknown;\n}\n\n/**\n * ๐Ÿ“– Goose is the first adapter that mixes three genuinely different sources:\n * HTTP session discovery, SSE streaming, and a coarse SQLite fallback. Each\n * layer is best-effort and intentionally conservative about what it claims.\n */\nexport class GooseAdapter extends BaseAdapter {\n public override readonly displayName = 'Goose';\n\n public override readonly name = 'goose' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'api-client',\n 'sqlite-watch',\n 'process-detect',\n ];\n\n private apiPoller: NodeJS.Timeout | null = null;\n\n private readonly apiBaseUrl: string;\n\n private readonly apiKey: string | undefined;\n\n private readonly databasePath: string;\n\n private databaseWatcher: FSWatcher | null = null;\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly fetchImplementation: typeof fetch;\n\n private apiDiscoverySeeded = false;\n\n private readonly observedSessions = new Set<string>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionEventFingerprints = new Map<string, Set<string>>();\n\n private readonly sessionSnapshots = new Map<string, GooseSessionSnapshot>();\n\n private readonly sessionStreams = new Map<string, GooseStreamHandle>();\n\n private readonly sqliteQueryCommand: (\n databasePath: string,\n query: string,\n ) => Promise<string>;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: GooseAdapterOptions) {\n super(options);\n this.apiBaseUrl =\n options.apiBaseUrl ??\n options.env?.AISNITCH_GOOSE_API_BASE_URL ??\n DEFAULT_GOOSED_BASE_URL;\n this.apiKey =\n options.apiKey ??\n options.env?.AISNITCH_GOOSE_API_KEY ??\n options.env?.GOOSE_API_KEY;\n this.databasePath =\n options.databasePath ??\n join(this.getUserHomeDirectory(), '.config', 'goose', 'sessions.db');\n this.fetchImplementation = options.fetchImplementation ?? fetch;\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'goose|goosed']).then(\n (result) => result.stdout,\n ));\n this.sqliteQueryCommand =\n options.sqliteQueryCommand ??\n (async (databasePath, query) =>\n await execFile('sqlite3', ['-json', databasePath, query]).then(\n (result) => result.stdout,\n ));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedSqliteSessions();\n\n this.databaseWatcher = this.watcherFactory(this.databasePath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.databaseWatcher.on('add', () => {\n void this.pollSqliteSessions(true);\n });\n this.databaseWatcher.on('change', () => {\n void this.pollSqliteSessions(true);\n });\n this.databaseWatcher.on('error', (error) => {\n logger.warn({ error }, 'Goose SQLite watcher error');\n });\n\n this.startApiPolling();\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.databaseWatcher !== null) {\n await this.databaseWatcher.close();\n this.databaseWatcher = null;\n }\n\n if (this.apiPoller !== null) {\n clearInterval(this.apiPoller);\n this.apiPoller = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n for (const streamHandle of this.sessionStreams.values()) {\n streamHandle.abortController.abort();\n void streamHandle.promise.catch(() => undefined);\n }\n\n this.apiDiscoverySeeded = false;\n this.fallbackProcessSessionId = null;\n this.observedSessions.clear();\n this.sessionEventFingerprints.clear();\n this.sessionSnapshots.clear();\n this.sessionStreams.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload === null) {\n logger.debug({ payload }, 'Goose ignores non-normalized hook payloads');\n return;\n }\n\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n }\n\n private startApiPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.apiPoller = setInterval(() => {\n void this.pollGooseApi(true);\n }, this.pollIntervalMs);\n this.apiPoller.unref();\n\n void this.pollGooseApi(false);\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollGooseProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollGooseProcesses();\n }\n\n private async seedSqliteSessions(): Promise<void> {\n try {\n await stat(this.databasePath);\n } catch {\n return;\n }\n\n const sessions = await this.readSqliteSessions();\n\n this.syncSessionSnapshots(sessions, false, 'sqlite-seed');\n }\n\n private async pollSqliteSessions(emitChanges: boolean): Promise<void> {\n const sessions = await this.readSqliteSessions();\n\n this.syncSessionSnapshots(sessions, emitChanges, 'sqlite');\n }\n\n private async readSqliteSessions(): Promise<GooseSessionSnapshot[]> {\n let rawOutput: string;\n\n try {\n rawOutput = await this.sqliteQueryCommand(\n this.databasePath,\n DEFAULT_SQLITE_QUERY,\n );\n } catch (error) {\n logger.debug({ error }, 'Goose SQLite session query skipped');\n return [];\n }\n\n let parsedOutput: unknown;\n\n try {\n parsedOutput = JSON.parse(rawOutput) as unknown;\n } catch (error) {\n logger.warn({ error }, 'Goose SQLite JSON output is invalid');\n return [];\n }\n\n if (!Array.isArray(parsedOutput)) {\n return [];\n }\n\n return parsedOutput\n .map((entry) => normalizeGooseSession(entry))\n .filter((entry): entry is GooseSessionSnapshot => entry !== null);\n }\n\n private async pollGooseApi(emitChanges: boolean): Promise<void> {\n let statusResponse: Response;\n\n try {\n statusResponse = await this.fetchImplementation(\n new URL('/status', this.apiBaseUrl),\n );\n } catch (error) {\n logger.debug({ error }, 'Goosed status endpoint is unavailable');\n return;\n }\n\n if (!statusResponse.ok) {\n return;\n }\n\n let sessionsResponse: Response;\n\n try {\n sessionsResponse = await this.fetchImplementation(\n new URL('/sessions', this.apiBaseUrl),\n {\n headers: this.createApiHeaders(),\n },\n );\n } catch (error) {\n logger.debug({ error }, 'Goosed sessions endpoint request failed');\n return;\n }\n\n if (!sessionsResponse.ok) {\n logger.debug(\n { status: sessionsResponse.status },\n 'Goosed sessions endpoint rejected the request',\n );\n return;\n }\n\n let parsedPayload: unknown;\n\n try {\n parsedPayload = await sessionsResponse.json();\n } catch (error) {\n logger.warn({ error }, 'Goosed sessions payload is not valid JSON');\n return;\n }\n\n const responsePayload = parsedPayload as GooseSessionsResponse;\n const rawSessions = Array.isArray(responsePayload.sessions)\n ? responsePayload.sessions\n : [];\n const sessions = rawSessions\n .map((entry) => normalizeGooseSession(entry))\n .filter((entry): entry is GooseSessionSnapshot => entry !== null);\n\n this.syncSessionSnapshots(\n sessions,\n emitChanges && this.apiDiscoverySeeded,\n 'api',\n );\n this.apiDiscoverySeeded = true;\n }\n\n private syncSessionSnapshots(\n nextSnapshots: readonly GooseSessionSnapshot[],\n emitChanges: boolean,\n source: string,\n ): void {\n for (const snapshot of nextSnapshots) {\n const previousSnapshot = this.sessionSnapshots.get(snapshot.sessionId);\n\n this.sessionSnapshots.set(snapshot.sessionId, snapshot);\n this.ensureTrackedSessionStream(snapshot);\n\n if (!emitChanges) {\n continue;\n }\n\n if (previousSnapshot === undefined) {\n void this.ensureObservedSession(snapshot, source);\n continue;\n }\n\n if (!didGooseSessionAdvance(previousSnapshot, snapshot)) {\n continue;\n }\n\n void this.ensureObservedSession(snapshot, source).then(async () => {\n await this.emitStateChange(\n 'agent.streaming',\n buildGooseSessionData(snapshot, {\n raw: {\n snapshot,\n source,\n },\n }),\n this.createSessionContext(snapshot, `aisnitch://adapters/goose/${source}`),\n );\n });\n }\n\n this.trimTrackedSessionStreams(nextSnapshots);\n }\n\n private ensureTrackedSessionStream(snapshot: GooseSessionSnapshot): void {\n if (this.sessionStreams.has(snapshot.sessionId)) {\n return;\n }\n\n const abortController = new AbortController();\n const streamPromise = this.consumeSessionEvents(snapshot, abortController).finally(\n () => {\n const activeStream = this.sessionStreams.get(snapshot.sessionId);\n\n if (activeStream?.abortController === abortController) {\n this.sessionStreams.delete(snapshot.sessionId);\n }\n },\n );\n\n this.sessionStreams.set(snapshot.sessionId, {\n abortController,\n promise: streamPromise,\n });\n }\n\n private trimTrackedSessionStreams(\n nextSnapshots: readonly GooseSessionSnapshot[],\n ): void {\n const keepSessionIds = new Set(\n [...nextSnapshots]\n .sort(compareGooseSessionsByRecency)\n .slice(0, MAX_STREAMED_SESSIONS)\n .map((snapshot) => snapshot.sessionId),\n );\n\n for (const [sessionId, streamHandle] of this.sessionStreams) {\n if (keepSessionIds.has(sessionId)) {\n continue;\n }\n\n streamHandle.abortController.abort();\n this.sessionStreams.delete(sessionId);\n }\n }\n\n private async consumeSessionEvents(\n snapshot: GooseSessionSnapshot,\n abortController: AbortController,\n ): Promise<void> {\n let response: Response;\n\n try {\n response = await this.fetchImplementation(\n new URL(\n `/sessions/${encodeURIComponent(snapshot.gooseSessionId)}/events`,\n this.apiBaseUrl,\n ),\n {\n headers: {\n ...this.createApiHeaders(),\n Accept: 'text/event-stream',\n },\n signal: abortController.signal,\n },\n );\n } catch (error) {\n if (abortController.signal.aborted) {\n return;\n }\n\n logger.debug({ error, sessionId: snapshot.sessionId }, 'Goose SSE request failed');\n return;\n }\n\n if (!response.ok || response.body === null) {\n logger.debug(\n { sessionId: snapshot.sessionId, status: response.status },\n 'Goose SSE stream is unavailable',\n );\n return;\n }\n\n const reader: ReadableStreamDefaultReader<Uint8Array> =\n response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const readResult = await reader.read();\n\n if (readResult.done) {\n break;\n }\n\n buffer += decoder.decode(readResult.value, { stream: true });\n\n while (true) {\n const delimiterIndex = buffer.indexOf('\\n\\n');\n\n if (delimiterIndex === -1) {\n break;\n }\n\n const frame = buffer.slice(0, delimiterIndex);\n\n buffer = buffer.slice(delimiterIndex + 2);\n await this.processSSEFrame(snapshot, frame);\n }\n }\n } catch (error) {\n if (!abortController.signal.aborted) {\n logger.debug(\n { error, sessionId: snapshot.sessionId },\n 'Goose SSE stream closed unexpectedly',\n );\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private async processSSEFrame(\n snapshot: GooseSessionSnapshot,\n frame: string,\n ): Promise<void> {\n const payloadText = frame\n .split(/\\r?\\n/u)\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice(5).trimStart())\n .join('\\n');\n\n if (payloadText.length === 0) {\n return;\n }\n\n let parsedPayload: unknown;\n\n try {\n parsedPayload = JSON.parse(payloadText) as unknown;\n } catch (error) {\n logger.warn({ error }, 'Goose SSE frame is not valid JSON');\n return;\n }\n\n await this.processSessionEvent(snapshot, parsedPayload);\n }\n\n private async processSessionEvent(\n snapshot: GooseSessionSnapshot,\n payload: unknown,\n ): Promise<void> {\n if (!isRecord(payload)) {\n return;\n }\n\n const fingerprint = createGooseFingerprint(payload);\n\n if (fingerprint && !this.markSessionEventSeen(snapshot.sessionId, fingerprint)) {\n return;\n }\n\n const eventType = getString(payload, 'type');\n\n switch (eventType) {\n case 'Message': {\n await this.processGooseMessage(snapshot, payload);\n return;\n }\n case 'Finish': {\n await this.ensureObservedSession(snapshot, 'sse');\n await this.emitStateChange(\n 'task.complete',\n buildGooseSessionData(snapshot, {\n raw: payload,\n tokensUsed: extractGooseTokenCount(getRecord(payload.token_state)),\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n return;\n }\n case 'Error': {\n const errorMessage = getString(payload, 'error');\n\n await this.ensureObservedSession(snapshot, 'sse');\n await this.emitStateChange(\n 'agent.error',\n buildGooseSessionData(snapshot, {\n errorMessage,\n errorType: inferGooseErrorType(errorMessage),\n raw: payload,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n return;\n }\n case 'Notification': {\n await this.ensureObservedSession(snapshot, 'sse');\n await this.emitStateChange(\n 'agent.asking_user',\n buildGooseSessionData(snapshot, {\n errorMessage: extractLooseString(payload, ['message']),\n raw: payload,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n return;\n }\n default:\n return;\n }\n }\n\n private async processGooseMessage(\n snapshot: GooseSessionSnapshot,\n payload: Record<string, unknown>,\n ): Promise<void> {\n const message = getRecord(payload.message);\n\n if (!message) {\n return;\n }\n\n const role = getString(message, 'role');\n const content = getRecordArray(message.content);\n const tokenState = getRecord(payload.token_state);\n const tokensUsed = extractGooseTokenCount(tokenState);\n\n await this.ensureObservedSession(snapshot, 'sse');\n\n if (role === 'user') {\n const promptText = content\n .filter((part) => getString(part, 'type') === 'text')\n .map((part) => getString(part, 'text'))\n .filter((part): part is string => typeof part === 'string')\n .join('\\n')\n .trim();\n\n await this.emitStateChange(\n 'task.start',\n buildGooseSessionData(snapshot, {\n raw: {\n message,\n prompt: promptText,\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n\n return;\n }\n\n if (role !== 'assistant') {\n return;\n }\n\n for (const part of content) {\n const partType = getString(part, 'type');\n\n switch (partType) {\n case 'thinking': {\n await this.emitStateChange(\n 'agent.thinking',\n buildGooseSessionData(snapshot, {\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'redactedThinking': {\n await this.emitStateChange(\n 'agent.thinking',\n buildGooseSessionData(snapshot, {\n raw: {\n message: {\n content: [\n {\n thinking: getString(part, 'data'),\n type: 'thinking',\n },\n ],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'text': {\n await this.emitStateChange(\n 'agent.streaming',\n buildGooseSessionData(snapshot, {\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'toolRequest': {\n const toolName = extractGooseToolName(part);\n const toolInput = extractGooseToolInput(part);\n const activeFile = toolInput?.filePath;\n const emittedType = isGooseCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n\n await this.emitStateChange(\n emittedType,\n buildGooseSessionData(snapshot, {\n activeFile,\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n toolInput,\n toolName,\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'toolConfirmationRequest':\n case 'actionRequired': {\n await this.emitStateChange(\n 'agent.asking_user',\n buildGooseSessionData(snapshot, {\n errorMessage:\n getString(part, 'prompt') ??\n extractLooseString(getRecord(part.data), ['message']),\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n toolInput: extractGooseToolInput(part),\n toolName: extractGooseToolName(part),\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'systemNotification': {\n const notificationType = getString(part, 'notificationType');\n const eventTypeToEmit =\n notificationType === 'thinkingMessage'\n ? 'agent.thinking'\n : 'agent.asking_user';\n\n await this.emitStateChange(\n eventTypeToEmit,\n buildGooseSessionData(snapshot, {\n errorMessage: getString(part, 'msg'),\n errorType:\n notificationType === 'creditsExhausted'\n ? 'rate_limit'\n : undefined,\n raw: {\n message:\n notificationType === 'thinkingMessage'\n ? {\n content: [\n {\n thinking: getString(part, 'msg'),\n type: 'thinking',\n },\n ],\n role,\n }\n : {\n content: [part],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n default:\n break;\n }\n }\n }\n\n private async ensureObservedSession(\n snapshot: GooseSessionSnapshot,\n source: string,\n ): Promise<void> {\n if (this.observedSessions.has(snapshot.sessionId)) {\n return;\n }\n\n this.observedSessions.add(snapshot.sessionId);\n\n const context = this.createSessionContext(\n snapshot,\n `aisnitch://adapters/goose/${source}`,\n );\n const eventData = buildGooseSessionData(snapshot, {\n raw: {\n snapshot,\n source,\n },\n });\n\n await this.emitStateChange('session.start', eventData, context);\n await this.emitStateChange('agent.idle', eventData, context);\n }\n\n private createSessionContext(\n snapshot: GooseSessionSnapshot,\n source: string,\n ): AdapterPublishContext {\n return {\n cwd: snapshot.workingDir,\n sessionId: snapshot.sessionId,\n source,\n };\n }\n\n private markSessionEventSeen(sessionId: string, fingerprint: string): boolean {\n const knownFingerprints =\n this.sessionEventFingerprints.get(sessionId) ?? new Set<string>();\n\n if (knownFingerprints.has(fingerprint)) {\n return false;\n }\n\n if (knownFingerprints.size >= 256) {\n knownFingerprints.clear();\n }\n\n knownFingerprints.add(fingerprint);\n this.sessionEventFingerprints.set(sessionId, knownFingerprints);\n\n return true;\n }\n\n private createApiHeaders(): Record<string, string> | undefined {\n if (!this.apiKey) {\n return undefined;\n }\n\n return {\n Authorization: `Bearer ${this.apiKey}`,\n };\n }\n\n private async pollGooseProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `goose-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/goose/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/goose/process-detect',\n },\n );\n }\n }\n}\n\nfunction normalizeGooseSession(payload: unknown): GooseSessionSnapshot | null {\n if (!isRecord(payload)) {\n return null;\n }\n\n const gooseSessionId = getString(payload, 'id');\n\n if (!gooseSessionId) {\n return null;\n }\n\n const workingDir =\n getString(payload, 'working_dir') ?? getString(payload, 'workingDir');\n const name = getString(payload, 'name');\n const providerName =\n getString(payload, 'provider_name') ?? getString(payload, 'providerName');\n const updatedAt =\n getString(payload, 'updated_at') ?? getString(payload, 'updatedAt');\n const messageCount =\n getNumber(payload, 'message_count') ?? getNumber(payload, 'messageCount');\n const totalTokens =\n getNumber(payload, 'accumulated_total_tokens') ??\n getNumber(payload, 'total_tokens') ??\n getNumber(payload, 'accumulatedTotalTokens') ??\n getNumber(payload, 'totalTokens');\n const modelConfig = getRecord(payload.model_config) ?? getRecord(payload.modelConfig);\n const rawModelConfig = getString(payload, 'model_config');\n const parsedModelConfig =\n modelConfig ?? parseJsonRecord(rawModelConfig);\n const model = getString(parsedModelConfig, 'model_name') ?? getString(parsedModelConfig, 'modelName');\n const sessionId = resolveSessionId({\n cwd: workingDir,\n projectPath: workingDir,\n sessionId: gooseSessionId,\n tool: 'goose',\n });\n\n return {\n gooseSessionId,\n messageCount,\n model,\n name,\n providerName,\n sessionId,\n totalTokens,\n updatedAt,\n workingDir,\n };\n}\n\nfunction buildGooseSessionData(\n snapshot: GooseSessionSnapshot,\n overrides: Partial<Omit<EventData, 'state'>> = {},\n): Omit<EventData, 'state'> {\n return {\n cwd: overrides.cwd ?? snapshot.workingDir,\n model: overrides.model ?? snapshot.model,\n project: overrides.project ?? snapshot.name,\n projectPath: overrides.projectPath ?? snapshot.workingDir,\n raw: overrides.raw,\n tokensUsed: overrides.tokensUsed ?? snapshot.totalTokens,\n ...overrides,\n };\n}\n\nfunction compareGooseSessionsByRecency(\n left: GooseSessionSnapshot,\n right: GooseSessionSnapshot,\n): number {\n return Date.parse(right.updatedAt ?? '') - Date.parse(left.updatedAt ?? '');\n}\n\nfunction didGooseSessionAdvance(\n previousSnapshot: GooseSessionSnapshot,\n nextSnapshot: GooseSessionSnapshot,\n): boolean {\n return (\n previousSnapshot.updatedAt !== nextSnapshot.updatedAt ||\n previousSnapshot.messageCount !== nextSnapshot.messageCount ||\n previousSnapshot.totalTokens !== nextSnapshot.totalTokens\n );\n}\n\nfunction createGooseFingerprint(payload: Record<string, unknown>): string | null {\n const eventType = getString(payload, 'type');\n\n if (!eventType) {\n return null;\n }\n\n if (eventType === 'Message') {\n const message = getRecord(payload.message);\n const messageId = getString(message, 'id');\n const created = getNumber(message, 'created');\n const role = getString(message, 'role');\n\n return [eventType, messageId, created, role]\n .filter((value): value is string | number => value !== undefined)\n .join(':');\n }\n\n if (eventType === 'Finish') {\n return `${eventType}:${getString(payload, 'reason') ?? 'unknown'}`;\n }\n\n if (eventType === 'Error') {\n return `${eventType}:${getString(payload, 'error') ?? 'unknown'}`;\n }\n\n return eventType;\n}\n\nfunction extractGooseTokenCount(\n tokenState: Record<string, unknown> | undefined,\n): number | undefined {\n return (\n getNumber(tokenState, 'accumulatedTotalTokens') ??\n getNumber(tokenState, 'totalTokens')\n );\n}\n\nfunction extractGooseToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolCall = getRecord(payload.toolCall);\n\n return (\n getString(toolCall, 'name') ??\n getString(toolCall, 'toolName') ??\n getString(payload, 'toolName')\n );\n}\n\nfunction extractGooseToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolCall = getRecord(payload.toolCall);\n const argumentsRecord =\n getRecord(toolCall?.arguments) ??\n getRecord(toolCall?.args) ??\n getRecord(toolCall?.input) ??\n getRecord(payload.arguments);\n const filePath = extractFirstString(argumentsRecord, [\n 'file',\n 'file_path',\n 'filePath',\n 'path',\n 'target',\n 'target_path',\n 'targetPath',\n ]);\n const command = extractFirstString(argumentsRecord, [\n 'cmd',\n 'command',\n 'script',\n ]);\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction isGooseCodingTool(\n toolName: string | undefined,\n toolInput: ToolInput | undefined,\n): boolean {\n if (toolName && GOOSE_CODING_TOOL_HINT.test(toolName)) {\n return true;\n }\n\n const filePath = toolInput?.filePath;\n\n if (!filePath) {\n return false;\n }\n\n return !/read|view|glob|grep|list|search/iu.test(toolName ?? '');\n}\n\nfunction inferGooseErrorType(\n errorMessage: string | undefined,\n): ErrorType | undefined {\n if (!errorMessage) {\n return undefined;\n }\n\n if (GOOSE_RATE_LIMIT_HINT.test(errorMessage)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|too long/iu.test(errorMessage)) {\n return 'context_overflow';\n }\n\n if (/tool/iu.test(errorMessage)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n processListCommand: () => Promise<string>,\n): Promise<GooseProcessInfo[]> {\n try {\n const commandOutput = await processListCommand();\n\n return commandOutput\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const [pidPart, ...commandParts] = line.split(/\\s+/u);\n const pid = pidPart ? Number.parseInt(pidPart, 10) : Number.NaN;\n\n return {\n command: commandParts.join(' '),\n pid,\n } satisfies GooseProcessInfo;\n })\n .filter((processInfo) => Number.isInteger(processInfo.pid));\n } catch (error) {\n logger.debug({ error }, 'Goose process listing skipped');\n return [];\n }\n}\n\nfunction parseJsonRecord(\n value: string | undefined,\n): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n\n try {\n const parsedValue = JSON.parse(value) as unknown;\n\n return getRecord(parsedValue);\n } catch {\n return undefined;\n }\n}\n\nfunction extractFirstString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n }\n\n return undefined;\n}\n\nfunction extractLooseString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n\n const nestedValue = getString(getRecord(payload[key]), 'message');\n\n if (nestedValue) {\n return nestedValue;\n }\n }\n\n return undefined;\n}\n\nfunction getRecordArray(value: unknown): Record<string, unknown>[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.filter((entry): entry is Record<string, unknown> => isRecord(entry));\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/kilo.ts\n * @description Kilo CLI adapter covering process detection, ACP protocol integration,\n * and local data directory watching for the open-source Kilo Code agent.\n * @functions\n * โ†’ none\n * @exports KiloAdapter, KiloAdapterOptions\n * @see ./base.ts\n * @see ../../docs/priority-adapters.md\n *\n * ๐Ÿ“– Kilo is an open-source AI coding agent (10k+ stars on GitHub) that works with\n * VS Code, JetBrains, and as a standalone CLI. It ships an ACP (Agent Communication\n * Protocol) similar to OpenCode's, plus writes logs to ~/.config/kilo/ and\n * ~/.local/share/kilo/. Interception: process-detect primary, ACP plugin fallback.\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst KILO_CODING_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'Create',\n 'Delete',\n 'Move',\n 'ApplyDiff',\n]);\n\nexport interface KiloAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly configDirectory?: string;\n readonly dataDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface KiloProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface KiloSessionMetadata {\n readonly cwd?: string;\n readonly model?: string;\n readonly sessionId: string;\n}\n\n/**\n * ๐Ÿ“– Kilo uses an ACP protocol with JSON-RPC messages over stdin/stdout. The adapter\n * detects running processes and watches for session data files. When hooks are\n * available via the Kilo config, they are parsed as structured events.\n */\nexport class KiloAdapter extends BaseAdapter {\n public override readonly displayName = 'Kilo CLI';\n\n public override readonly name = 'kilo' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'jsonl-watch',\n 'hooks',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly configDirectory: string;\n\n private readonly dataDirectory: string;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionMetadata = new Map<string, KiloSessionMetadata>();\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: KiloAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () => {\n const results = await Promise.all([\n execFile('pgrep', ['-lf', 'kilo']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'kilocode']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'kilocode']).catch(() => ({ stdout: '' })),\n ]);\n return results.map((r) => r.stdout).join('\\n');\n });\n this.configDirectory =\n options.configDirectory ?? join(this.getUserHomeDirectory(), '.config', 'kilo');\n this.dataDirectory =\n options.dataDirectory ?? join(this.getUserHomeDirectory(), '.local', 'share', 'kilo');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n // Watch for Kilo session logs (additional patterns available for future expansion)\n const _logPatterns = [\n join(this.dataDirectory, '**', '*.jsonl'),\n join(this.configDirectory, 'logs', '**', '*.jsonl'),\n ];\n\n // Watch primary log directory\n this.watcher = this.watcherFactory(join(this.dataDirectory, '**', '*.jsonl'), {\n awaitWriteFinish: { stabilityThreshold: 200 },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => void this.processTranscriptUpdate(filePath, true));\n this.watcher.on('change', (filePath) => void this.processTranscriptUpdate(filePath, false));\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Kilo log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.sessionMetadata.clear();\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Kilo hook payload must be an object');\n return;\n }\n\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath: getString(payload, 'projectPath'),\n sessionId:\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(getRecord(payload.data), 'sessionId'),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/kilo',\n };\n const eventType = getString(payload, 'event') ?? getString(payload, 'type') ?? getString(payload, 'method');\n const data = getRecord(payload.data) ?? payload;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName') ?? getString(data, 'name');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: getString(data, 'model') ?? getString(payload, 'model'),\n projectPath: getString(data, 'projectPath') ?? getString(payload, 'projectPath'),\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.start':\n case 'sessionStart':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'sessionEnd':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'taskStart':\n case 'UserPrompt':\n case 'user_message': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'taskComplete':\n case 'TaskComplete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'tool.call':\n case 'toolCall':\n case 'PreToolUse': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'tool.result':\n case 'toolResult':\n case 'PostToolUse': {\n const emittedType = isKiloCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking':\n case 'reasoning': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'streaming':\n case 'Streaming':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(payload, 'error') ?? 'Kilo error',\n errorType: inferKiloErrorType(data),\n }, context);\n return;\n }\n case 'asking_user':\n case 'PermissionRequest':\n case 'input_required': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n logger.debug({ eventType }, 'Kilo hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Kilo transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ?? (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') + newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Kilo transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n // ACP protocol format: messages have type, id, session, data fields\n const acpType = getString(parsedLine, 'type') ?? getString(parsedLine, 'method');\n const sessionId = resolveSessionId({\n sessionId:\n getString(parsedLine, 'sessionId') ??\n getString(parsedLine, 'session_id') ??\n getString(parsedLine, 'id') ??\n basename(transcriptPath, '.jsonl'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n env: process.env,\n hookPayload: parsedLine,\n sessionId,\n source: 'aisnitch://adapters/kilo/log',\n transcriptPath,\n };\n const data = getRecord(parsedLine.data) ?? parsedLine;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: getString(data, 'cwd'),\n model: getString(data, 'model'),\n raw: parsedLine,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n // Map Kilo/ACP message types to AISnitch events\n switch (acpType) {\n case 'session.start':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'TaskStart':\n case 'user_message': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'TaskComplete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking':\n case 'reasoning': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'streaming':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'tool_call':\n case 'tool_use': {\n const emittedType = isKiloCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(data, 'message'),\n errorType: inferKiloErrorType(data),\n }, context);\n return;\n }\n case 'permission_request':\n case 'asking_user': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n // ACP also sends heartbeat/ping messages โ€” ignore gracefully\n if (acpType === 'ping' || acpType === 'pong' || acpType === 'heartbeat') {\n return;\n }\n return;\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n try {\n const files = await collectFilesRecursively(this.dataDirectory, '.jsonl');\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n } catch {\n // Data directory may not exist yet on first run.\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollKiloProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollKiloProcesses();\n }\n\n private async pollKiloProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `kilo-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n { raw: { process: processInfo, source: 'process-detect' } },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/kilo/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n { raw: { reason: 'process-exit', source: 'process-detect' } },\n {\n sessionId,\n source: 'aisnitch://adapters/kilo/process-detect',\n },\n );\n }\n }\n}\n\n// โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput) ?? getRecord(payload.arguments) ?? getRecord(payload.params);\n const filePath =\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'path') ??\n getString(toolInput, 'target');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd') ??\n getString(toolInput, 'script');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return { command, filePath };\n}\n\nfunction isKiloCodingTool(toolName?: string): boolean {\n return toolName !== undefined && KILO_CODING_TOOLS.has(toolName);\n}\n\nfunction inferKiloErrorType(\n payload: Record<string, unknown> | undefined,\n): ErrorType {\n const message =\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n '';\n\n if (/rate.?limit|quota|credit/i.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token.?limit|too.?long/i.test(message)) {\n return 'context_overflow';\n }\n\n if (/tool|permission|denied/i.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<KiloProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .filter((line) => line.includes('kilo') || line.includes('kilocode'))\n .map(parseProcessLine)\n .filter((processInfo): processInfo is KiloProcessInfo => processInfo !== null);\n } catch (error) {\n logger.debug({ error }, 'Kilo process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): KiloProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, dirname, extname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\nimport pidCwd from 'pid-cwd';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n AISnitchEventType,\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/openclaw.ts\n * @description OpenClaw adapter combining managed hook ingestion, bundled command logs, transcript watching, workspace-memory watching, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports OpenClawAdapter, OpenClawAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/04_adapters-secondary_openclaw.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst COMMAND_START_THINKING_DELAY_MS = 2_000;\nconst POST_TOOL_THINKING_DELAY_MS = 500;\nconst OPENCLAW_CODING_TOOL_HINT =\n /apply|bash|create|delete|edit|exec|file|patch|replace|shell|write/iu;\nconst OPENCLAW_ERROR_HINT =\n /denied|error|exception|failed|quota|rate limit|refused|timeout/iu;\n\nexport interface OpenClawAdapterOptions extends AdapterRuntimeOptions {\n readonly agentsDirectory?: string;\n readonly commandsLogPath?: string;\n readonly cwdResolver?: (pid: number) => Promise<string | undefined>;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: Parameters<typeof watch>[0],\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface OpenClawProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface OpenClawSessionSnapshot {\n readonly cwd?: string;\n readonly project?: string;\n readonly sessionId: string;\n readonly sessionKey?: string;\n readonly transcriptPath?: string;\n}\n\ninterface PendingThinkingState {\n readonly context: AdapterPublishContext;\n readonly data: Omit<EventData, 'state'>;\n}\n\n/**\n * ๐Ÿ“– OpenClaw has several passive surfaces, but none of them is perfect alone.\n * AISnitch therefore merges the real managed hook path with filesystem and\n * process fallbacks so operators still get signal when setup is partial.\n */\nexport class OpenClawAdapter extends BaseAdapter {\n public override readonly displayName = 'OpenClaw';\n\n public override readonly name = 'openclaw' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'log-watch',\n 'jsonl-watch',\n 'process-detect',\n ];\n\n private readonly agentsDirectory: string;\n\n private readonly commandsLogPath: string;\n\n private commandsLogWatcher: FSWatcher | null = null;\n\n private readonly cwdResolver: (pid: number) => Promise<string | undefined>;\n\n private readonly fallbackProcessSessions = new Map<number, string>();\n\n private readonly observedTranscriptEntries = new Set<string>();\n\n private readonly pendingThinking = new Map<string, NodeJS.Timeout>();\n\n private readonly pendingThinkingState = new Map<string, PendingThinkingState>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionSnapshots = new Map<string, OpenClawSessionSnapshot>();\n\n private readonly startedSessions = new Set<string>();\n\n private transcriptWatcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: Parameters<typeof watch>[0],\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n private readonly memoryRootGlobs: readonly string[];\n\n private memoryWatcher: FSWatcher | null = null;\n\n private readonly fileOffsets = new Map<string, number>();\n\n private readonly fileRemainders = new Map<string, string>();\n\n public constructor(options: OpenClawAdapterOptions) {\n super(options);\n\n const openclawHome = join(this.getUserHomeDirectory(), '.openclaw');\n\n this.agentsDirectory = options.agentsDirectory ?? join(openclawHome, 'agents');\n this.commandsLogPath =\n options.commandsLogPath ?? join(openclawHome, 'logs', 'commands.log');\n this.cwdResolver =\n options.cwdResolver ??\n (async (pid) => {\n return await pidCwd(pid);\n });\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-ifl', 'openclaw']).then(\n (result) => result.stdout,\n ));\n this.watcherFactory = options.watcherFactory ?? watch;\n this.memoryRootGlobs = [\n join(openclawHome, 'workspace', 'MEMORY.md'),\n join(openclawHome, 'workspace', 'memory', '*.md'),\n join(openclawHome, 'workspace-*', 'MEMORY.md'),\n join(openclawHome, 'workspace-*', 'memory', '*.md'),\n ];\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await Promise.all([\n this.seedCommandsLogOffset(),\n this.seedMemoryOffsets(),\n this.seedTranscriptOffsets(),\n ]);\n\n this.commandsLogWatcher = this.watcherFactory(this.commandsLogPath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n this.commandsLogWatcher.on('add', (filePath) => {\n void this.processCommandsLogUpdate(filePath, true);\n });\n this.commandsLogWatcher.on('change', (filePath) => {\n void this.processCommandsLogUpdate(filePath, false);\n });\n this.commandsLogWatcher.on('error', (error) => {\n logger.warn({ error }, 'OpenClaw commands.log watcher error');\n });\n\n this.transcriptWatcher = this.watcherFactory(\n join(this.agentsDirectory, '*', 'sessions', '*.jsonl'),\n {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n },\n );\n this.transcriptWatcher.on('add', (filePath) => {\n void this.processTranscriptUpdate(filePath, true);\n });\n this.transcriptWatcher.on('change', (filePath) => {\n void this.processTranscriptUpdate(filePath, false);\n });\n this.transcriptWatcher.on('error', (error) => {\n logger.warn({ error }, 'OpenClaw transcript watcher error');\n });\n\n this.memoryWatcher = this.watcherFactory([...this.memoryRootGlobs], {\n awaitWriteFinish: {\n stabilityThreshold: 300,\n },\n ignoreInitial: true,\n });\n this.memoryWatcher.on('add', (filePath) => {\n void this.processMemoryUpdate(filePath, true);\n });\n this.memoryWatcher.on('change', (filePath) => {\n void this.processMemoryUpdate(filePath, false);\n });\n this.memoryWatcher.on('error', (error) => {\n logger.warn({ error }, 'OpenClaw memory watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.commandsLogWatcher !== null) {\n await this.commandsLogWatcher.close();\n this.commandsLogWatcher = null;\n }\n\n if (this.transcriptWatcher !== null) {\n await this.transcriptWatcher.close();\n this.transcriptWatcher = null;\n }\n\n if (this.memoryWatcher !== null) {\n await this.memoryWatcher.close();\n this.memoryWatcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n for (const timer of this.pendingThinking.values()) {\n clearTimeout(timer);\n }\n\n this.fileOffsets.clear();\n this.fileRemainders.clear();\n this.fallbackProcessSessions.clear();\n this.observedTranscriptEntries.clear();\n this.pendingThinking.clear();\n this.pendingThinkingState.clear();\n this.sessionSnapshots.clear();\n this.startedSessions.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'OpenClaw payload must be an object');\n return;\n }\n\n await this.processNativePayload(\n payload,\n 'aisnitch://adapters/openclaw/hooks',\n extractOpenClawEventName(payload),\n );\n }\n\n private async processNativePayload(\n payload: Record<string, unknown>,\n source: string,\n eventName: string | undefined,\n transcriptPath?: string,\n ): Promise<void> {\n if (!eventName) {\n logger.debug({ payload, source }, 'OpenClaw payload missing event name');\n return;\n }\n\n const sessionId = resolveSessionId({\n activeFile: extractOpenClawActiveFile(payload),\n cwd: extractOpenClawCwd(payload),\n pid: getNumber(payload, 'pid'),\n project: extractOpenClawProject(payload),\n projectPath: extractOpenClawCwd(payload),\n sessionId: extractOpenClawSessionKey(payload),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n cwd: extractOpenClawCwd(payload),\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source,\n transcriptPath,\n };\n const sharedData = buildOpenClawEventData(payload);\n\n this.sessionSnapshots.set(sessionId, {\n cwd: sharedData.cwd,\n project: sharedData.project,\n sessionId,\n sessionKey: extractOpenClawSessionKey(payload),\n transcriptPath,\n });\n\n switch (eventName) {\n case 'gateway:startup':\n case 'agent:bootstrap': {\n await this.emitOpenClawSessionStart(sharedData, context);\n return;\n }\n case 'command:new':\n case '/new': {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange('task.start', sharedData, context);\n this.scheduleThinking(sessionId, sharedData, context, COMMAND_START_THINKING_DELAY_MS);\n return;\n }\n case 'command:stop':\n case '/stop': {\n this.clearThinking(sessionId);\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'command:reset':\n case '/reset':\n case 'gateway:shutdown': {\n await this.emitOpenClawSessionEnd(sharedData, context);\n return;\n }\n case 'session:compact:before':\n case 'before_compaction': {\n await this.ensureSessionStarted(sharedData, context);\n this.clearThinking(sessionId);\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n case 'tool_result_persist': {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange(\n isOpenClawCodingTool(sharedData.toolName, sharedData.toolInput)\n ? 'agent.coding'\n : 'agent.tool_call',\n sharedData,\n context,\n );\n this.scheduleThinking(sessionId, sharedData, context, POST_TOOL_THINKING_DELAY_MS);\n return;\n }\n case 'message:received':\n case 'message:preprocessed':\n case 'session:compact:after':\n case 'after_compaction': {\n logger.debug({ eventName }, 'OpenClaw event intentionally ignored');\n return;\n }\n default: {\n logger.debug({ eventName }, 'OpenClaw event ignored by adapter');\n }\n }\n }\n\n private async emitOpenClawSessionStart(\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n const sessionId = context.sessionId;\n\n if (!sessionId) {\n return;\n }\n\n if (this.startedSessions.has(sessionId)) {\n await this.emitStateChange('agent.idle', data, context);\n return;\n }\n\n this.startedSessions.add(sessionId);\n await this.emitStateChange('session.start', data, context);\n await this.emitStateChange('agent.idle', data, context);\n }\n\n private async emitOpenClawSessionEnd(\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n const sessionId = context.sessionId;\n\n if (sessionId) {\n this.clearThinking(sessionId);\n this.startedSessions.delete(sessionId);\n this.sessionSnapshots.delete(sessionId);\n }\n\n await this.emitStateChange('session.end', data, context);\n }\n\n private async ensureSessionStarted(\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n const sessionId = context.sessionId;\n\n if (!sessionId || this.startedSessions.has(sessionId)) {\n return;\n }\n\n await this.emitOpenClawSessionStart(\n {\n ...data,\n raw: {\n reason: 'implicit-start',\n source: context.source,\n ...(data.raw ?? {}),\n },\n },\n context,\n );\n }\n\n private scheduleThinking(\n sessionId: string,\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n delayMs: number,\n ): void {\n this.clearThinking(sessionId);\n this.pendingThinkingState.set(sessionId, { context, data });\n\n const timer = setTimeout(() => {\n const thinkingState = this.pendingThinkingState.get(sessionId);\n\n if (!thinkingState) {\n return;\n }\n\n this.pendingThinking.delete(sessionId);\n this.pendingThinkingState.delete(sessionId);\n void this.emitStateChange(\n 'agent.thinking',\n thinkingState.data,\n thinkingState.context,\n );\n }, delayMs);\n timer.unref();\n\n this.pendingThinking.set(sessionId, timer);\n }\n\n private clearThinking(sessionId: string): void {\n const timer = this.pendingThinking.get(sessionId);\n\n if (timer) {\n clearTimeout(timer);\n }\n\n this.pendingThinking.delete(sessionId);\n this.pendingThinkingState.delete(sessionId);\n }\n\n private async seedCommandsLogOffset(): Promise<void> {\n await this.seedFileOffset(this.commandsLogPath);\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n const files = await collectFilesRecursively(this.agentsDirectory, '.jsonl');\n\n await Promise.all(files.map(async (filePath) => await this.seedFileOffset(filePath)));\n }\n\n private async seedMemoryOffsets(): Promise<void> {\n for (const root of [join(this.getUserHomeDirectory(), '.openclaw', 'workspace')]) {\n await Promise.all([\n this.seedDirectoryFileOffsets(join(root, 'memory'), '.md'),\n this.seedFileOffset(join(root, 'MEMORY.md')),\n ]);\n }\n }\n\n private async seedDirectoryFileOffsets(\n directory: string,\n extension: string,\n ): Promise<void> {\n const files = await collectFilesRecursively(directory, extension);\n\n await Promise.all(files.map(async (filePath) => await this.seedFileOffset(filePath)));\n }\n\n private async seedFileOffset(filePath: string): Promise<void> {\n try {\n const fileStats = await stat(filePath);\n\n this.fileOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore missing files while the source is still dormant.\n }\n }\n\n private async processCommandsLogUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n const lines = await this.readIncrementalLines(filePath, readFromStart);\n\n for (const line of lines) {\n const payload = parseJsonRecord(line);\n\n if (!payload) {\n logger.debug({ filePath, line }, 'OpenClaw commands.log line ignored');\n continue;\n }\n\n await this.processNativePayload(\n payload,\n 'aisnitch://adapters/openclaw/commands-log',\n extractOpenClawEventName(payload),\n );\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n const lines = await this.readIncrementalLines(filePath, readFromStart);\n\n for (const line of lines) {\n const parsedLine = parseJsonRecord(line);\n\n if (!parsedLine) {\n continue;\n }\n\n await this.processTranscriptLine(parsedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: Record<string, unknown>,\n filePath: string,\n ): Promise<void> {\n const rawSessionId =\n extractOpenClawSessionKey(line) ??\n inferOpenClawSessionIdFromTranscriptPath(filePath);\n const cwd = extractOpenClawCwd(line) ?? dirname(dirname(filePath));\n const sessionId = resolveSessionId({\n cwd,\n projectPath: cwd,\n sessionId: rawSessionId,\n tool: this.name,\n transcriptPath: filePath,\n });\n const eventFingerprint =\n getString(line, 'id') ??\n `${filePath}:${getString(line, 'timestamp') ?? JSON.stringify(line).slice(0, 120)}`;\n const dedupeKey = `${sessionId}:${eventFingerprint}`;\n\n if (this.observedTranscriptEntries.has(dedupeKey)) {\n return;\n }\n\n if (this.observedTranscriptEntries.size >= 4096) {\n this.observedTranscriptEntries.clear();\n }\n\n this.observedTranscriptEntries.add(dedupeKey);\n\n const context: AdapterPublishContext = {\n cwd,\n sessionId,\n source: 'aisnitch://adapters/openclaw/transcript',\n transcriptPath: filePath,\n };\n const sharedData: Omit<EventData, 'state'> = {\n cwd,\n project: basename(cwd) || cwd,\n projectPath: cwd,\n raw: line,\n };\n\n this.sessionSnapshots.set(sessionId, {\n cwd,\n project: sharedData.project,\n sessionId,\n transcriptPath: filePath,\n });\n\n if (getString(line, 'type') === 'session') {\n await this.emitOpenClawSessionStart(sharedData, context);\n return;\n }\n\n if (getString(line, 'type') === 'compaction') {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n\n const transcriptToolObservation = extractOpenClawTranscriptToolObservation(line);\n\n if (transcriptToolObservation) {\n const toolData: Omit<EventData, 'state'> = {\n ...sharedData,\n activeFile: transcriptToolObservation.activeFile,\n toolInput: transcriptToolObservation.toolInput,\n toolName: transcriptToolObservation.toolName,\n };\n\n await this.ensureSessionStarted(toolData, context);\n await this.emitStateChange(\n transcriptToolObservation.type,\n toolData,\n context,\n );\n this.scheduleThinking(sessionId, toolData, context, POST_TOOL_THINKING_DELAY_MS);\n return;\n }\n\n const thinkingText = extractOpenClawTranscriptThinkingText(line);\n\n if (thinkingText) {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange(\n 'agent.thinking',\n {\n ...sharedData,\n raw: {\n source: line,\n thinking: thinkingText,\n },\n },\n context,\n );\n return;\n }\n\n const streamingText = extractOpenClawTranscriptStreamingText(line);\n\n if (streamingText) {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange(\n 'agent.streaming',\n {\n ...sharedData,\n raw: {\n content: streamingText,\n source: line,\n },\n },\n context,\n );\n }\n }\n\n private async processMemoryUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n const baseName = basename(filePath);\n const resolvedSession = this.resolveMemorySession(filePath);\n\n if (!resolvedSession) {\n return;\n }\n\n const context: AdapterPublishContext = {\n cwd: resolvedSession.cwd,\n sessionId: resolvedSession.sessionId,\n source: 'aisnitch://adapters/openclaw/memory',\n };\n\n if (baseName === 'MEMORY.md') {\n await this.ensureSessionStarted(\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n source: 'memory-file',\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.compact',\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n source: 'memory-file',\n },\n },\n context,\n );\n return;\n }\n\n const lines = await this.readIncrementalLines(filePath, readFromStart);\n const snippet = lines.at(-1)?.trim();\n\n if (!snippet) {\n return;\n }\n\n await this.ensureSessionStarted(\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n source: 'memory-log',\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.thinking',\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n snippet,\n source: 'memory-log',\n },\n },\n context,\n );\n }\n\n private resolveMemorySession(\n filePath: string,\n ): OpenClawSessionSnapshot | undefined {\n const workspaceDirectory =\n basename(filePath) === 'MEMORY.md' ? dirname(filePath) : dirname(dirname(filePath));\n\n for (const snapshot of this.sessionSnapshots.values()) {\n if (snapshot.cwd === workspaceDirectory) {\n return snapshot;\n }\n }\n\n const sessionId = resolveSessionId({\n cwd: workspaceDirectory,\n projectPath: workspaceDirectory,\n sessionId: `openclaw:${basename(workspaceDirectory)}:memory`,\n tool: this.name,\n });\n\n return {\n cwd: workspaceDirectory,\n project: basename(workspaceDirectory) || workspaceDirectory,\n sessionId,\n };\n }\n\n private async readIncrementalLines(\n filePath: string,\n readFromStart: boolean,\n ): Promise<readonly string[]> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'OpenClaw source read skipped');\n return [];\n }\n\n const knownOffset = this.fileOffsets.get(filePath);\n const previousOffset =\n knownOffset ??\n (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.fileRemainders.get(filePath) ?? '') +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.fileOffsets.set(filePath, fileContent.byteLength);\n this.fileRemainders.set(filePath, remainder);\n\n return lines\n .map((line) => line.trimEnd())\n .filter((line) => line.trim().length > 0);\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollOpenClawProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollOpenClawProcesses();\n }\n\n private async pollOpenClawProcesses(): Promise<void> {\n const processes = await listOpenClawProcesses(this.processListCommand);\n const observedPids = new Set<number>();\n\n for (const processInfo of processes) {\n observedPids.add(processInfo.pid);\n\n if (this.fallbackProcessSessions.has(processInfo.pid)) {\n continue;\n }\n\n const cwd = await this.cwdResolver(processInfo.pid);\n const sessionId = resolveSessionId({\n cwd,\n pid: processInfo.pid,\n projectPath: cwd,\n sessionId: `openclaw-process-${processInfo.pid}`,\n tool: this.name,\n });\n const data: Omit<EventData, 'state'> = {\n cwd,\n project: cwd ? basename(cwd) || cwd : undefined,\n projectPath: cwd,\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n };\n const context: AdapterPublishContext = {\n cwd,\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/openclaw/process-detect',\n };\n\n this.fallbackProcessSessions.set(processInfo.pid, sessionId);\n this.sessionSnapshots.set(sessionId, {\n cwd,\n project: data.project,\n sessionId,\n });\n await this.emitOpenClawSessionStart(data, context);\n }\n\n for (const [pid, sessionId] of this.fallbackProcessSessions) {\n if (observedPids.has(pid)) {\n continue;\n }\n\n this.fallbackProcessSessions.delete(pid);\n await this.emitOpenClawSessionEnd(\n {\n raw: {\n pid,\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/openclaw/process-detect',\n },\n );\n }\n }\n}\n\nasync function collectFilesRecursively(\n directory: string,\n extension: string,\n): Promise<string[]> {\n try {\n const directoryEntries = await readdir(directory, {\n withFileTypes: true,\n });\n const nestedFiles = await Promise.all(\n directoryEntries.map(async (entry) => {\n const entryPath = join(directory, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return extname(entry.name) === extension ? [entryPath] : [];\n }),\n );\n\n return nestedFiles.flat();\n } catch {\n return [];\n }\n}\n\nasync function listOpenClawProcesses(\n listCommand: () => Promise<string>,\n): Promise<OpenClawProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n } satisfies OpenClawProcessInfo;\n })\n .filter((value): value is OpenClawProcessInfo => value !== null);\n } catch (error) {\n const errorCode =\n error instanceof Error && 'code' in error ? String(error.code) : '';\n\n if (\n error instanceof Error &&\n 'code' in error &&\n (errorCode === 'ENOENT' || errorCode === '1')\n ) {\n return [];\n }\n\n logger.debug({ error }, 'OpenClaw process detection failed');\n return [];\n }\n}\n\nfunction buildOpenClawEventData(\n payload: Record<string, unknown>,\n): Omit<EventData, 'state'> {\n const cwd = extractOpenClawCwd(payload);\n const project = extractOpenClawProject(payload);\n const toolInput = extractOpenClawToolInput(payload);\n\n return {\n activeFile: extractOpenClawActiveFile(payload) ?? toolInput?.filePath,\n cwd,\n errorMessage: extractOpenClawErrorMessage(payload),\n errorType: inferOpenClawErrorType(payload),\n model: extractOpenClawModel(payload),\n project,\n projectPath: cwd,\n raw: payload,\n toolInput,\n toolName: extractOpenClawToolName(payload),\n tokensUsed: extractOpenClawTokens(payload),\n };\n}\n\nfunction extractOpenClawEventName(\n payload: Record<string, unknown>,\n): string | undefined {\n const explicitEvent =\n getString(payload, 'event') ??\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hookEventName');\n\n if (explicitEvent) {\n return explicitEvent;\n }\n\n const type = getString(payload, 'type');\n const action = getString(payload, 'action');\n\n if (!type) {\n return undefined;\n }\n\n if (!action) {\n return type;\n }\n\n if (type === 'command' && !action.startsWith('/') && !action.includes(':')) {\n return `command:${action}`;\n }\n\n return `${type}:${action}`;\n}\n\nfunction extractOpenClawSessionKey(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'sessionKey') ??\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(getRecord(payload.context), 'sessionKey') ??\n getString(getRecord(payload.context), 'sessionId') ??\n getString(getRecord(payload.context), 'session_id') ??\n getString(getRecord(payload.context), 'sessionEntry')\n );\n}\n\nfunction extractOpenClawCwd(\n payload: Record<string, unknown>,\n): string | undefined {\n const context = getRecord(payload.context);\n\n return (\n getString(payload, 'cwd') ??\n getString(payload, 'workspaceDir') ??\n getString(context, 'workspaceDir') ??\n getString(context, 'cwd')\n );\n}\n\nfunction extractOpenClawProject(\n payload: Record<string, unknown>,\n): string | undefined {\n const cwd = extractOpenClawCwd(payload);\n\n if (cwd) {\n return basename(cwd) || cwd;\n }\n\n return (\n getString(payload, 'project') ??\n getString(getRecord(payload.context), 'project')\n );\n}\n\nfunction extractOpenClawActiveFile(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolInput = extractOpenClawToolInput(payload);\n\n return (\n getString(payload, 'activeFile') ??\n getString(payload, 'filePath') ??\n getString(getRecord(payload.context), 'filePath') ??\n toolInput?.filePath\n );\n}\n\nfunction extractOpenClawToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'toolName') ??\n getString(payload, 'tool_name') ??\n getString(getRecord(payload.tool), 'name') ??\n getString(getRecord(payload.data), 'toolName') ??\n getString(getRecord(payload.result), 'toolName')\n );\n}\n\nfunction extractOpenClawToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const context = getRecord(payload.context);\n const argsRecord =\n getRecord(payload.toolInput) ??\n getRecord(payload.tool_input) ??\n getRecord(payload.params) ??\n getRecord(payload.arguments) ??\n getRecord(getRecord(payload.tool)?.params) ??\n getRecord(getRecord(payload.tool)?.arguments) ??\n getRecord(context?.params) ??\n getRecord(context?.arguments);\n const filePath =\n getString(payload, 'filePath') ??\n getString(argsRecord, 'filePath') ??\n getString(argsRecord, 'path');\n const command =\n getString(payload, 'command') ??\n getString(argsRecord, 'command') ??\n getString(argsRecord, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n ...(command ? { command } : {}),\n ...(filePath ? { filePath } : {}),\n };\n}\n\nfunction extractOpenClawErrorMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n getString(getRecord(payload.error), 'message') ??\n getString(getRecord(payload.result), 'error')\n );\n}\n\nfunction inferOpenClawErrorType(\n payload: Record<string, unknown>,\n): ErrorType | undefined {\n const errorMessage = extractOpenClawErrorMessage(payload);\n\n if (!errorMessage) {\n return undefined;\n }\n\n const normalizedMessage = errorMessage.toLowerCase();\n\n if (normalizedMessage.includes('rate limit') || normalizedMessage.includes('quota')) {\n return 'rate_limit';\n }\n\n if (\n normalizedMessage.includes('context window') ||\n normalizedMessage.includes('context length') ||\n normalizedMessage.includes('too many tokens')\n ) {\n return 'context_overflow';\n }\n\n return OPENCLAW_ERROR_HINT.test(errorMessage) ? 'tool_failure' : 'api_error';\n}\n\nfunction extractOpenClawModel(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'model') ??\n getString(getRecord(payload.context), 'model') ??\n getString(getRecord(payload.sessionEntry), 'model')\n );\n}\n\nfunction extractOpenClawTokens(\n payload: Record<string, unknown>,\n): number | undefined {\n const directTokens =\n getNumber(payload, 'totalTokens') ??\n getNumber(payload, 'tokensUsed') ??\n getNumber(getRecord(payload.sessionEntry), 'totalTokens') ??\n getNumber(getRecord(payload.stats), 'totalTokens');\n\n return directTokens === undefined ? undefined : Math.max(0, directTokens);\n}\n\nfunction isOpenClawCodingTool(\n toolName: string | undefined,\n toolInput: ToolInput | undefined,\n): boolean {\n return Boolean(\n toolInput?.filePath ||\n (toolName && OPENCLAW_CODING_TOOL_HINT.test(toolName)),\n );\n}\n\nfunction inferOpenClawSessionIdFromTranscriptPath(\n filePath: string,\n): string | undefined {\n const fileName = basename(filePath, extname(filePath));\n\n return fileName.length > 0 ? fileName : undefined;\n}\n\nfunction extractOpenClawTranscriptToolObservation(\n payload: Record<string, unknown>,\n):\n | {\n readonly activeFile?: string;\n readonly toolInput?: ToolInput;\n readonly toolName?: string;\n readonly type: AISnitchEventType;\n }\n | null {\n const nestedMessage = getRecord(payload.message) ?? getRecord(payload.data);\n const role =\n getString(payload, 'role') ??\n getString(nestedMessage, 'role') ??\n getString(getRecord(payload.entry), 'role');\n const toolName =\n extractOpenClawToolName(payload) ??\n getString(nestedMessage, 'name') ??\n getString(getRecord(payload.tool), 'name');\n const toolInput = extractOpenClawToolInput(payload);\n const activeFile =\n extractOpenClawActiveFile(payload) ??\n getString(nestedMessage, 'filePath') ??\n toolInput?.filePath;\n const content = getString(nestedMessage, 'content');\n const looksLikeToolPayload = Boolean(\n role === 'tool' ||\n role === 'tool_result' ||\n toolName ||\n getString(payload, 'type') === 'tool_result' ||\n content?.includes('tool') ||\n Array.isArray(getRecord(nestedMessage)?.content),\n );\n\n if (!looksLikeToolPayload) {\n return null;\n }\n\n return {\n activeFile,\n toolInput,\n toolName,\n type: isOpenClawCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call',\n };\n}\n\nfunction extractOpenClawTranscriptThinkingText(\n payload: Record<string, unknown>,\n): string | undefined {\n const directReasoning =\n getString(payload, 'reasoning') ??\n getString(getRecord(payload.message), 'reasoning') ??\n getString(getRecord(payload.data), 'reasoning');\n\n if (directReasoning) {\n return directReasoning;\n }\n\n const content = getRecord(payload.message)?.content;\n\n if (!Array.isArray(content)) {\n return undefined;\n }\n\n for (const item of content) {\n const itemRecord = getRecord(item);\n const itemType = getString(itemRecord, 'type');\n\n if (itemType === 'thinking' || itemType === 'reasoning') {\n return (\n getString(itemRecord, 'thinking') ??\n getString(itemRecord, 'text') ??\n getString(itemRecord, 'content')\n );\n }\n }\n\n return undefined;\n}\n\nfunction extractOpenClawTranscriptStreamingText(\n payload: Record<string, unknown>,\n): string | undefined {\n const directText =\n getString(payload, 'text') ??\n getString(getRecord(payload.message), 'text') ??\n getString(getRecord(payload.data), 'text');\n\n if (directText) {\n return directText;\n }\n\n const content = getRecord(payload.message)?.content;\n\n if (!Array.isArray(content)) {\n return undefined;\n }\n\n for (const item of content) {\n const itemRecord = getRecord(item);\n const itemType = getString(itemRecord, 'type');\n\n if (itemType === 'text' || itemType === 'output_text') {\n return getString(itemRecord, 'text') ?? getString(itemRecord, 'content');\n }\n }\n\n return undefined;\n}\n\nfunction parseJsonRecord(value: string): Record<string, unknown> | null {\n try {\n const parsedValue = JSON.parse(value) as unknown;\n\n return getRecord(parsedValue) ?? null;\n } catch {\n return null;\n }\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const value = payload?.[key];\n\n return typeof value === 'string' && value.trim().length > 0\n ? value\n : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n const value = payload?.[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { ErrorType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/opencode.ts\n * @description OpenCode adapter centered on the official plugin system plus process fallback detection.\n * @functions\n * โ†’ none\n * @exports OpenCodeAdapter, OpenCodeAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/04-adapters-priority/03_adapters-priority_opencode.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst OPENCODE_CODING_TOOLS = new Set(['edit', 'multi_edit', 'write']);\n\n/**\n * OpenCode officially documents plugin hooks and ACP subprocess support.\n * The plugin path is the stable passive-observer option for AISnitch today;\n * ACP is interactive editor transport, not a passive tap into a running TUI.\n */\nexport interface OpenCodeAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n}\n\ninterface ProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– The setup command already installs an OpenCode plugin that forwards\n * events over HTTP, so this adapter mostly focuses on mapping that stream\n * cleanly and falling back to process detection when setup was skipped.\n */\nexport class OpenCodeAdapter extends BaseAdapter {\n public override readonly displayName = 'OpenCode';\n\n public override readonly name = 'opencode' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n public constructor(options: OpenCodeAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ?? (async () => await execFile('pgrep', ['-lf', 'opencode']).then((result) => result.stdout));\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startProcessPolling();\n\n return Promise.resolve();\n }\n\n public override stop(): Promise<void> {\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.setRunning(false);\n\n return Promise.resolve();\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'OpenCode payload must be an object');\n return;\n }\n\n const eventType = getString(payload, 'type');\n\n if (!eventType) {\n logger.warn({ payload }, 'OpenCode payload is missing its event type');\n return;\n }\n\n const sessionId = resolveSessionId({\n activeFile: extractOpenCodeActiveFile(payload),\n cwd: extractOpenCodeCwd(payload),\n pid: getNumber(payload, 'pid'),\n project: extractOpenCodeProject(payload),\n sessionId: extractOpenCodeSessionId(payload),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: extractOpenCodeCwd(payload),\n // ๐Ÿ“– Pass process.env so the context detector can detect the terminal\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/opencode',\n };\n const sharedData = {\n activeFile: extractOpenCodeActiveFile(payload),\n cwd: context.cwd,\n errorMessage: extractOpenCodeErrorMessage(payload),\n errorType: extractOpenCodeErrorType(payload),\n // ๐Ÿ“– Extract model from payload โ€” OpenCode may send it as \"model\" or nested in properties\n model: getString(payload, 'model') ?? getString(getRecord(payload.properties), 'model'),\n project: extractOpenCodeProject(payload),\n raw: payload,\n toolInput: extractOpenCodeToolInput(payload),\n toolName: extractOpenCodeToolName(payload),\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.created': {\n this.fallbackProcessSessionId = null;\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.deleted': {\n const finalMessage = extractOpenCodeFinalMessage(payload);\n await this.emitStateChange('session.end', {\n ...sharedData,\n finalMessage,\n }, context);\n return;\n }\n case 'session.error': {\n await this.emitStateChange('agent.error', sharedData, context);\n return;\n }\n case 'session.idle': {\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.compacted': {\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n case 'message.updated':\n case 'message.part.updated': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'permission.asked': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n case 'tool.execute.before': {\n const toolCallName = extractOpenCodeToolName(payload);\n await this.emitStateChange('agent.tool_call', {\n ...sharedData,\n toolCallName,\n }, context);\n return;\n }\n case 'tool.execute.after': {\n const toolCallName = extractOpenCodeToolName(payload);\n const toolResult = extractOpenCodeToolResult(payload);\n const emittedType = isOpenCodeCodingTool(sharedData.toolName)\n ? 'agent.coding'\n : 'agent.tool_call';\n await this.emitStateChange(emittedType, {\n ...sharedData,\n toolCallName,\n toolResult,\n }, context);\n return;\n }\n default: {\n logger.debug({ eventType }, 'OpenCode event ignored by adapter');\n }\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollOpenCodeProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollOpenCodeProcesses();\n }\n\n private async pollOpenCodeProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `opencode-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/opencode/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/opencode/process-detect',\n },\n );\n }\n }\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<ProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n } satisfies ProcessInfo;\n })\n .filter((processInfo): processInfo is ProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode =\n error instanceof Error && 'code' in error ? String(error.code) : '';\n\n if (\n error instanceof Error &&\n 'code' in error &&\n (errorCode === 'ENOENT' || errorCode === '1')\n ) {\n return [];\n }\n\n logger.debug({ error }, 'OpenCode process detection failed');\n return [];\n }\n}\n\nfunction extractOpenCodeSessionId(\n payload: Record<string, unknown>,\n): string | undefined {\n const directSessionId =\n getString(payload, 'sessionID') ??\n getString(payload, 'sessionId');\n\n if (directSessionId) {\n return directSessionId;\n }\n\n const properties = getRecord(payload.properties);\n\n return getString(properties, 'sessionID') ?? getString(properties, 'sessionId');\n}\n\nfunction extractOpenCodeCwd(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'cwd') ??\n getString(getRecord(payload.properties), 'cwd')\n );\n}\n\nfunction extractOpenCodeProject(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'project') ??\n getString(getRecord(payload.properties), 'project')\n );\n}\n\nfunction extractOpenCodeToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n const tool = getRecord(payload.tool);\n\n return getString(tool, 'name') ?? getString(payload, 'tool');\n}\n\nfunction extractOpenCodeActiveFile(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'file') ??\n getString(getRecord(payload.properties), 'file') ??\n extractOpenCodeToolInput(payload)?.filePath\n );\n}\n\nfunction extractOpenCodeToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const args =\n getRecord(payload.args) ??\n getRecord(getRecord(payload.output)?.args) ??\n getRecord(getRecord(payload.properties)?.args);\n\n if (!args) {\n return undefined;\n }\n\n const command =\n getString(args, 'command') ??\n getString(args, 'cmd');\n const filePath =\n getString(args, 'filePath') ??\n getString(args, 'file_path') ??\n getString(args, 'path');\n\n if (!command && !filePath) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction extractOpenCodeErrorMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(getRecord(payload.error), 'message') ??\n getString(payload, 'message')\n );\n}\n\nfunction extractOpenCodeErrorType(\n payload: Record<string, unknown>,\n): ErrorType | undefined {\n const rawType =\n getString(payload, 'errorType') ??\n getString(getRecord(payload.error), 'type');\n\n switch (rawType) {\n case 'rate_limit':\n return 'rate_limit';\n case 'context_overflow':\n return 'context_overflow';\n case 'tool_failure':\n return 'tool_failure';\n case 'api_error':\n case 'provider_error':\n return 'api_error';\n default:\n return undefined;\n }\n}\n\nfunction isOpenCodeCodingTool(toolName?: string): boolean {\n return toolName !== undefined && OPENCODE_CODING_TOOLS.has(toolName);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the final/completion message from OpenCode payload.\n * This is the summary text shown at the end of an AI run.\n */\nfunction extractOpenCodeFinalMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct final message fields\n const directMessage =\n getString(payload, 'final_message') ??\n getString(payload, 'finalMessage') ??\n getString(payload, 'summary') ??\n getString(payload, 'completion_message');\n\n if (directMessage) {\n return directMessage;\n }\n\n // From result or output fields\n const result =\n getString(payload, 'result') ??\n getString(payload, 'output') ??\n getString(getRecord(payload.properties), 'result');\n\n if (result) {\n return result;\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the tool execution result from OpenCode payload.\n * Contains success messages, error outputs, or short tool results.\n */\nfunction extractOpenCodeToolResult(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct result field\n const directResult =\n getString(payload, 'result') ??\n getString(payload, 'output') ??\n getString(payload, 'toolResult');\n\n if (directResult) {\n return directResult;\n }\n\n // From tool_result object\n const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);\n if (toolResult) {\n return getString(toolResult, 'content') ?? getString(toolResult, 'output');\n }\n\n // From properties.toolResult\n const props = getRecord(payload.properties);\n if (props) {\n const nestedResult = getRecord(props.tool_result) ?? getRecord(props.toolResult);\n if (nestedResult) {\n return getString(nestedResult, 'content') ?? getString(nestedResult, 'output');\n }\n }\n\n return undefined;\n}\n","/**\n * @file src/adapters/pi.ts\n * @description Pi AI Agent adapter using Pi's local API and log monitoring.\n * @functions\n * โ†’ detectPiInstance\n * @exports PiAdapter\n * @see ./base.ts\n * @see ../core/events/types.ts\n */\n\nimport { execFile } from 'node:child_process';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { logger } from '../core/engine/logger.js';\nimport type { AISnitchEventType, EventData } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\nconst execFileAsync = promisify(execFile);\n\ninterface PiActivity {\n sessionId: string;\n state: 'thinking' | 'tool' | 'idle' | 'output' | 'error';\n content?: string;\n toolName?: string;\n toolInput?: { filePath?: string; command?: string };\n model?: string;\n}\n\n/**\n * ๐Ÿ“– Pi is a coding agent by MiniMax. This adapter detects Pi activity through:\n * 1. Process detection (pgrep for pi processes)\n * 2. MiniMax API / local socket detection\n * 3. Log file monitoring\n */\nexport class PiAdapter extends BaseAdapter {\n public override readonly displayName = 'Pi (MiniMax)';\n\n public override readonly name = 'pi' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'api-client',\n 'log-watch',\n ];\n\n private readonly apiPort = 7890;\n\n private readonly logPath: string;\n\n private poller: NodeJS.Timeout | null = null;\n\n private activePiSessions: Map<string, PiActivity> = new Map();\n\n private lastCheckedTime: number = 0;\n\n public constructor(options: AdapterRuntimeOptions) {\n super(options);\n\n this.logPath = join(\n options.homeDirectory ?? process.env.HOME ?? '',\n '.pi',\n 'agent.log',\n );\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startPolling();\n\n logger.info({ adapter: this.name }, 'Pi adapter started');\n\n return Promise.resolve();\n }\n\n public override stop(): Promise<void> {\n if (this.poller !== null) {\n clearInterval(this.poller);\n this.poller = null;\n }\n\n this.setRunning(false);\n logger.info({ adapter: this.name }, 'Pi adapter stopped');\n\n return Promise.resolve();\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalized = this.parseNormalizedHookPayload(payload);\n\n if (normalized === null) {\n return;\n }\n\n const context: AdapterPublishContext = {\n cwd: normalized.cwd,\n pid: normalized.pid,\n sessionId: normalized.sessionId,\n source: 'pi-hook',\n };\n\n const eventType = this.mapEventType(normalized.type ?? '');\n const eventData = this.buildEventData(eventType, normalized);\n\n await this.emit(eventType, eventData, context);\n }\n\n private startPolling(): void {\n this.poller = setInterval(() => {\n void this.pollPiActivity();\n }, 2_000);\n }\n\n private async pollPiActivity(): Promise<void> {\n // Check for Pi processes\n const running = await this.detectPiInstance();\n\n if (!running) {\n // Pi not running, mark sessions as idle\n for (const [sessionId, activity] of this.activePiSessions) {\n if (activity.state !== 'idle') {\n activity.state = 'idle';\n await this.emitIdle(sessionId);\n }\n }\n return;\n }\n\n // Try Pi's local API\n try {\n const response = await fetch(\n `http://127.0.0.1:${this.apiPort}/api/status`,\n {\n signal: AbortSignal.timeout(500),\n },\n );\n\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n await this.processPiApiResponse(data);\n }\n } catch {\n // API not available, try MiniMax API\n await this.checkMiniMaxApi();\n }\n }\n\n private async detectPiInstance(): Promise<boolean> {\n try {\n // Check for Pi/MiniMax process\n const result = await execFileAsync('pgrep', ['-l', 'pi|minimax']);\n\n if (result.stdout.includes('pi') || result.stdout.includes('minimax')) {\n return true;\n }\n } catch {\n // No Pi process found\n }\n\n // Check for Pi socket or port\n try {\n const response = await fetch(\n `http://127.0.0.1:${this.apiPort}/health`,\n {\n signal: AbortSignal.timeout(200),\n },\n );\n\n if (response.ok) {\n return true;\n }\n } catch {\n // Pi not listening\n }\n\n return false;\n }\n\n private async checkMiniMaxApi(): Promise<void> {\n try {\n // Check MiniMax API for running sessions\n const response = await fetch('http://127.0.0.1:3000/api/agent/status', {\n signal: AbortSignal.timeout(500),\n });\n\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n await this.processPiApiResponse(data);\n }\n } catch {\n // MiniMax not running\n }\n }\n\n private async processPiApiResponse(\n data: Record<string, unknown>,\n ): Promise<void> {\n const rawSession = (data.sessionId ?? data.project ?? 'default') as string;\n const sessionId = `pi:${rawSession.replace(/[^a-zA-Z0-9-_]/g, '-')}`;\n\n let activity = this.activePiSessions.get(sessionId);\n\n if (!activity) {\n activity = { sessionId, state: 'idle' };\n this.activePiSessions.set(sessionId, activity);\n await this.emitSessionStart(sessionId, data);\n }\n\n const rawState = (data.state ?? 'idle') as string;\n const state = rawState as PiActivity['state'];\n\n if (state !== activity.state) {\n switch (state) {\n case 'thinking': {\n const rawThinking = data.thinking as string | undefined;\n if (rawThinking) {\n await this.emitThinking(sessionId, rawThinking);\n }\n break;\n }\n case 'tool': {\n const rawFilePath = data.filePath as string | undefined;\n const rawCommand = data.command as string | undefined;\n const rawToolName = (data.toolName as string | undefined) ?? 'unknown';\n await this.emitToolCall(\n sessionId,\n {\n filePath: rawFilePath ?? '',\n command: rawCommand ?? '',\n },\n rawToolName,\n );\n break;\n }\n case 'output': {\n const rawOutput = data.output as string | undefined;\n if (rawOutput) {\n await this.emitOutput(sessionId, rawOutput);\n }\n break;\n }\n case 'error': {\n const rawError = (data.error as string | undefined) ?? 'Unknown error';\n await this.emitError(sessionId, rawError);\n break;\n }\n case 'idle':\n await this.emitIdle(sessionId);\n break;\n }\n\n activity.state = state;\n }\n }\n\n private async emitSessionStart(\n sessionId: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n const rawProject = (data.project as string | undefined) ?? 'pi-project';\n const rawModel = (data.model as string | undefined) ?? 'minimax/moonshot';\n const eventData: EventData = {\n state: 'session.start',\n project: rawProject,\n model: rawModel,\n raw: data,\n };\n\n await this.emit('session.start', eventData, { sessionId });\n }\n\n private async emitThinking(sessionId: string, content: string): Promise<void> {\n if (!content) return;\n\n const eventData: EventData = {\n state: 'agent.thinking',\n thinkingContent: content,\n };\n\n await this.emit('agent.thinking', eventData, { sessionId });\n }\n\n private async emitToolCall(\n sessionId: string,\n toolInput: { filePath?: string; command?: string },\n toolName: string,\n ): Promise<void> {\n const eventData: EventData = {\n state: 'agent.tool_call',\n toolCallName: toolName,\n toolInput,\n activeFile: toolInput.filePath,\n };\n\n await this.emit('agent.tool_call', eventData, { sessionId });\n }\n\n private async emitOutput(sessionId: string, content: string): Promise<void> {\n if (!content) return;\n\n const eventData: EventData = {\n state: 'agent.streaming',\n messageContent: content,\n };\n\n await this.emit('agent.streaming', eventData, { sessionId });\n }\n\n private async emitError(sessionId: string, errorMessage: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.error',\n errorMessage,\n errorType: 'api_error',\n };\n\n await this.emit('agent.error', eventData, { sessionId });\n }\n\n private async emitIdle(sessionId: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.idle',\n };\n\n await this.emit('agent.idle', eventData, { sessionId });\n }\n\n private mapEventType(type: string): AISnitchEventType {\n const mapping: Record<string, AISnitchEventType> = {\n 'session.start': 'session.start',\n 'session.end': 'session.end',\n 'task.start': 'task.start',\n 'task.complete': 'task.complete',\n thinking: 'agent.thinking',\n tool: 'agent.tool_call',\n coding: 'agent.coding',\n output: 'agent.streaming',\n message: 'agent.streaming',\n ask: 'agent.asking_user',\n error: 'agent.error',\n idle: 'agent.idle',\n compact: 'agent.compact',\n };\n\n return mapping[type] ?? 'agent.streaming';\n }\n\n private buildEventData(\n eventType: AISnitchEventType,\n payload: Record<string, unknown>,\n ): EventData {\n const data = (payload.data ?? {}) as Partial<EventData>;\n\n return {\n state: eventType,\n project: data.project,\n activeFile: data.activeFile,\n model: data.model,\n toolInput: data.toolInput,\n toolCallName: data.toolCallName,\n thinkingContent: data.thinkingContent,\n messageContent: data.messageContent,\n finalMessage: data.finalMessage,\n toolResult: data.toolResult,\n errorMessage: data.errorMessage,\n errorType: data.errorType,\n raw: data.raw,\n };\n }\n}\n","/**\n * @file src/adapters/zed.ts\n * @description Zed AI Agent adapter using log file monitoring and IPC detection.\n * @functions\n * โ†’ extractZedEventFromLog\n * @exports ZedAdapter\n * @see ./base.ts\n * @see ../core/events/types.ts\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\n\nimport { logger } from '../core/engine/logger.js';\nimport type { AISnitchEventType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * ๐Ÿ“– Zed Agent (zed.dev) exposes a local HTTP API on port 9876 for its agent.\n * This adapter polls that endpoint and watches Zed's log file for activity.\n */\nexport class ZedAdapter extends BaseAdapter {\n public override readonly displayName = 'Zed AI';\n\n public override readonly name = 'zed' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'api-client',\n ];\n\n private readonly logPaths: readonly string[];\n\n private readonly apiPort = 9876;\n\n private readonly pollIntervalMs: number;\n\n private poller: NodeJS.Timeout | null = null;\n\n private lastEventTime: number = 0;\n\n private activeZedSessions: Map<string, string> = new Map();\n\n public constructor(options: AdapterRuntimeOptions) {\n super(options);\n\n this.pollIntervalMs = 2_000;\n this.logPaths = [\n join(options.homeDirectory ?? process.env.HOME ?? '', '.config', 'zed', 'logs', 'agent.log'),\n '/tmp/zed-agent.log',\n ];\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startPolling();\n\n logger.info({ adapter: this.name }, 'Zed adapter started');\n\n return Promise.resolve();\n }\n\n public override stop(): Promise<void> {\n if (this.poller !== null) {\n clearInterval(this.poller);\n this.poller = null;\n }\n\n this.setRunning(false);\n logger.info({ adapter: this.name }, 'Zed adapter stopped');\n\n return Promise.resolve();\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalized = this.parseNormalizedHookPayload(payload);\n\n if (normalized === null) {\n return;\n }\n\n const context: AdapterPublishContext = {\n cwd: normalized.cwd,\n pid: normalized.pid,\n sessionId: normalized.sessionId,\n source: 'zed-hook',\n };\n\n const eventType = this.mapEventType(normalized.type ?? '');\n const eventData = this.buildEventData(eventType, normalized);\n\n await this.emit(eventType, eventData, context);\n }\n\n private startPolling(): void {\n this.poller = setInterval(() => {\n void this.pollZedStatus();\n }, this.pollIntervalMs);\n }\n\n private async pollZedStatus(): Promise<void> {\n try {\n // Try Zed's agent API\n const response = await fetch(`http://127.0.0.1:${this.apiPort}/api/agent/status`, {\n signal: AbortSignal.timeout(1_000),\n });\n\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n\n if (data.sessionId && typeof data.sessionId === 'string') {\n const sessionId = `zed:${data.sessionId}`;\n\n if (!this.activeZedSessions.has(sessionId)) {\n this.activeZedSessions.set(sessionId, sessionId);\n await this.emitSessionStart(sessionId, data);\n }\n\n if (data.state === 'thinking' && this.lastEventTime < Date.now() - 5_000) {\n const rawThinking = data.thinking as string | undefined;\n if (rawThinking) {\n await this.emitThinking(sessionId, rawThinking);\n }\n } else if (data.state === 'tool' && data.toolName) {\n const rawFilePath = data.filePath as string | undefined;\n const rawCommand = data.command as string | undefined;\n const rawToolName = (data.toolName as string | undefined) ?? 'unknown';\n await this.emitToolCall(\n sessionId,\n {\n filePath: rawFilePath ?? '',\n command: rawCommand ?? '',\n },\n rawToolName,\n );\n } else if (data.state === 'idle') {\n await this.emitIdle(sessionId);\n }\n }\n }\n } catch {\n // Zed agent not running or API not available - fall through to log parsing\n await this.checkLogFiles();\n }\n }\n\n private async checkLogFiles(): Promise<void> {\n for (const logPath of this.logPaths) {\n try {\n const content = await readFile(logPath, 'utf8');\n await this.parseLogContent(content);\n } catch {\n // Log file doesn't exist yet\n }\n }\n }\n\n private async parseLogContent(content: string): Promise<void> {\n const lines = content.split('\\n').filter((line) => line.trim());\n\n for (const line of lines) {\n if (this.lastEventTime > 0 && this.lastEventTime >= Date.now() - 2_000) {\n continue;\n }\n\n const event = this.extractZedEventFromLog(line);\n if (event) {\n await this.handleHook(event);\n this.lastEventTime = Date.now();\n }\n }\n }\n\n private extractZedEventFromLog(\n line: string,\n ): Record<string, unknown> | null {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n\n if (!parsed.type || typeof parsed.type !== 'string') {\n return null;\n }\n\n const rawSessionId = parsed.sessionId as string | undefined;\n const rawWorkspace = parsed.workspace as string | undefined;\n const sessionId = rawSessionId\n ? rawSessionId\n : rawWorkspace\n ? `zed:${basename(rawWorkspace)}`\n : `zed:${Date.now()}`;\n\n const rawCwd = (parsed.cwd ?? rawWorkspace) as string | undefined;\n\n return {\n type: parsed.type,\n sessionId,\n cwd: rawCwd,\n data: {\n project: parsed.project ?? rawWorkspace ? basename(String(rawWorkspace)) : undefined,\n model: parsed.model,\n state: parsed.type,\n thinkingContent: parsed.thinking,\n toolCallName: parsed.toolName,\n toolInput: parsed.toolInput,\n messageContent: parsed.message ?? parsed.output,\n errorMessage: parsed.error,\n raw: parsed,\n },\n };\n } catch {\n // Not JSON - try pattern matching for plain text logs\n if (line.includes('[zed:agent]')) {\n const cleaned = line.replace(/^\\[.*?\\] \\[.*?\\] /, '');\n\n if (cleaned.includes('Thinking:')) {\n return { type: 'thinking', thinkingContent: cleaned.replace('Thinking:', '').trim() };\n }\n if (cleaned.includes('Executing tool:')) {\n return { type: 'tool', toolCallName: cleaned.replace('Executing tool:', '').trim() };\n }\n if (cleaned.includes('Error:')) {\n return { type: 'error', errorMessage: cleaned.replace('Error:', '').trim() };\n }\n }\n\n return null;\n }\n }\n\n private async emitSessionStart(sessionId: string, _data: Record<string, unknown>): Promise<void> {\n const eventData: EventData = {\n state: 'session.start',\n project: sessionId.split(':')[1] ?? 'unknown',\n };\n\n await this.emit('session.start', eventData, { sessionId });\n }\n\n private async emitThinking(sessionId: string, content: string): Promise<void> {\n if (!content) return;\n\n const eventData: EventData = {\n state: 'agent.thinking',\n thinkingContent: content,\n };\n\n await this.emit('agent.thinking', eventData, { sessionId });\n this.lastEventTime = Date.now();\n }\n\n private async emitToolCall(sessionId: string, toolInput: ToolInput, toolName: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.tool_call',\n toolCallName: toolName,\n toolInput,\n activeFile: toolInput.filePath,\n };\n\n await this.emit('agent.tool_call', eventData, { sessionId });\n this.lastEventTime = Date.now();\n }\n\n private async emitIdle(sessionId: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.idle',\n };\n\n await this.emit('agent.idle', eventData, { sessionId });\n }\n\n private mapEventType(type: string): AISnitchEventType {\n const mapping: Record<string, AISnitchEventType> = {\n 'session.start': 'session.start',\n 'session.end': 'session.end',\n 'task.start': 'task.start',\n 'task.complete': 'task.complete',\n thinking: 'agent.thinking',\n tool: 'agent.tool_call',\n coding: 'agent.coding',\n output: 'agent.streaming',\n message: 'agent.streaming',\n ask: 'agent.asking_user',\n error: 'agent.error',\n idle: 'agent.idle',\n compact: 'agent.compact',\n };\n\n return mapping[type] ?? 'agent.streaming';\n }\n\n private buildEventData(\n eventType: AISnitchEventType,\n payload: Record<string, unknown>,\n ): EventData {\n const data = (payload.data ?? {}) as Partial<EventData>;\n\n return {\n state: eventType,\n project: data.project,\n activeFile: data.activeFile,\n model: data.model,\n toolInput: data.toolInput,\n toolCallName: data.toolCallName,\n thinkingContent: data.thinkingContent,\n messageContent: data.messageContent,\n finalMessage: data.finalMessage,\n toolResult: data.toolResult,\n errorMessage: data.errorMessage,\n errorType: data.errorType,\n raw: data.raw,\n };\n }\n}\n","import type { AISnitchConfig } from '../core/config/schema.js';\nimport type { ToolName } from '../core/events/types.js';\nimport type { AdapterStatus, BaseAdapter } from './base.js';\n\nimport { logger } from '../core/engine/logger.js';\n\n/**\n * @file src/adapters/registry.ts\n * @description Adapter registry that owns built-in adapter instances and orchestrates their lifecycle.\n * @functions\n * โ†’ none\n * @exports AdapterRegistry\n * @see ./base.ts\n * @see ./index.ts\n */\n\n/**\n * ๐Ÿ“– The registry is intentionally tiny: one place to register adapters, one\n * place to start/stop them, and one place to ask what is alive right now.\n */\nexport class AdapterRegistry {\n private readonly adapters = new Map<ToolName, BaseAdapter>();\n\n /**\n * Registers one built-in or community adapter instance.\n */\n public register(adapter: BaseAdapter): void {\n if (this.adapters.has(adapter.name)) {\n throw new Error(`Adapter \"${adapter.name}\" is already registered.`);\n }\n\n this.adapters.set(adapter.name, adapter);\n }\n\n /**\n * Returns one adapter instance by its tool name.\n */\n public get(toolName: ToolName): BaseAdapter | undefined {\n return this.adapters.get(toolName);\n }\n\n /**\n * Lists every registered adapter.\n */\n public list(): BaseAdapter[] {\n return [...this.adapters.values()];\n }\n\n /**\n * Returns one status snapshot per registered adapter.\n */\n public getStatus(): AdapterStatus[] {\n return this.list().map((adapter) => adapter.getStatus());\n }\n\n /**\n * Starts every adapter enabled in the current AISnitch config.\n * ๐Ÿ“– Each adapter is started independently โ€” one failure does not prevent\n * the others from starting.\n */\n public async startAll(config: AISnitchConfig): Promise<void> {\n for (const adapter of this.list()) {\n if (config.adapters[adapter.name]?.enabled !== true) {\n continue;\n }\n\n try {\n await adapter.start();\n } catch (error: unknown) {\n logger.error(\n { error, adapter: adapter.name },\n `๐Ÿ“– Failed to start adapter \"${adapter.name}\" โ€” skipping`,\n );\n }\n }\n }\n\n /**\n * Stops every adapter in reverse registration order.\n * ๐Ÿ“– Each adapter is stopped independently โ€” one failure does not prevent\n * the others from being stopped.\n */\n public async stopAll(): Promise<void> {\n const adapters = this.list().reverse();\n\n for (const adapter of adapters) {\n try {\n await adapter.stop();\n } catch (error: unknown) {\n logger.warn(\n { error, adapter: adapter.name },\n `๐Ÿ“– Error stopping adapter \"${adapter.name}\" โ€” continuing`,\n );\n }\n }\n }\n}\n","import { basename } from 'node:path';\n\nimport { spawn as spawnPty, type IPty } from '@lydell/node-pty';\nimport stripAnsi from 'strip-ansi';\n\nimport { createEvent } from '../core/events/factory.js';\nimport type {\n AISnitchEvent,\n AISnitchEventType,\n ErrorType,\n EventData,\n ToolName,\n} from '../core/events/types.js';\nimport { ContextDetector } from '../core/engine/context-detector.js';\nimport { resolveSessionId } from '../core/session-identity.js';\n\n/**\n * @file src/adapters/generic-pty.ts\n * @description Generic PTY wrapper used by `aisnitch wrap` to observe interactive tools without first-class adapters.\n * @functions\n * โ†’ analyzeTerminalOutputChunk\n * @exports GenericPTYSession, GenericPTYSessionOptions, GenericPTYObservation, analyzeTerminalOutputChunk\n * @see ../cli/runtime.ts\n * @see ../../tasks/06-adapters-secondary/03_adapters-secondary_aider-pty_DONE.md\n */\n\nconst PTY_ERROR_HINT = /error|exception|failed|traceback|refused|denied/iu;\nconst PTY_ASKING_USER_HINT =\n /\\b\\(Y(?:es)?\\/N(?:o)?\\)|\\bPress Enter\\b|\\bcontinue\\?\\b|\\bselect\\b|\\bchoose\\b|\\bapprove\\b/iu;\nconst PTY_THINKING_HINT =\n /thinking|analyzing|planning|reasoning|reflecting|compacting|summarizing/iu;\nconst PTY_CODING_HINT =\n /apply_patch|creating|deleting|editing|patch|renaming|replacing|search\\/replace|updating|writing|<<<<<<<|>>>>>>>|diff --git/iu;\nconst PTY_SPINNER_FRAME_HINT = /[|/\\\\-]|[โ ‹โ ™โ นโ ธโ ผโ ดโ ฆโ งโ ‡โ ]/u;\n\nexport interface GenericPTYSessionOptions {\n readonly args: readonly string[];\n readonly command: string;\n readonly cwd: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly publishEvent: (\n event: AISnitchEvent,\n context?: {\n readonly cwd?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly pid?: number;\n },\n ) => Promise<boolean>;\n readonly rows?: number;\n readonly cols?: number;\n readonly stdin?: NodeJS.ReadStream;\n readonly stdout?: NodeJS.WriteStream;\n}\n\nexport interface GenericPTYObservation {\n readonly fingerprint: string;\n readonly type: AISnitchEventType;\n readonly data: Omit<EventData, 'state'>;\n}\n\n/**\n * ๐Ÿ“– The wrapper deliberately uses heuristics instead of pretending it has a\n * stable protocol. Its job is to recover useful live signals from messy ANSI.\n */\nexport class GenericPTYSession {\n private readonly args: readonly string[];\n\n private readonly cols: number;\n\n private readonly command: string;\n\n private readonly commandLine: string;\n\n private readonly contextDetector = new ContextDetector();\n\n private readonly cwd: string;\n\n private readonly env: NodeJS.ProcessEnv;\n\n private lastObservationFingerprint: string | null = null;\n\n private readonly publishEvent: GenericPTYSessionOptions['publishEvent'];\n\n private readonly rows: number;\n\n private sequenceNumber = 0;\n\n private readonly stdin: NodeJS.ReadStream;\n\n private readonly stdout: NodeJS.WriteStream;\n\n private readonly tool: ToolName;\n\n private userInputBuffer = '';\n\n public constructor(options: GenericPTYSessionOptions) {\n this.args = options.args;\n this.command = options.command;\n this.commandLine = [options.command, ...options.args].join(' ').trim();\n this.cols = options.cols ?? process.stdout.columns ?? 120;\n this.cwd = options.cwd;\n this.env = {\n ...process.env,\n ...options.env,\n };\n this.publishEvent = options.publishEvent;\n this.rows = options.rows ?? process.stdout.rows ?? 32;\n this.stdin = options.stdin ?? process.stdin;\n this.stdout = options.stdout ?? process.stdout;\n this.tool = inferWrappedToolName(options.command, options.args);\n }\n\n /**\n * Launches the wrapped PTY session and resolves with the wrapped exit code.\n */\n public async run(): Promise<number> {\n const pty = spawnPty(this.command, [...this.args], {\n cols: this.cols,\n cwd: this.cwd,\n env: normalizePtyEnvironment(this.env),\n rows: this.rows,\n });\n const sessionId = resolveSessionId({\n cwd: this.cwd,\n pid: pty.pid,\n tool: this.tool,\n });\n const terminal = this.contextDetector.detectTerminal(this.env);\n\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'session.start',\n {\n cwd: this.cwd,\n pid: pty.pid,\n project: basename(this.cwd) || this.cwd,\n projectPath: this.cwd,\n raw: {\n args: this.args,\n command: this.command,\n source: 'pty-wrap',\n },\n terminal,\n toolInput: {\n command: this.commandLine,\n },\n toolName: basename(this.command) || this.command,\n },\n );\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'task.start',\n {\n cwd: this.cwd,\n pid: pty.pid,\n project: basename(this.cwd) || this.cwd,\n projectPath: this.cwd,\n raw: {\n args: this.args,\n command: this.command,\n source: 'pty-wrap',\n },\n terminal,\n toolInput: {\n command: this.commandLine,\n },\n },\n );\n\n return await new Promise<number>((resolve) => {\n let settled = false;\n let exitPoller: NodeJS.Timeout | null = null;\n const finalize = (exitCode: number, signal?: number) => {\n if (settled) {\n return;\n }\n\n settled = true;\n if (exitPoller !== null) {\n clearInterval(exitPoller);\n }\n void this.handleExit(pty, sessionId, terminal, exitCode, signal).finally(() => {\n inputCleanup();\n resizeCleanup();\n signalCleanup();\n dataDisposable.dispose();\n exitDisposable.dispose();\n resolve(exitCode);\n });\n };\n const dataDisposable = pty.onData((chunk: string) => {\n this.stdout.write(chunk);\n void this.handleOutputChunk(pty, sessionId, terminal, chunk);\n });\n const exitDisposable = pty.onExit(\n ({ exitCode, signal }: { exitCode: number; signal?: number }) => {\n finalize(exitCode, signal);\n },\n );\n exitPoller = setInterval(() => {\n if (!isPidRunning(pty.pid)) {\n finalize(0);\n }\n }, 200);\n exitPoller.unref();\n const inputCleanup = this.attachStdin(pty, sessionId, terminal);\n const resizeCleanup = this.attachResize(pty);\n const signalCleanup = this.attachParentSignals(pty);\n });\n }\n\n private attachParentSignals(pty: IPty): () => void {\n const handleSigterm = () => {\n pty.kill('SIGTERM');\n };\n const handleSigint = () => {\n pty.kill('SIGINT');\n };\n\n process.on('SIGTERM', handleSigterm);\n process.on('SIGINT', handleSigint);\n\n return () => {\n process.off('SIGTERM', handleSigterm);\n process.off('SIGINT', handleSigint);\n };\n }\n\n private attachResize(pty: IPty): () => void {\n if (!this.stdout.isTTY) {\n return () => undefined;\n }\n\n const handleResize = () => {\n pty.resize(process.stdout.columns ?? this.cols, process.stdout.rows ?? this.rows);\n };\n\n this.stdout.on('resize', handleResize);\n\n return () => {\n this.stdout.off('resize', handleResize);\n };\n }\n\n private attachStdin(\n pty: IPty,\n sessionId: string,\n terminal: string,\n ): () => void {\n const input = this.stdin;\n\n if (!input.isTTY) {\n return () => undefined;\n }\n\n const handleInput = (chunk: Buffer) => {\n pty.write(chunk);\n void this.captureUserInput(pty, sessionId, terminal, chunk.toString('utf8'));\n };\n\n input.resume();\n input.setRawMode?.(true);\n input.on('data', handleInput);\n\n return () => {\n input.off('data', handleInput);\n input.setRawMode?.(false);\n void this.flushUserInput(sessionId, pty.pid, terminal);\n };\n }\n\n private async captureUserInput(\n pty: IPty,\n sessionId: string,\n terminal: string,\n chunk: string,\n ): Promise<void> {\n const sanitizedChunk = stripTerminalControlCharacters(chunk);\n\n if (sanitizedChunk.includes('\\r') || sanitizedChunk.includes('\\n')) {\n await this.flushUserInput(sessionId, pty.pid, terminal);\n return;\n }\n\n const printableChunk = sanitizedChunk.trim();\n\n if (printableChunk.length === 0) {\n return;\n }\n\n this.userInputBuffer = `${this.userInputBuffer}${printableChunk}`;\n\n if (this.userInputBuffer.length >= 120) {\n await this.flushUserInput(sessionId, pty.pid, terminal);\n }\n }\n\n private async flushUserInput(\n sessionId: string,\n pid: number,\n terminal: string,\n ): Promise<void> {\n const input = this.userInputBuffer.trim();\n\n if (input.length === 0) {\n this.userInputBuffer = '';\n return;\n }\n\n this.userInputBuffer = '';\n\n await this.emitEvent(\n pid,\n sessionId,\n 'agent.asking_user',\n {\n cwd: this.cwd,\n pid,\n raw: {\n input,\n source: 'pty-stdin',\n },\n terminal,\n },\n );\n }\n\n private async handleOutputChunk(\n pty: IPty,\n sessionId: string,\n terminal: string,\n chunk: string,\n ): Promise<void> {\n const observation = analyzeTerminalOutputChunk({\n chunk,\n commandLine: this.commandLine,\n tool: this.tool,\n });\n\n if (!observation) {\n return;\n }\n\n if (this.lastObservationFingerprint === observation.fingerprint) {\n return;\n }\n\n this.lastObservationFingerprint = observation.fingerprint;\n await this.emitEvent(pty.pid, sessionId, observation.type, {\n cwd: this.cwd,\n pid: pty.pid,\n project: basename(this.cwd) || this.cwd,\n projectPath: this.cwd,\n terminal,\n ...observation.data,\n });\n }\n\n private async handleExit(\n pty: IPty,\n sessionId: string,\n terminal: string,\n exitCode: number,\n signal: number | undefined,\n ): Promise<void> {\n await this.flushUserInput(sessionId, pty.pid, terminal);\n\n if (exitCode !== 0) {\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'agent.error',\n {\n cwd: this.cwd,\n errorMessage: `Wrapped process exited with code ${exitCode}.`,\n errorType: 'tool_failure',\n pid: pty.pid,\n raw: {\n exitCode,\n signal,\n source: 'pty-wrap',\n },\n terminal,\n },\n );\n }\n\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'session.end',\n {\n cwd: this.cwd,\n pid: pty.pid,\n raw: {\n exitCode,\n signal,\n source: 'pty-wrap',\n },\n terminal,\n },\n );\n }\n\n private async emitEvent(\n pid: number,\n sessionId: string,\n type: AISnitchEventType,\n data: Omit<EventData, 'state'>,\n ): Promise<void> {\n this.sequenceNumber += 1;\n\n await this.publishEvent(\n createEvent({\n source: `aisnitch://adapters/${this.tool}/pty-wrap`,\n type,\n 'aisnitch.tool': this.tool,\n 'aisnitch.sessionid': sessionId,\n 'aisnitch.seqnum': this.sequenceNumber,\n data,\n }),\n {\n cwd: this.cwd,\n env: this.env,\n pid,\n },\n );\n }\n}\n\n/**\n * Interprets one PTY chunk into the best-effort AISnitch activity state.\n */\nexport function analyzeTerminalOutputChunk(input: {\n readonly chunk: string;\n readonly commandLine: string;\n readonly tool: ToolName;\n}): GenericPTYObservation | null {\n const strippedText = stripAnsi(input.chunk)\n .replaceAll('\\u0007', '');\n const normalizedText = stripTerminalControlCharacters(strippedText)\n .replaceAll('\\r', '\\n')\n .trim();\n\n if (normalizedText.length === 0) {\n return null;\n }\n\n const activeFile = extractPathReference(normalizedText);\n const raw = {\n chunk: input.chunk,\n output: normalizedText,\n source: 'pty-wrap',\n } satisfies Record<string, unknown>;\n\n if (containsRedAnsi(input.chunk) || PTY_ERROR_HINT.test(normalizedText)) {\n return {\n data: {\n activeFile,\n errorMessage: normalizedText,\n errorType: classifyPtyErrorType(normalizedText),\n raw,\n },\n fingerprint: createPtyFingerprint('agent.error', normalizedText, activeFile),\n type: 'agent.error',\n };\n }\n\n if (PTY_ASKING_USER_HINT.test(normalizedText)) {\n return {\n data: {\n activeFile,\n raw,\n },\n fingerprint: createPtyFingerprint(\n 'agent.asking_user',\n normalizedText,\n activeFile,\n ),\n type: 'agent.asking_user',\n };\n }\n\n if (\n PTY_CODING_HINT.test(normalizedText) ||\n (activeFile !== undefined && /\\.(?:[cm]?[jt]sx?|json|md|py|rb|rs|sh|ya?ml)$/u.test(activeFile))\n ) {\n return {\n data: {\n activeFile,\n raw,\n toolInput: activeFile\n ? {\n filePath: activeFile,\n }\n : {\n command: input.commandLine,\n },\n toolName: activeFile ? 'file-edit' : basename(input.commandLine) || 'shell',\n },\n fingerprint: createPtyFingerprint('agent.coding', normalizedText, activeFile),\n type: 'agent.coding',\n };\n }\n\n if (containsSpinnerHint(input.chunk) || PTY_THINKING_HINT.test(normalizedText)) {\n return {\n data: {\n raw,\n },\n fingerprint: createPtyFingerprint('agent.thinking', normalizedText, activeFile),\n type: 'agent.thinking',\n };\n }\n\n return {\n data: {\n activeFile,\n raw,\n },\n fingerprint: createPtyFingerprint('agent.streaming', normalizedText, activeFile),\n type: 'agent.streaming',\n };\n}\n\nfunction normalizePtyEnvironment(\n env: NodeJS.ProcessEnv,\n): Record<string, string | undefined> {\n return Object.fromEntries(\n Object.entries(env).map(([key, value]) => [key, value]),\n );\n}\n\nfunction inferWrappedToolName(\n command: string,\n args: readonly string[],\n): ToolName {\n const commandBaseName = basename(command).toLowerCase();\n const fullCommandLine = [commandBaseName, ...args].join(' ').toLowerCase();\n const toolMatchers: readonly [ToolName, RegExp][] = [\n ['aider', /\\baider\\b/u],\n ['amp', /\\bamp\\b/u],\n ['claude-code', /\\bclaude\\b/u],\n ['copilot-cli', /\\bcopilot\\b/u],\n ['codex', /\\bcodex\\b/u],\n ['continue', /\\bcontinue\\b/u],\n ['cursor', /\\bcursor\\b/u],\n ['gemini-cli', /\\bgemini\\b/u],\n ['goose', /\\bgoose\\b/u],\n ['kilo', /\\bkilo\\b/u],\n ['openclaw', /\\bopenclaw\\b/u],\n ['opencode', /\\bopencode\\b/u],\n ['openhands', /\\bopenhands\\b/u],\n ['qwen-code', /\\bqwen\\b/u],\n ['windsurf', /\\bwindsurf\\b/u],\n ];\n\n for (const [toolName, matcher] of toolMatchers) {\n if (matcher.test(fullCommandLine)) {\n return toolName;\n }\n }\n\n return 'unknown';\n}\n\nfunction extractPathReference(text: string): string | undefined {\n const pathMatch = text.match(\n /(?:^|[\\s'\"])((?:\\.{0,2}\\/|\\/)?[A-Za-z0-9._/-]+\\.[A-Za-z0-9._-]+)(?=$|[\\s'\":,)])/u,\n );\n\n return pathMatch?.[1];\n}\n\nfunction classifyPtyErrorType(message: string): ErrorType {\n if (/rate limit|quota|too many requests/iu.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|context window/iu.test(message)) {\n return 'context_overflow';\n }\n\n if (/write|edit|patch|apply|command failed|exit code/iu.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nfunction createPtyFingerprint(\n type: AISnitchEventType,\n text: string,\n activeFile?: string,\n): string {\n return [type, activeFile ?? '', text.replace(/\\s+/gu, ' ').slice(0, 240)].join(\n '::',\n );\n}\n\nfunction stripTerminalControlCharacters(value: string): string {\n return [...value]\n .filter((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n\n return !(\n (codePoint >= 0x00 && codePoint <= 0x08) ||\n (codePoint >= 0x0b && codePoint <= 0x1a) ||\n (codePoint >= 0x1c && codePoint <= 0x1f) ||\n codePoint === 0x7f\n );\n })\n .join('');\n}\n\nfunction containsRedAnsi(value: string): boolean {\n return (\n value.includes('\\u001B[31m') ||\n value.includes('\\u001B[0;31m') ||\n value.includes('\\u001B[91m')\n );\n}\n\nfunction containsSpinnerHint(value: string): boolean {\n return (\n (value.includes('\\r') || value.includes('\\u0008')) &&\n PTY_SPINNER_FRAME_HINT.test(value)\n );\n}\n\nfunction isPidRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n (error.code === 'ESRCH' || error.code === 'ENOENT')\n ) {\n return false;\n }\n\n return true;\n }\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { basename } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport pidCwd from 'pid-cwd';\n\nimport type { AISnitchEvent, ToolName } from '../events/types.js';\nimport { logger } from './logger.js';\n\nconst execFile = promisify(execFileCallback);\n\n/**\n * @file src/core/engine/context-detector.ts\n * @description Best-effort runtime context enrichment for terminal, cwd, pid, and instance metadata.\n * @functions\n * โ†’ none\n * @exports ProcessInfo, ProcessContext, EnrichedContextFields, ContextDetector\n * @see ../events/schema.ts\n */\n\n/**\n * Lightweight process metadata used during instance enumeration.\n */\nexport interface ProcessInfo {\n readonly pid: number;\n readonly cwd?: string;\n}\n\n/**\n * Context captured from a tool process, transcript path, or hook payload.\n */\nexport interface ProcessContext {\n readonly pid?: number;\n readonly env?: NodeJS.ProcessEnv;\n readonly sessionId?: string;\n readonly transcriptPath?: string;\n readonly hookPayload?: Record<string, unknown>;\n}\n\n/**\n * Context fields that AISnitch attaches into `event.data`.\n */\nexport interface EnrichedContextFields {\n readonly terminal?: string;\n readonly cwd?: string;\n readonly pid?: number;\n readonly instanceId?: string;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n}\n\ninterface CachedProcessContext {\n readonly terminal?: string;\n readonly cwd?: string;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n readonly expiresAt: number;\n}\n\ninterface CommandExecutionOptions {\n readonly timeoutMs?: number;\n}\n\ninterface ContextDetectorOptions {\n readonly cacheTtlMs?: number;\n readonly commandTimeoutMs?: number;\n readonly cwdResolver?: (pid: number) => Promise<string | undefined>;\n readonly execCommand?: (\n command: string,\n args: readonly string[],\n options?: CommandExecutionOptions,\n ) => Promise<string>;\n readonly now?: () => number;\n}\n\nconst TERM_PROGRAM_MAP: Record<string, string> = {\n Apple_Terminal: 'Terminal.app',\n Hyper: 'Hyper',\n 'iTerm.app': 'iTerm2',\n WezTerm: 'WezTerm',\n ghostty: 'Ghostty',\n tmux: 'tmux',\n vscode: 'VS Code',\n zed: 'Zed',\n};\n\nconst PROCESS_NAME_MAP: Record<string, string> = {\n Alacritty: 'Alacritty',\n Hyper: 'Hyper',\n Terminal: 'Terminal.app',\n Warp: 'Warp',\n WezTerm: 'WezTerm',\n ghostty: 'Ghostty',\n iTerm2: 'iTerm2',\n kitty: 'kitty',\n screen: 'screen',\n tmux: 'tmux',\n 'tmux: server': 'tmux',\n};\n\nconst TOOL_BINARY_MAP: Record<ToolName, string> = {\n 'aider': 'aider',\n 'amp': 'amp',\n 'augment-code': 'auggie',\n 'claude-code': 'claude',\n 'cline': 'cline',\n 'codex': 'codex',\n 'continue': 'continue',\n 'copilot-cli': 'copilot',\n 'cursor': 'cursor',\n 'devin': 'devin',\n 'gemini-cli': 'gemini',\n 'goose': 'goose',\n 'kilo': 'kilo',\n 'kiro': 'kiro',\n 'mistral': 'mistral',\n 'openhands': 'openhands',\n 'openclaw': 'openclaw',\n 'opencode': 'opencode',\n 'pi': 'pi',\n 'qwen-code': 'qwen',\n 'unknown': 'unknown',\n 'windsurf': 'windsurf',\n 'zed': 'zed',\n};\n\n/**\n * ๐Ÿ“– Context enrichment is always best-effort. Failing to detect a terminal or\n * cwd must never break the event stream itself.\n */\nexport class ContextDetector {\n private readonly cache = new Map<number, CachedProcessContext>();\n\n private readonly cacheTtlMs: number;\n\n private readonly commandTimeoutMs: number;\n\n private readonly cwdResolver: (pid: number) => Promise<string | undefined>;\n\n private readonly execCommand: (\n command: string,\n args: readonly string[],\n options?: CommandExecutionOptions,\n ) => Promise<string>;\n\n private readonly now: () => number;\n\n public constructor(options: ContextDetectorOptions = {}) {\n this.cacheTtlMs = options.cacheTtlMs ?? 30_000;\n this.commandTimeoutMs = options.commandTimeoutMs ?? 500;\n this.cwdResolver =\n options.cwdResolver ?? ((pid) => this.resolveCwdWithPidCwd(pid));\n this.execCommand =\n options.execCommand ??\n ((command, args, commandOptions) =>\n this.defaultExecCommand(command, args, commandOptions));\n this.now = options.now ?? Date.now;\n }\n\n /**\n * Detects the terminal display name from environment variables.\n */\n public detectTerminal(env: NodeJS.ProcessEnv = {}): string {\n if (env.ITERM_SESSION_ID) {\n return 'iTerm2';\n }\n\n if (env.KITTY_WINDOW_ID) {\n return 'kitty';\n }\n\n if (env.WEZTERM_EXECUTABLE) {\n return 'WezTerm';\n }\n\n if (env.TERM_PROGRAM) {\n return TERM_PROGRAM_MAP[env.TERM_PROGRAM] ?? env.TERM_PROGRAM;\n }\n\n if (env.TERM === 'alacritty' || env.TERM?.includes('alacritty')) {\n return 'Alacritty';\n }\n\n if (env.TERM?.includes('ghostty')) {\n return 'Ghostty';\n }\n\n if (env.TMUX) {\n return 'tmux';\n }\n\n return 'unknown';\n }\n\n /**\n * Walks the parent-process chain looking for a known terminal emulator.\n */\n public async getTerminalFromPPIDChain(pid: number): Promise<string> {\n let currentPid = pid;\n\n for (let depth = 0; depth < 4 && currentPid > 0; depth += 1) {\n try {\n const stdout = await this.execCommand(\n 'ps',\n ['-p', String(currentPid), '-o', 'ppid=,comm='],\n { timeoutMs: this.commandTimeoutMs },\n );\n const line = stdout.trim();\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return 'unknown';\n }\n\n const parentPidToken = match[1];\n const commandText = match[2];\n\n if (!parentPidToken || !commandText) {\n return 'unknown';\n }\n\n const nextPid = Number.parseInt(parentPidToken, 10);\n const normalizedProcessName = basename(commandText).replace(/\\.app$/u, '');\n const mappedTerminal =\n PROCESS_NAME_MAP[normalizedProcessName] ??\n PROCESS_NAME_MAP[commandText.trim()];\n\n if (mappedTerminal) {\n return mappedTerminal;\n }\n\n currentPid = nextPid;\n } catch (error: unknown) {\n logger.debug({ error, pid }, 'Terminal PPID chain lookup failed');\n return 'unknown';\n }\n }\n\n return 'unknown';\n }\n\n /**\n * Resolves the working directory for a running process with a fast timeout.\n */\n public async getCWDForPID(pid: number): Promise<string | undefined> {\n try {\n return await this.withTimeout(this.cwdResolver(pid));\n } catch (error: unknown) {\n logger.warn({ error, pid }, 'Primary PID cwd lookup failed');\n }\n\n if (process.platform !== 'darwin') {\n return undefined;\n }\n\n try {\n const stdout = await this.execCommand(\n 'lsof',\n ['-a', '-p', String(pid), '-d', 'cwd', '-Fn'],\n { timeoutMs: this.commandTimeoutMs },\n );\n const cwdLine = stdout\n .split('\\n')\n .find((line) => line.startsWith('n') && line.length > 1);\n\n return cwdLine?.slice(1) || undefined;\n } catch (error: unknown) {\n logger.warn({ error, pid }, 'Fallback PID cwd lookup failed');\n return undefined;\n }\n }\n\n /**\n * Decodes a Claude transcript path into its original project cwd when possible.\n */\n public decodeCWDFromTranscriptPath(\n transcriptPath: string,\n ): string | undefined {\n const match = transcriptPath.match(/\\.claude\\/projects\\/([^/]+)\\//u);\n\n if (!match?.[1] || !match[1].startsWith('-')) {\n return undefined;\n }\n\n return match[1].replace(/-/gu, '/');\n }\n\n /**\n * Enumerates active instances for a given tool binary using `pgrep`.\n */\n public async enumerateInstances(toolBinary: string): Promise<ProcessInfo[]> {\n if (process.platform === 'win32' || toolBinary === 'unknown') {\n return [];\n }\n\n try {\n const stdout = await this.execCommand(\n 'pgrep',\n ['-fl', toolBinary],\n { timeoutMs: this.commandTimeoutMs },\n );\n const lines = stdout\n .trim()\n .split('\\n')\n .filter((line) => line.trim().length > 0);\n\n const processRows: ProcessInfo[] = [];\n\n for (const line of lines) {\n const [pidToken] = line.trim().split(/\\s+/u, 1);\n const parsedPid = Number.parseInt(pidToken ?? '', 10);\n\n if (!Number.isFinite(parsedPid)) {\n continue;\n }\n\n processRows.push({\n pid: parsedPid,\n cwd: await this.getCWDForPID(parsedPid),\n });\n }\n\n return processRows.sort((left, right) => left.pid - right.pid);\n } catch (error: unknown) {\n logger.debug({ error, toolBinary }, 'Instance enumeration failed');\n return [];\n }\n }\n\n /**\n * Returns the 1-based position of the PID among active tool instances.\n */\n public async getInstanceIndex(\n pid: number,\n toolBinary: string,\n ): Promise<{ readonly index: number; readonly total: number }> {\n const instances = await this.enumerateInstances(toolBinary);\n const index = instances.findIndex((instance) => instance.pid === pid);\n\n return {\n index: index >= 0 ? index + 1 : 1,\n total: Math.max(instances.length, 1),\n };\n }\n\n /**\n * Builds a stable identifier for one tool instance.\n */\n public buildInstanceId(\n toolName: ToolName,\n pid: number,\n sessionId?: string,\n ): string {\n return `${toolName}:${sessionId ?? pid}`;\n }\n\n /**\n * Enriches an AISnitch event with best-effort runtime context.\n */\n public async enrich(\n event: AISnitchEvent,\n context: ProcessContext = {},\n ): Promise<AISnitchEvent> {\n const pid = context.pid ?? event.data.pid;\n const toolName = event['aisnitch.tool'];\n const toolBinary = TOOL_BINARY_MAP[toolName];\n const hookPayloadCwd = this.getHookPayloadCwd(context.hookPayload);\n const explicitTerminal =\n event.data.terminal ??\n (context.env ? this.detectTerminal(context.env) : 'unknown');\n const explicitCwd =\n event.data.cwd ??\n hookPayloadCwd ??\n (context.transcriptPath\n ? this.decodeCWDFromTranscriptPath(context.transcriptPath)\n : undefined);\n\n if (!pid || pid <= 0) {\n return {\n ...event,\n data: {\n ...event.data,\n terminal:\n explicitTerminal !== 'unknown' ? explicitTerminal : event.data.terminal,\n cwd: explicitCwd ?? event.data.cwd,\n instanceId: context.sessionId\n ? this.buildInstanceId(toolName, 0, context.sessionId)\n : event.data.instanceId,\n },\n };\n }\n\n const cachedContext = this.getCachedContext(pid);\n const detectedContext =\n cachedContext ?? (await this.detectContext(pid, toolBinary, explicitTerminal));\n\n if (!cachedContext) {\n this.cache.set(pid, {\n ...detectedContext,\n expiresAt: this.now() + this.cacheTtlMs,\n });\n }\n\n const instanceId = this.buildInstanceId(\n toolName,\n pid,\n context.sessionId ?? event['aisnitch.sessionid'],\n );\n\n return {\n ...event,\n data: {\n ...event.data,\n terminal:\n explicitTerminal !== 'unknown'\n ? explicitTerminal\n : detectedContext.terminal ?? event.data.terminal,\n cwd:\n explicitCwd ??\n detectedContext.cwd ??\n event.data.cwd,\n pid,\n instanceId,\n instanceIndex:\n event.data.instanceIndex ?? detectedContext.instanceIndex,\n instanceTotal:\n event.data.instanceTotal ?? detectedContext.instanceTotal,\n },\n };\n }\n\n private async detectContext(\n pid: number,\n toolBinary: string,\n explicitTerminal: string,\n ): Promise<Omit<CachedProcessContext, 'expiresAt'>> {\n const cwdPromise = this.getCWDForPID(pid);\n const instancePromise = this.getInstanceIndex(pid, toolBinary);\n const terminalPromise =\n explicitTerminal !== 'unknown'\n ? Promise.resolve(explicitTerminal)\n : this.getTerminalFromPPIDChain(pid);\n\n const [cwd, instanceInfo, terminal] = await Promise.all([\n cwdPromise.catch(() => undefined),\n instancePromise.catch(() => ({ index: 1, total: 1 })),\n terminalPromise.catch(() => 'unknown'),\n ]);\n\n return {\n cwd,\n terminal: terminal !== 'unknown' ? terminal : undefined,\n instanceIndex: instanceInfo.index,\n instanceTotal: instanceInfo.total,\n };\n }\n\n private getCachedContext(pid: number): Omit<CachedProcessContext, 'expiresAt'> | undefined {\n const cachedContext = this.cache.get(pid);\n\n if (!cachedContext) {\n return undefined;\n }\n\n if (cachedContext.expiresAt <= this.now()) {\n this.cache.delete(pid);\n return undefined;\n }\n\n const { expiresAt: _expiresAt, ...context } = cachedContext;\n return context;\n }\n\n private getHookPayloadCwd(\n hookPayload: Record<string, unknown> | undefined,\n ): string | undefined {\n if (!hookPayload) {\n return undefined;\n }\n\n const rawCwd = hookPayload.cwd;\n\n return typeof rawCwd === 'string' && rawCwd.length > 0 ? rawCwd : undefined;\n }\n\n private async resolveCwdWithPidCwd(pid: number): Promise<string | undefined> {\n const cwd = (await pidCwd(pid)) as string | null | undefined;\n\n return cwd ?? undefined;\n }\n\n private async defaultExecCommand(\n command: string,\n args: readonly string[],\n options: CommandExecutionOptions = {},\n ): Promise<string> {\n const result = await execFile(command, [...args], {\n encoding: 'utf8',\n timeout: options.timeoutMs ?? this.commandTimeoutMs,\n maxBuffer: 1024 * 1024,\n });\n\n return result.stdout;\n }\n\n private async withTimeout<T>(promise: Promise<T>): Promise<T> {\n return await Promise.race([\n promise,\n new Promise<never>((_resolve, reject) => {\n setTimeout(() => {\n reject(new Error('Context detection timed out.'));\n }, this.commandTimeoutMs).unref();\n }),\n ]);\n }\n}\n","/**\n * @file src/adapters/index.ts\n * @description Barrel exports for the built-in AISnitch adapter system and factory.\n * @functions\n * โ†’ createDefaultAdapters\n * @exports all adapter primitives plus createDefaultAdapters\n * @see ./base.ts\n * @see ./registry.ts\n * @see ./aider.ts\n * @see ./claude-code.ts\n * @see ./copilot-cli.ts\n * @see ./cursor.ts\n * @see ./devin.ts\n * @see ./gemini-cli.ts\n * @see ./generic-pty.ts\n * @see ./goose.ts\n * @see ./kilo.ts\n * @see ./codex.ts\n * @see ./openclaw.ts\n * @see ./opencode.ts\n * @see ./pi.ts\n * @see ./zed.ts\n */\n\nimport type { AdapterRuntimeOptions } from './base.js';\nimport { AiderAdapter } from './aider.js';\nimport { ClaudeCodeAdapter } from './claude-code.js';\nimport { CopilotCLIAdapter } from './copilot-cli.js';\nimport { CodexAdapter } from './codex.js';\nimport { CursorAdapter } from './cursor.js';\nimport { DevinAdapter } from './devin.js';\nimport { GeminiCLIAdapter } from './gemini-cli.js';\nimport { GooseAdapter } from './goose.js';\nimport { KiloAdapter } from './kilo.js';\nimport { OpenClawAdapter } from './openclaw.js';\nimport { OpenCodeAdapter } from './opencode.js';\nimport { PiAdapter } from './pi.js';\nimport { ZedAdapter } from './zed.js';\n\nexport * from './base.js';\nexport * from './registry.js';\nexport * from './aider.js';\nexport * from './claude-code.js';\nexport * from './copilot-cli.js';\nexport * from './codex.js';\nexport * from './cursor.js';\nexport * from './devin.js';\nexport * from './gemini-cli.js';\nexport * from './generic-pty.js';\nexport * from './goose.js';\nexport * from './kilo.js';\nexport * from './openclaw.js';\nexport * from './opencode.js';\nexport * from './pi.js';\nexport * from './zed.js';\n\n/**\n * Instantiates the built-in adapters that ship with AISnitch.\n */\nexport function createDefaultAdapters(options: AdapterRuntimeOptions) {\n return [\n new AiderAdapter(options),\n new ClaudeCodeAdapter(options),\n new CopilotCLIAdapter(options),\n new CursorAdapter(options),\n new DevinAdapter(options),\n new GeminiCLIAdapter(options),\n new GooseAdapter(options),\n new KiloAdapter(options),\n new CodexAdapter(options),\n new OpenClawAdapter(options),\n new OpenCodeAdapter(options),\n new PiAdapter(options),\n new ZedAdapter(options),\n ] as const;\n}\n","import type { infer as ZodInfer } from 'zod';\nimport { z } from 'zod';\n\nimport { ToolNameSchema } from '../events/schema.js';\n\n/**\n * @file src/core/config/schema.ts\n * @description Zod schemas and inferred types for the persistent AISnitch configuration file.\n * @functions\n * โ†’ none\n * @exports LOG_LEVELS, AdapterConfigSchema, ConfigSchema, AISnitchConfig, AdapterConfig\n * @see ./loader.ts\n */\n\n/**\n * Supported log levels for the daemon runtime.\n */\nexport const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\nexport const AUTO_UPDATE_MANAGERS = ['auto', 'npm', 'pnpm', 'bun', 'brew'] as const;\n\n/**\n * Per-adapter toggle stored inside the config file.\n */\nexport const AdapterConfigSchema = z.strictObject({\n enabled: z.boolean().default(true),\n});\n\n/**\n * Silent self-update behavior for globally installed AISnitch binaries.\n */\nexport const AutoUpdateConfigSchema = z.strictObject({\n enabled: z.boolean().default(true),\n intervalMs: z.number().int().min(0).default(0),\n manager: z.enum(AUTO_UPDATE_MANAGERS).default('auto'),\n});\n\n/**\n * Runtime schema for the full persisted configuration contract.\n */\nexport const ConfigSchema = z.strictObject({\n wsPort: z.number().int().min(1024).max(65535).default(4820),\n httpPort: z.number().int().min(1024).max(65535).default(4821),\n /**\n * ๐Ÿ“– This is intentionally a partial record because most users will only\n * override a couple of adapters instead of all supported tools at once.\n */\n adapters: z.partialRecord(ToolNameSchema, AdapterConfigSchema).default({}),\n autoUpdate: AutoUpdateConfigSchema.default({\n enabled: true,\n intervalMs: 0,\n manager: 'auto',\n }),\n idleTimeoutMs: z.number().int().min(10_000).default(120_000),\n logLevel: z.enum(LOG_LEVELS).default('info'),\n});\n\n/**\n * Inferred TypeScript view of a single adapter config entry.\n */\nexport type AdapterConfig = ZodInfer<typeof AdapterConfigSchema>;\nexport type AutoUpdateConfig = ZodInfer<typeof AutoUpdateConfigSchema>;\n\n/**\n * Inferred TypeScript view of the persisted AISnitch config.\n */\nexport type AISnitchConfig = ZodInfer<typeof ConfigSchema>;\n","import type { AISnitchConfig } from './schema.js';\n\n/**\n * @file src/core/config/defaults.ts\n * @description Central default values for the AISnitch runtime configuration.\n * @functions\n * โ†’ none\n * @exports DEFAULT_CONFIG\n * @see ./schema.ts\n */\n\n/**\n * ๐Ÿ“– Keeping defaults in plain data makes them reusable for docs, tests,\n * config bootstrapping, and eventual `aisnitch config` CLI commands.\n */\nexport const DEFAULT_CONFIG: AISnitchConfig = {\n wsPort: 4820,\n httpPort: 4821,\n adapters: {},\n autoUpdate: {\n enabled: true,\n intervalMs: 0,\n manager: 'auto',\n },\n idleTimeoutMs: 120_000,\n logLevel: 'info',\n};\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { DEFAULT_CONFIG } from './defaults.js';\nimport { ConfigSchema } from './schema.js';\nimport type { AISnitchConfig } from './schema.js';\n\n/**\n * @file src/core/config/loader.ts\n * @description File-system backed helpers for reading, writing, and resolving AISnitch config paths and ports.\n * @functions\n * โ†’ getAISnitchHomePath\n * โ†’ getConfigPath\n * โ†’ ensureConfigDir\n * โ†’ loadConfig\n * โ†’ saveConfig\n * โ†’ resolveAvailablePort\n * @exports ConfigPathOptions, PortResolutionOptions, getAISnitchHomePath, getConfigPath, ensureConfigDir, loadConfig, saveConfig, resolveAvailablePort\n * @see ./schema.ts\n * @see ./defaults.ts\n */\n\n/**\n * Common options for redirecting config path resolution during tests.\n */\nexport interface ConfigPathOptions {\n readonly env?: NodeJS.ProcessEnv;\n readonly homeDirectory?: string;\n readonly configPath?: string;\n}\n\n/**\n * Options for port selection and lightweight logging during bootstrap.\n */\nexport interface PortResolutionOptions {\n readonly host?: string;\n readonly maxAttempts?: number;\n readonly logger?: (message: string) => void;\n}\n\n/**\n * Returns the root directory used by AISnitch to store config and daemon state.\n */\nexport function getAISnitchHomePath(options: ConfigPathOptions = {}): string {\n if (options.configPath && options.configPath.trim().length > 0) {\n return dirname(resolve(options.configPath));\n }\n\n const configuredHome = options.env?.AISNITCH_HOME;\n\n if (configuredHome && configuredHome.trim().length > 0) {\n return resolve(configuredHome);\n }\n\n return join(options.homeDirectory ?? homedir(), '.aisnitch');\n}\n\n/**\n * Resolves the absolute path of `config.json`, honoring `AISNITCH_HOME`.\n */\nexport function getConfigPath(options: ConfigPathOptions = {}): string {\n if (options.configPath && options.configPath.trim().length > 0) {\n return resolve(options.configPath);\n }\n\n return join(getAISnitchHomePath(options), 'config.json');\n}\n\n/**\n * Ensures the AISnitch home directory exists before reading or writing config.\n */\nexport async function ensureConfigDir(\n options: ConfigPathOptions = {},\n): Promise<string> {\n const directoryPath = getAISnitchHomePath(options);\n\n await mkdir(directoryPath, { recursive: true });\n\n return directoryPath;\n}\n\n/**\n * Loads, validates, and default-fills the AISnitch config from disk.\n */\nexport async function loadConfig(\n options: ConfigPathOptions = {},\n): Promise<AISnitchConfig> {\n const configPath = getConfigPath(options);\n\n try {\n const rawConfig = await readFile(configPath, 'utf8');\n const parsedJson: unknown = JSON.parse(rawConfig);\n\n return ConfigSchema.parse(parsedJson);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return ConfigSchema.parse(DEFAULT_CONFIG);\n }\n\n if (error instanceof SyntaxError) {\n throw new Error(`Invalid JSON in AISnitch config at ${configPath}`, {\n cause: error,\n });\n }\n\n throw error;\n }\n}\n\n/**\n * Writes a validated AISnitch config back to disk using stable pretty JSON.\n */\nexport async function saveConfig(\n config: AISnitchConfig,\n options: ConfigPathOptions = {},\n): Promise<string> {\n const validatedConfig = ConfigSchema.parse(config);\n const configPath = getConfigPath(options);\n\n await ensureConfigDir(options);\n await writeFile(\n configPath,\n `${JSON.stringify(validatedConfig, null, 2)}\\n`,\n 'utf8',\n );\n\n return configPath;\n}\n\nasync function canBindPort(port: number, host: string): Promise<boolean> {\n return await new Promise<boolean>((resolveAvailability, reject) => {\n const server = createServer();\n\n server.once('error', (error: NodeJS.ErrnoException) => {\n server.close();\n\n if (error.code === 'EADDRINUSE') {\n resolveAvailability(false);\n return;\n }\n\n reject(error);\n });\n\n server.once('listening', () => {\n server.close((closeError) => {\n if (closeError) {\n reject(closeError);\n return;\n }\n\n resolveAvailability(true);\n });\n });\n\n server.listen(port, host);\n });\n}\n\n/**\n * Resolves a usable port by trying the requested port first and then the next\n * sequential ports up to a bounded retry count.\n */\nexport async function resolveAvailablePort(\n requestedPort: number,\n options: PortResolutionOptions = {},\n): Promise<number> {\n const host = options.host ?? '127.0.0.1';\n /**\n * ๐Ÿ“– AISnitch can spawn foreground demos, ephemeral wrap pipelines, and a\n * managed daemon on the same machine. Keeping the default search window too\n * narrow makes one stale process enough to brick startup, so we probe a\n * wider local range before giving up.\n */\n const maxAttempts = options.maxAttempts ?? 100;\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n const candidatePort = requestedPort + attempt;\n const available = await canBindPort(candidatePort, host);\n\n if (!available) {\n continue;\n }\n\n if (candidatePort === requestedPort) {\n options.logger?.(`AISnitch will use requested port ${candidatePort}.`);\n } else {\n options.logger?.(\n `AISnitch port ${requestedPort} is busy, using ${candidatePort} instead.`,\n );\n }\n\n return candidatePort;\n }\n\n throw new Error(\n `Unable to find an available port from ${requestedPort} to ${\n requestedPort + maxAttempts - 1\n }.`,\n );\n}\n","import { EventEmitter } from 'eventemitter3';\n\nimport { AISnitchEventSchema } from '../events/schema.js';\nimport type { AISnitchEvent, AISnitchEventType } from '../events/types.js';\nimport { logger } from './logger.js';\n\n/**\n * @file src/core/engine/event-bus.ts\n * @description Typed in-memory pub/sub bus used by the AISnitch runtime pipeline.\n * @functions\n * โ†’ none\n * @exports EventHandler, EventBusStats, EventBus\n * @see ./logger.ts\n * @see ../events/schema.ts\n */\n\n/**\n * Listener signature used by the EventBus.\n */\nexport type EventHandler = (event: AISnitchEvent) => void;\n\ntype EventBusChannels = {\n event: (event: AISnitchEvent) => void;\n} & {\n [K in AISnitchEventType as `event:${K}`]: (event: AISnitchEvent) => void;\n};\n\n/**\n * Metrics exposed by the in-memory event bus.\n */\nexport interface EventBusStats {\n readonly publishedEvents: number;\n readonly rejectedEvents: number;\n readonly subscriberCount: number;\n}\n\n/**\n * ๐Ÿ“– The EventBus is the single fan-out point inside the process. Adapters,\n * hook receivers, and IPC ingress all publish here before anything reaches WS.\n */\nexport class EventBus {\n private readonly emitter: EventEmitter<EventBusChannels> =\n new EventEmitter<EventBusChannels>();\n\n private readonly globalHandlers = new Set<EventHandler>();\n\n private readonly typedHandlers = new Map<AISnitchEventType, Set<EventHandler>>();\n\n private publishedEvents = 0;\n\n private rejectedEvents = 0;\n\n /**\n * Validates and publishes an event to all generic and type-specific listeners.\n */\n publish(event: unknown): event is AISnitchEvent {\n const parsedEvent = AISnitchEventSchema.safeParse(event);\n\n if (!parsedEvent.success) {\n this.rejectedEvents += 1;\n logger.warn(\n {\n issues: parsedEvent.error.issues,\n },\n 'Rejected invalid event',\n );\n return false;\n }\n\n this.publishedEvents += 1;\n\n logger.debug(\n {\n eventId: parsedEvent.data.id,\n instanceId: parsedEvent.data.data.instanceId,\n sessionId: parsedEvent.data['aisnitch.sessionid'],\n eventType: parsedEvent.data.type,\n tool: parsedEvent.data['aisnitch.tool'],\n },\n 'Published event',\n );\n\n // ๐Ÿ“– Wrap emits in try/catch โ€” one buggy subscriber must never crash the bus\n try {\n this.emitter.emit('event', parsedEvent.data);\n } catch (error: unknown) {\n logger.warn({ error, eventType: parsedEvent.data.type }, '๐Ÿ“– Error in EventBus global subscriber');\n }\n\n try {\n this.emitter.emit(`event:${parsedEvent.data.type}`, parsedEvent.data);\n } catch (error: unknown) {\n logger.warn({ error, eventType: parsedEvent.data.type }, '๐Ÿ“– Error in EventBus typed subscriber');\n }\n\n return true;\n }\n\n /**\n * Subscribes to all valid events emitted on the bus.\n */\n subscribe(handler: EventHandler): () => void {\n this.globalHandlers.add(handler);\n this.emitter.on('event', handler);\n\n return () => {\n this.unsubscribe(handler);\n };\n }\n\n /**\n * Subscribes to only one normalized event type.\n */\n subscribeType(type: AISnitchEventType, handler: EventHandler): () => void {\n const channel = `event:${type}` as const;\n const handlersForType = this.typedHandlers.get(type) ?? new Set<EventHandler>();\n\n handlersForType.add(handler);\n this.typedHandlers.set(type, handlersForType);\n this.emitter.on(channel, handler);\n\n return () => {\n this.unsubscribeType(type, handler);\n };\n }\n\n /**\n * Removes a previously subscribed catch-all handler.\n */\n unsubscribe(handler: EventHandler): void {\n this.globalHandlers.delete(handler);\n this.emitter.off('event', handler);\n }\n\n /**\n * Removes all listeners and clears internal handler tracking.\n */\n unsubscribeAll(): void {\n this.globalHandlers.clear();\n this.typedHandlers.clear();\n this.emitter.removeAllListeners();\n }\n\n /**\n * Returns current in-memory bus statistics.\n */\n getStats(): EventBusStats {\n const typedSubscriberCount = [...this.typedHandlers.values()].reduce(\n (count, handlers) => count + handlers.size,\n 0,\n );\n\n return {\n publishedEvents: this.publishedEvents,\n rejectedEvents: this.rejectedEvents,\n subscriberCount: this.globalHandlers.size + typedSubscriberCount,\n };\n }\n\n private unsubscribeType(type: AISnitchEventType, handler: EventHandler): void {\n const channel = `event:${type}` as const;\n const handlersForType = this.typedHandlers.get(type);\n\n if (!handlersForType) {\n return;\n }\n\n handlersForType.delete(handler);\n\n if (handlersForType.size === 0) {\n this.typedHandlers.delete(type);\n }\n\n this.emitter.off(channel, handler);\n }\n}\n","/**\n * @file src/core/engine/ring-buffer.ts\n * @description Fixed-size oldest-first ring buffer used to absorb temporary consumer backpressure.\n * @functions\n * โ†’ none\n * @exports RingBuffer\n */\n\n/**\n * ๐Ÿ“– This buffer intentionally drops the oldest item when full. For a live\n * stream UI that is exactly the right tradeoff: newest activity beats stale UI.\n */\nexport class RingBuffer<T> {\n private readonly items: Array<T | undefined>;\n\n private head = 0;\n\n private count = 0;\n\n public constructor(private readonly maxCapacity: number) {\n if (!Number.isInteger(maxCapacity) || maxCapacity <= 0) {\n throw new Error('RingBuffer capacity must be a positive integer.');\n }\n\n this.items = new Array<T | undefined>(maxCapacity);\n }\n\n /**\n * Pushes one item into the buffer and returns the dropped oldest item if full.\n */\n push(item: T): T | undefined {\n if (this.count < this.maxCapacity) {\n const insertIndex = (this.head + this.count) % this.maxCapacity;\n this.items[insertIndex] = item;\n this.count += 1;\n return undefined;\n }\n\n const droppedItem = this.items[this.head];\n\n this.items[this.head] = item;\n this.head = (this.head + 1) % this.maxCapacity;\n\n return droppedItem;\n }\n\n /**\n * Removes and returns the oldest item in the buffer.\n */\n shift(): T | undefined {\n if (this.count === 0) {\n return undefined;\n }\n\n const item = this.items[this.head];\n\n this.items[this.head] = undefined;\n this.head = (this.head + 1) % this.maxCapacity;\n this.count -= 1;\n\n return item;\n }\n\n /**\n * Drains and returns all items in oldest-first order.\n */\n drain(): T[] {\n const drainedItems: T[] = [];\n\n while (this.count > 0) {\n const item = this.shift();\n\n if (item !== undefined) {\n drainedItems.push(item);\n }\n }\n\n return drainedItems;\n }\n\n /**\n * Clears the buffer contents.\n */\n clear(): void {\n this.items.fill(undefined);\n this.head = 0;\n this.count = 0;\n }\n\n public get capacity(): number {\n return this.maxCapacity;\n }\n\n public get size(): number {\n return this.count;\n }\n\n public get isFull(): boolean {\n return this.count === this.maxCapacity;\n }\n}\n","import { once } from 'node:events';\nimport type { AddressInfo } from 'node:net';\n\nimport { WebSocket, WebSocketServer } from 'ws';\n\nimport { AISNITCH_VERSION } from '../../package-info.js';\nimport type { AISnitchEvent, ToolName } from '../events/types.js';\nimport type { EventBus } from './event-bus.js';\nimport { logger } from './logger.js';\nimport { RingBuffer } from './ring-buffer.js';\n\n/**\n * @file src/core/engine/ws-server.ts\n * @description Localhost-only WebSocket event stream server with per-consumer buffering and heartbeat handling.\n * @functions\n * โ†’ none\n * @exports WelcomeMessage, WSServerStartOptions, WSServerStats, WSServer\n * @see ./ring-buffer.ts\n * @see ./event-bus.ts\n */\n\n/**\n * Message sent immediately after a new consumer connects.\n */\nexport interface WelcomeMessage {\n readonly type: 'welcome';\n readonly version: string;\n readonly tools: readonly ToolName[];\n}\n\n/**\n * Startup configuration for the WebSocket server.\n */\nexport interface WSServerStartOptions {\n readonly port: number;\n readonly eventBus: EventBus;\n readonly activeTools?: readonly ToolName[];\n readonly host?: string;\n readonly bufferCapacity?: number;\n readonly backpressureThresholdBytes?: number;\n readonly heartbeatIntervalMs?: number;\n readonly pongTimeoutMs?: number;\n}\n\n/**\n * Observable runtime stats for the WebSocket server.\n */\nexport interface WSServerStats {\n readonly listening: boolean;\n readonly host: string;\n readonly port: number | null;\n readonly consumerCount: number;\n readonly eventsSent: number;\n readonly droppedEvents: number;\n}\n\ninterface ConsumerState {\n readonly buffer: RingBuffer<string>;\n lastPingAt: number;\n awaitingPongSince: number | null;\n}\n\n/**\n * ๐Ÿ“– Every consumer gets its own ring buffer so one slow UI cannot block the\n * others or force the daemon to keep unbounded queued output in memory.\n */\nexport class WSServer {\n private wss: WebSocketServer | undefined;\n\n private host = '127.0.0.1';\n\n private port: number | null = null;\n\n private readonly consumers = new Map<WebSocket, ConsumerState>();\n\n private unsubscribeFromBus: (() => void) | undefined;\n\n private maintenanceTimer: NodeJS.Timeout | undefined;\n\n private eventsSent = 0;\n\n private droppedEvents = 0;\n\n /**\n * Starts the localhost WebSocket server and subscribes it to the event bus.\n */\n public async start(options: WSServerStartOptions): Promise<number> {\n if (this.wss) {\n return this.port ?? options.port;\n }\n\n this.host = options.host ?? '127.0.0.1';\n\n const bufferCapacity = options.bufferCapacity ?? 1_000;\n const backpressureThresholdBytes =\n options.backpressureThresholdBytes ?? 64 * 1024;\n const heartbeatIntervalMs = options.heartbeatIntervalMs ?? 30_000;\n const pongTimeoutMs = options.pongTimeoutMs ?? 10_000;\n const activeTools = options.activeTools ?? [];\n\n this.wss = new WebSocketServer({\n host: this.host,\n port: options.port,\n });\n\n this.wss.on('connection', (socket) => {\n this.handleConnection(\n socket,\n {\n activeTools,\n bufferCapacity,\n backpressureThresholdBytes,\n },\n );\n });\n\n this.wss.on('error', (error) => {\n logger.error({ error }, 'WebSocket server error');\n });\n\n await once(this.wss, 'listening');\n\n const address = this.wss.address();\n\n if (!address || typeof address === 'string') {\n throw new Error('Unable to resolve WebSocket server address.');\n }\n\n this.port = (address as AddressInfo).port;\n\n this.unsubscribeFromBus = options.eventBus.subscribe((event) => {\n this.broadcastEvent(event, backpressureThresholdBytes);\n });\n\n this.maintenanceTimer = setInterval(() => {\n this.runMaintenance(backpressureThresholdBytes, heartbeatIntervalMs, pongTimeoutMs);\n }, 1_000);\n this.maintenanceTimer.unref();\n\n logger.info(\n {\n host: this.host,\n port: this.port,\n },\n 'WebSocket server started',\n );\n\n return this.port;\n }\n\n /**\n * Stops the server and closes all consumer connections.\n */\n public async stop(): Promise<void> {\n this.unsubscribeFromBus?.();\n this.unsubscribeFromBus = undefined;\n\n if (this.maintenanceTimer) {\n clearInterval(this.maintenanceTimer);\n this.maintenanceTimer = undefined;\n }\n\n for (const socket of this.consumers.keys()) {\n socket.terminate();\n }\n this.consumers.clear();\n\n if (!this.wss) {\n this.port = null;\n return;\n }\n\n const wss = this.wss;\n this.wss = undefined;\n\n await new Promise<void>((resolve, reject) => {\n wss.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n\n this.port = null;\n\n logger.info('WebSocket server stopped');\n }\n\n /**\n * Returns live server metrics used by health and status reporting.\n */\n public getStats(): WSServerStats {\n return {\n listening: this.wss !== undefined,\n host: this.host,\n port: this.port,\n consumerCount: this.consumers.size,\n eventsSent: this.eventsSent,\n droppedEvents: this.droppedEvents,\n };\n }\n\n private handleConnection(\n socket: WebSocket,\n options: {\n readonly activeTools: readonly ToolName[];\n readonly bufferCapacity: number;\n readonly backpressureThresholdBytes: number;\n },\n ): void {\n const state: ConsumerState = {\n buffer: new RingBuffer<string>(options.bufferCapacity),\n lastPingAt: Date.now(),\n awaitingPongSince: null,\n };\n\n this.consumers.set(socket, state);\n\n socket.on('pong', () => {\n state.awaitingPongSince = null;\n this.flushConsumer(socket, state, options.backpressureThresholdBytes);\n });\n\n socket.on('close', () => {\n this.consumers.delete(socket);\n });\n\n socket.on('error', (error) => {\n logger.warn({ error }, 'WebSocket consumer error');\n // ๐Ÿ“– Remove the consumer from the map so dead sockets don't accumulate\n this.consumers.delete(socket);\n });\n\n const welcomeMessage: WelcomeMessage = {\n type: 'welcome',\n version: AISNITCH_VERSION,\n tools: options.activeTools,\n };\n\n this.trySendOrQueue(\n socket,\n state,\n JSON.stringify(welcomeMessage),\n options.backpressureThresholdBytes,\n );\n }\n\n private broadcastEvent(\n event: AISnitchEvent,\n backpressureThresholdBytes: number,\n ): void {\n const serializedEvent = JSON.stringify(event);\n\n for (const [socket, state] of this.consumers) {\n this.trySendOrQueue(\n socket,\n state,\n serializedEvent,\n backpressureThresholdBytes,\n );\n }\n }\n\n private trySendOrQueue(\n socket: WebSocket,\n state: ConsumerState,\n serializedPayload: string,\n backpressureThresholdBytes: number,\n ): void {\n if (socket.readyState !== WebSocket.OPEN) {\n return;\n }\n\n if (state.buffer.size === 0 && socket.bufferedAmount < backpressureThresholdBytes) {\n socket.send(serializedPayload, (error) => {\n if (error) {\n logger.warn({ error }, 'Failed to send WebSocket payload');\n }\n });\n this.eventsSent += 1;\n return;\n }\n\n const droppedPayload = state.buffer.push(serializedPayload);\n\n if (droppedPayload !== undefined) {\n this.droppedEvents += 1;\n }\n }\n\n private flushConsumer(\n socket: WebSocket,\n state: ConsumerState,\n backpressureThresholdBytes: number,\n ): void {\n while (\n socket.readyState === WebSocket.OPEN &&\n state.buffer.size > 0 &&\n socket.bufferedAmount < backpressureThresholdBytes\n ) {\n const nextPayload = state.buffer.shift();\n\n if (nextPayload === undefined) {\n break;\n }\n\n socket.send(nextPayload, (error) => {\n if (error) {\n logger.warn({ error }, 'Failed to flush buffered WebSocket payload');\n }\n });\n\n this.eventsSent += 1;\n }\n }\n\n private runMaintenance(\n backpressureThresholdBytes: number,\n heartbeatIntervalMs: number,\n pongTimeoutMs: number,\n ): void {\n const now = Date.now();\n\n for (const [socket, state] of this.consumers) {\n this.flushConsumer(socket, state, backpressureThresholdBytes);\n\n if (state.awaitingPongSince !== null) {\n if (now - state.awaitingPongSince > pongTimeoutMs) {\n socket.terminate();\n }\n continue;\n }\n\n if (now - state.lastPingAt >= heartbeatIntervalMs) {\n state.lastPingAt = now;\n state.awaitingPongSince = now;\n\n if (socket.readyState === WebSocket.OPEN) {\n socket.ping();\n }\n }\n }\n }\n}\n","/**\n * @file src/package-info.ts\n * @description Shared package metadata constants consumed by the public index, CLI, and TUI without creating import cycles.\n * @functions\n * โ†’ getPackageScaffoldInfo\n * @exports AISNITCH_PACKAGE_NAME, AISNITCH_VERSION, AISNITCH_DESCRIPTION, AISnitchScaffoldInfo, getPackageScaffoldInfo\n * @see ./index.ts\n * @see ./cli/program.ts\n * @see ./tui/index.tsx\n */\n\n/**\n * ๐Ÿ“– This constant keeps the published package identity in one place so the\n * CLI and TUI can reuse a single source of truth without reaching through the\n * package root export barrel.\n */\nexport const AISNITCH_PACKAGE_NAME = 'aisnitch';\n\n/**\n * ๐Ÿ“– Injected at build time by tsup (and at test time by vitest) from package.json\n * via the __AISNITCH_VERSION__ define constant โ€” never edit this manually.\n * Bumping package.json is the only step required to update the displayed version.\n */\ndeclare const __AISNITCH_VERSION__: string;\nexport const AISNITCH_VERSION: string = __AISNITCH_VERSION__;\n\n/**\n * ๐Ÿ“– The shared description stays close to the package identity so commander\n * help output and future docs surfaces stay aligned.\n */\nexport const AISNITCH_DESCRIPTION =\n 'Universal bridge for AI coding tool activity โ€” capture, normalize, stream.';\n\n/**\n * Represents the stable scaffold metadata exposed by the package root.\n */\nexport interface AISnitchScaffoldInfo {\n readonly name: string;\n readonly version: string;\n readonly description: string;\n readonly supportedNodeRange: string;\n}\n\n/**\n * Builds a small metadata snapshot that other modules can consume without\n * reading package.json at runtime.\n */\nexport function getPackageScaffoldInfo(): AISnitchScaffoldInfo {\n return {\n name: AISNITCH_PACKAGE_NAME,\n version: AISNITCH_VERSION,\n description: AISNITCH_DESCRIPTION,\n supportedNodeRange: '>=20.0.0',\n };\n}\n","import { once } from 'node:events';\nimport {\n createServer,\n type IncomingMessage,\n type Server,\n type ServerResponse,\n} from 'node:http';\n\nimport { ToolNameSchema } from '../events/schema.js';\nimport type { ToolName } from '../events/types.js';\nimport { logger } from './logger.js';\n\n/**\n * @file src/core/engine/http-receiver.ts\n * @description Lightweight localhost-only HTTP receiver for tool hooks and daemon health checks.\n * @functions\n * โ†’ none\n * @exports HealthSnapshot, HTTPReceiverStartOptions, HTTPReceiverStats, HTTPReceiver\n * @see ./pipeline.ts\n */\n\n/**\n * Health payload returned by the HTTP receiver.\n */\nexport interface HealthSnapshot {\n readonly status: 'ok';\n readonly uptime: number;\n readonly consumers: number;\n readonly events: number;\n readonly droppedEvents: number;\n}\n\n/**\n * Startup configuration for the HTTP hook receiver.\n */\nexport interface HTTPReceiverStartOptions {\n readonly port: number;\n readonly host?: string;\n readonly onHook: (tool: ToolName, payload: unknown) => Promise<void> | void;\n readonly getHealthSnapshot: () => HealthSnapshot;\n}\n\n/**\n * Observable runtime stats for the HTTP receiver.\n */\nexport interface HTTPReceiverStats {\n readonly listening: boolean;\n readonly host: string;\n readonly port: number | null;\n readonly requestCount: number;\n readonly invalidRequestCount: number;\n readonly acceptedHooks: number;\n}\n\n/**\n * ๐Ÿ“– The hook receiver keeps zero framework magic on purpose. One endpoint plus\n * one health route do not justify hauling a whole server framework into core.\n */\nexport class HTTPReceiver {\n private server: Server | undefined;\n\n private host = '127.0.0.1';\n\n private port: number | null = null;\n\n private requestCount = 0;\n\n private invalidRequestCount = 0;\n\n private acceptedHooks = 0;\n\n /**\n * Starts the HTTP receiver on localhost and exposes hook and health routes.\n */\n public async start(options: HTTPReceiverStartOptions): Promise<number> {\n if (this.server) {\n return this.port ?? options.port;\n }\n\n this.host = options.host ?? '127.0.0.1';\n\n this.server = createServer((request, response) => {\n void this.handleRequest(request, response, options);\n });\n\n this.server.on('error', (error) => {\n logger.error({ error }, 'HTTP receiver error');\n });\n\n this.server.listen(options.port, this.host);\n await once(this.server, 'listening');\n\n const address = this.server.address();\n\n if (!address || typeof address === 'string') {\n throw new Error('Unable to resolve HTTP receiver address.');\n }\n\n this.port = address.port;\n\n logger.info(\n {\n host: this.host,\n port: this.port,\n },\n 'HTTP receiver started',\n );\n\n return this.port;\n }\n\n /**\n * Stops the receiver and closes the listening socket.\n */\n public async stop(): Promise<void> {\n if (!this.server) {\n this.port = null;\n return;\n }\n\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n\n this.port = null;\n\n logger.info('HTTP receiver stopped');\n }\n\n /**\n * Returns live HTTP receiver stats for health/status endpoints.\n */\n public getStats(): HTTPReceiverStats {\n return {\n listening: this.server !== undefined,\n host: this.host,\n port: this.port,\n requestCount: this.requestCount,\n invalidRequestCount: this.invalidRequestCount,\n acceptedHooks: this.acceptedHooks,\n };\n }\n\n private async handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n options: HTTPReceiverStartOptions,\n ): Promise<void> {\n this.requestCount += 1;\n\n let requestUrl: URL;\n\n try {\n requestUrl = new URL(\n request.url ?? '/',\n `http://${this.host}:${this.port ?? options.port}`,\n );\n } catch {\n this.invalidRequestCount += 1;\n this.sendJson(response, 400, { error: 'malformed request url' });\n return;\n }\n\n if (request.method === 'GET' && requestUrl.pathname === '/health') {\n this.sendJson(response, 200, options.getHealthSnapshot());\n return;\n }\n\n if (request.method === 'POST' && requestUrl.pathname.startsWith('/hooks/')) {\n const toolSegment = decodeURIComponent(\n requestUrl.pathname.slice('/hooks/'.length),\n );\n const parsedTool = ToolNameSchema.safeParse(toolSegment);\n\n if (!parsedTool.success || parsedTool.data === 'unknown') {\n this.invalidRequestCount += 1;\n this.sendJson(response, 404, {\n error: 'unknown tool',\n });\n return;\n }\n\n let payload: unknown;\n\n try {\n payload = await this.readJsonBody(request);\n } catch (error: unknown) {\n this.invalidRequestCount += 1;\n this.sendJson(response, 400, {\n error: error instanceof Error ? error.message : 'invalid json body',\n });\n return;\n }\n\n this.acceptedHooks += 1;\n this.sendJson(response, 202, {\n status: 'accepted',\n });\n\n queueMicrotask(() => {\n void Promise.resolve(options.onHook(parsedTool.data, payload)).catch((error) => {\n logger.error(\n {\n error,\n tool: parsedTool.data,\n },\n 'Hook handler failed',\n );\n });\n });\n return;\n }\n\n this.invalidRequestCount += 1;\n this.sendJson(response, 404, {\n error: 'not found',\n });\n }\n\n private async readJsonBody(request: IncomingMessage): Promise<unknown> {\n let rawBody = '';\n let bodyLength = 0;\n\n for await (const chunk of request) {\n const chunkText =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk).toString('utf8');\n\n bodyLength += Buffer.byteLength(chunkText);\n\n if (bodyLength > 1_000_000) {\n throw new Error('request body too large');\n }\n\n rawBody += chunkText;\n }\n\n if (rawBody.length === 0) {\n throw new Error('missing json body');\n }\n\n try {\n return JSON.parse(rawBody) as unknown;\n } catch (error: unknown) {\n throw new Error('malformed json body', {\n cause: error,\n });\n }\n }\n\n private sendJson(\n response: ServerResponse,\n statusCode: number,\n payload: unknown,\n ): void {\n response.writeHead(statusCode, {\n 'content-type': 'application/json; charset=utf-8',\n });\n response.end(`${JSON.stringify(payload)}\\n`);\n }\n}\n","import { access, rm } from 'node:fs/promises';\nimport { constants } from 'node:fs';\nimport { createConnection, createServer, type Server, type Socket } from 'node:net';\nimport { createInterface } from 'node:readline';\nimport { once } from 'node:events';\n\nimport { AISnitchEventSchema } from '../events/schema.js';\nimport type { AISnitchEvent } from '../events/types.js';\nimport { logger } from './logger.js';\n\n/**\n * @file src/core/engine/uds-server.ts\n * @description NDJSON Unix domain socket ingress for out-of-process AISnitch adapters.\n * @functions\n * โ†’ none\n * @exports UDSServerStartOptions, UDSServerStats, UDSServer\n * @see ./pipeline.ts\n */\n\n/**\n * Startup configuration for the UDS server.\n */\nexport interface UDSServerStartOptions {\n readonly socketPath: string;\n readonly onEvent: (event: AISnitchEvent) => Promise<void> | void;\n}\n\n/**\n * Observable runtime stats for the UDS server.\n */\nexport interface UDSServerStats {\n readonly listening: boolean;\n readonly socketPath: string | null;\n readonly activeConnections: number;\n readonly acceptedConnections: number;\n readonly receivedEvents: number;\n readonly rejectedMessages: number;\n}\n\n/**\n * ๐Ÿ“– UDS is the low-friction IPC path for community adapters. NDJSON keeps the\n * protocol debuggable with shell tools and trivial to implement elsewhere.\n */\nexport class UDSServer {\n private server: Server | undefined;\n\n private socketPath: string | null = null;\n\n private readonly sockets = new Set<Socket>();\n\n private acceptedConnections = 0;\n\n private receivedEvents = 0;\n\n private rejectedMessages = 0;\n\n /**\n * Starts listening on the provided socket path.\n */\n public async start(options: UDSServerStartOptions): Promise<string> {\n if (this.server) {\n return this.socketPath ?? options.socketPath;\n }\n\n await this.ensureSocketPathAvailable(options.socketPath);\n\n this.server = createServer((socket) => {\n this.handleSocket(socket, options.onEvent);\n });\n\n this.server.on('error', (error) => {\n logger.error({ error }, 'UDS server error');\n });\n\n this.server.listen(options.socketPath);\n await once(this.server, 'listening');\n\n this.socketPath = options.socketPath;\n\n logger.info(\n {\n socketPath: this.socketPath,\n },\n 'UDS server started',\n );\n\n return this.socketPath;\n }\n\n /**\n * Stops the UDS server and removes the socket file.\n */\n public async stop(): Promise<void> {\n for (const socket of this.sockets) {\n socket.destroy();\n }\n this.sockets.clear();\n\n if (this.server) {\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n }\n\n if (this.socketPath && process.platform !== 'win32') {\n await rm(this.socketPath, { force: true });\n }\n\n this.socketPath = null;\n\n logger.info('UDS server stopped');\n }\n\n /**\n * Returns current runtime metrics for the UDS ingress channel.\n */\n public getStats(): UDSServerStats {\n return {\n listening: this.server !== undefined,\n socketPath: this.socketPath,\n activeConnections: this.sockets.size,\n acceptedConnections: this.acceptedConnections,\n receivedEvents: this.receivedEvents,\n rejectedMessages: this.rejectedMessages,\n };\n }\n\n private handleSocket(\n socket: Socket,\n onEvent: (event: AISnitchEvent) => Promise<void> | void,\n ): void {\n this.sockets.add(socket);\n this.acceptedConnections += 1;\n\n socket.on('close', () => {\n this.sockets.delete(socket);\n });\n\n socket.on('error', (error) => {\n logger.warn({ error }, 'UDS client socket error');\n });\n\n const lineReader = createInterface({\n input: socket,\n crlfDelay: Infinity,\n });\n\n lineReader.on('line', (line) => {\n if (line.trim().length === 0) {\n return;\n }\n\n let parsedPayload: unknown;\n\n try {\n parsedPayload = JSON.parse(line) as unknown;\n } catch (error: unknown) {\n this.rejectedMessages += 1;\n logger.warn({ error, line }, 'Rejected malformed UDS NDJSON payload');\n return;\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n if (!parsedEvent.success) {\n this.rejectedMessages += 1;\n logger.warn(\n {\n issues: parsedEvent.error.issues,\n },\n 'Rejected invalid UDS event payload',\n );\n return;\n }\n\n this.receivedEvents += 1;\n\n queueMicrotask(() => {\n void Promise.resolve(onEvent(parsedEvent.data)).catch((error) => {\n logger.error({ error }, 'UDS event handler failed');\n });\n });\n });\n }\n\n private async ensureSocketPathAvailable(socketPath: string): Promise<void> {\n if (process.platform === 'win32') {\n return;\n }\n\n try {\n await access(socketPath, constants.F_OK);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return;\n }\n\n throw error;\n }\n\n const staleSocket = await new Promise<boolean>((resolve, reject) => {\n const probe = createConnection(socketPath);\n\n probe.once('connect', () => {\n probe.destroy();\n resolve(false);\n });\n\n probe.once('error', (error: NodeJS.ErrnoException) => {\n if (\n error.code === 'ECONNREFUSED' ||\n error.code === 'ENOENT' ||\n error.code === 'EINVAL' ||\n error.code === 'ENOTSOCK'\n ) {\n resolve(true);\n return;\n }\n\n reject(error);\n });\n });\n\n if (!staleSocket) {\n throw new Error(`Socket path is already in use: ${socketPath}`);\n }\n\n await rm(socketPath, { force: true });\n }\n}\n","import { join } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { AdapterRegistry, createDefaultAdapters } from '../../adapters/index.js';\nimport {\n DEFAULT_CONFIG,\n type ConfigPathOptions,\n ensureConfigDir,\n getAISnitchHomePath,\n resolveAvailablePort,\n} from '../config/index.js';\nimport {\n AISnitchEventSchema,\n AISnitchEventTypeSchema,\n EventDataSchema,\n ToolNameSchema,\n createEvent,\n} from '../events/index.js';\nimport type { AISnitchConfig } from '../config/index.js';\nimport type { AISnitchEvent, ToolName } from '../events/index.js';\nimport { resolveSessionId } from '../session-identity.js';\nimport { ContextDetector, type ProcessContext } from './context-detector.js';\nimport { EventBus, type EventBusStats } from './event-bus.js';\nimport {\n HTTPReceiver,\n type HealthSnapshot,\n type HTTPReceiverStats,\n} from './http-receiver.js';\nimport { logger } from './logger.js';\nimport { UDSServer, type UDSServerStats } from './uds-server.js';\nimport { WSServer, type WSServerStats } from './ws-server.js';\n\n/**\n * @file src/core/engine/pipeline.ts\n * @description Orchestrates the in-memory AISnitch core pipeline and ingress/egress components.\n * @functions\n * โ†’ getSocketPath\n * @exports HookHandler, PipelineStartOptions, PipelineStatus, Pipeline\n * @see ./event-bus.ts\n * @see ./ws-server.ts\n * @see ./http-receiver.ts\n * @see ./uds-server.ts\n * @see ./context-detector.ts\n */\n\nconst HookIngressPayloadSchema = z.strictObject({\n type: AISnitchEventTypeSchema,\n source: z.string().min(1).optional(),\n sessionId: z.string().min(1).optional(),\n seqnum: z.number().int().min(1).optional(),\n data: EventDataSchema.partial().optional(),\n pid: z.number().int().positive().optional(),\n transcriptPath: z.string().min(1).optional(),\n cwd: z.string().min(1).optional(),\n env: z.record(z.string(), z.string()).optional(),\n hookPayload: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Hook handler signature for future adapter-specific hook processors.\n */\nexport type HookHandler = (payload: unknown) => Promise<void> | void;\n\n/**\n * Startup options for the orchestrating pipeline.\n */\nexport interface PipelineStartOptions {\n readonly config?: AISnitchConfig;\n readonly configPath?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly homeDirectory?: string;\n}\n\n/**\n * Snapshot of the full runtime pipeline state.\n */\nexport interface PipelineStatus {\n readonly running: boolean;\n readonly uptimeMs: number;\n readonly wsPort: number | null;\n readonly httpPort: number | null;\n readonly socketPath: string | null;\n readonly eventBus: EventBusStats;\n readonly websocket: WSServerStats;\n readonly http: HTTPReceiverStats;\n readonly uds: UDSServerStats;\n}\n\n/**\n * Returns the platform-specific IPC socket path for the AISnitch daemon.\n */\nexport function getSocketPath(aisnitchHomePath: string): string {\n if (process.platform === 'win32') {\n return '\\\\\\\\.\\\\pipe\\\\aisnitch.sock';\n }\n\n return join(aisnitchHomePath, 'aisnitch.sock');\n}\n\n/**\n * ๐Ÿ“– The pipeline is the real in-process backbone: one EventBus in the middle,\n * ingress on HTTP/UDS, egress on WS, and context enrichment before fan-out.\n */\nexport class Pipeline {\n private readonly eventBus = new EventBus();\n\n private readonly wsServer = new WSServer();\n\n private readonly httpReceiver = new HTTPReceiver();\n\n private readonly udsServer = new UDSServer();\n\n private readonly contextDetector = new ContextDetector();\n\n private adapterRegistry: AdapterRegistry | null = null;\n\n private enabledTools = new Set<ToolName>();\n\n private readonly hookHandlers = new Map<ToolName, HookHandler>();\n\n private startedAt: number | null = null;\n\n private wsPort: number | null = null;\n\n private httpPort: number | null = null;\n\n private socketPath: string | null = null;\n\n /**\n * Starts the full in-memory core pipeline.\n */\n public async start(options: PipelineStartOptions = {}): Promise<PipelineStatus> {\n if (this.startedAt !== null) {\n return this.getStatus();\n }\n\n const config = options.config ?? DEFAULT_CONFIG;\n const pathOptions: ConfigPathOptions = {\n configPath: options.configPath,\n env: options.env,\n homeDirectory: options.homeDirectory,\n };\n\n await ensureConfigDir(pathOptions);\n\n const resolvedWsPort = await resolveAvailablePort(config.wsPort, {\n logger: (message) => logger.info(message),\n });\n let resolvedHttpPort = await resolveAvailablePort(config.httpPort, {\n logger: (message) => logger.info(message),\n });\n\n if (resolvedHttpPort === resolvedWsPort) {\n resolvedHttpPort = await resolveAvailablePort(resolvedHttpPort + 1, {\n logger: (message) => logger.info(message),\n });\n }\n const aisnitchHomePath = getAISnitchHomePath(pathOptions);\n const socketPath = getSocketPath(aisnitchHomePath);\n const activeTools = Object.entries(config.adapters)\n .filter((entry): entry is [ToolName, { enabled: boolean }] => {\n const [toolName, adapterConfig] = entry;\n return (\n ToolNameSchema.safeParse(toolName).success &&\n adapterConfig?.enabled === true\n );\n })\n .map(([toolName]) => toolName);\n const adapterRegistry = new AdapterRegistry();\n\n for (const adapter of createDefaultAdapters({\n config,\n env: options.env,\n homeDirectory: options.homeDirectory,\n publishEvent: async (event, context) => {\n return await this.publishEvent(event, context);\n },\n })) {\n adapterRegistry.register(adapter);\n }\n\n this.adapterRegistry = adapterRegistry;\n this.enabledTools = new Set(activeTools);\n this.hookHandlers.clear();\n\n for (const toolName of activeTools) {\n const adapter = this.adapterRegistry.get(toolName);\n\n if (!adapter) {\n continue;\n }\n\n this.registerHookHandler(toolName, async (payload) => {\n await adapter.handleHook(payload);\n });\n }\n\n try {\n this.wsPort = await this.wsServer.start({\n port: resolvedWsPort,\n eventBus: this.eventBus,\n activeTools,\n });\n this.httpPort = await this.httpReceiver.start({\n port: resolvedHttpPort,\n onHook: async (tool, payload) => {\n await this.handleHook(tool, payload);\n },\n getHealthSnapshot: () => this.getHealthSnapshot(),\n });\n this.socketPath = await this.udsServer.start({\n socketPath,\n onEvent: async (event) => {\n await this.publishEvent(event);\n },\n });\n await this.adapterRegistry.startAll(config);\n } catch (error: unknown) {\n logger.error({ error }, '๐Ÿ“– Pipeline start failed โ€” rolling back already-started components');\n await this.rollbackPartialStart();\n throw error;\n }\n\n this.startedAt = Date.now();\n\n logger.info(this.getStatus(), 'Core pipeline started');\n\n return this.getStatus();\n }\n\n /**\n * Stops every pipeline component in reverse dependency order.\n */\n public async stop(): Promise<void> {\n const stopSafely = async (label: string, fn: () => Promise<void>) => {\n try {\n await fn();\n } catch (error: unknown) {\n logger.warn({ error }, `๐Ÿ“– Error while stopping ${label} โ€” continuing shutdown`);\n }\n };\n\n await stopSafely('adapter registry', async () => {\n await this.adapterRegistry?.stopAll();\n });\n await stopSafely('HTTP receiver', async () => {\n await this.httpReceiver.stop();\n });\n await stopSafely('UDS server', async () => {\n await this.udsServer.stop();\n });\n await stopSafely('WebSocket server', async () => {\n await this.wsServer.stop();\n });\n\n this.eventBus.unsubscribeAll();\n this.adapterRegistry = null;\n this.enabledTools.clear();\n this.hookHandlers.clear();\n\n this.startedAt = null;\n this.wsPort = null;\n this.httpPort = null;\n this.socketPath = null;\n\n logger.info('Core pipeline stopped');\n }\n\n /**\n * Registers a future adapter-specific hook handler for one tool.\n */\n public registerHookHandler(tool: ToolName, handler: HookHandler): void {\n this.hookHandlers.set(tool, handler);\n }\n\n /**\n * ๐Ÿ“– Rolls back any components that were successfully started before a\n * failure occurred, preventing orphaned servers or leaking resources.\n */\n private async rollbackPartialStart(): Promise<void> {\n const stopSafe = async (label: string, fn: () => Promise<void>) => {\n try {\n await fn();\n } catch (error: unknown) {\n logger.warn({ error }, `๐Ÿ“– Error rolling back ${label}`);\n }\n };\n\n await stopSafe('adapter registry', async () => {\n await this.adapterRegistry?.stopAll();\n });\n await stopSafe('UDS server', async () => {\n await this.udsServer.stop();\n });\n await stopSafe('HTTP receiver', async () => {\n await this.httpReceiver.stop();\n });\n await stopSafe('WebSocket server', async () => {\n await this.wsServer.stop();\n });\n\n this.adapterRegistry = null;\n this.enabledTools.clear();\n this.hookHandlers.clear();\n }\n\n /**\n * Publishes an event after best-effort context enrichment.\n * ๐Ÿ“– If enrichment fails, the original event is published un-enriched\n * rather than being dropped entirely.\n */\n public async publishEvent(\n event: AISnitchEvent,\n context: ProcessContext = {},\n ): Promise<boolean> {\n let enrichedEvent: AISnitchEvent;\n\n try {\n enrichedEvent = await this.contextDetector.enrich(event, context);\n } catch (error: unknown) {\n logger.warn(\n { error, eventId: event.id },\n '๐Ÿ“– Context enrichment failed โ€” publishing un-enriched event',\n );\n enrichedEvent = event;\n }\n\n return this.eventBus.publish(enrichedEvent);\n }\n\n /**\n * Exposes current pipeline state for tests, health checks, and future status commands.\n */\n public getStatus(): PipelineStatus {\n return {\n running: this.startedAt !== null,\n uptimeMs: this.startedAt === null ? 0 : Date.now() - this.startedAt,\n wsPort: this.wsPort,\n httpPort: this.httpPort,\n socketPath: this.socketPath,\n eventBus: this.eventBus.getStats(),\n websocket: this.wsServer.getStats(),\n http: this.httpReceiver.getStats(),\n uds: this.udsServer.getStats(),\n };\n }\n\n /**\n * Returns the in-process event bus for direct wiring in tests or future TUI code.\n */\n public getEventBus(): EventBus {\n return this.eventBus;\n }\n\n /**\n * Returns the adapter registry for graceful shutdown coordination.\n */\n public getAdapterRegistry(): AdapterRegistry | undefined {\n return this.adapterRegistry ?? undefined;\n }\n\n /**\n * Returns the HTTP receiver for graceful shutdown coordination.\n */\n public getHttpReceiver(): HTTPReceiver {\n return this.httpReceiver;\n }\n\n /**\n * Returns the UDS server for graceful shutdown coordination.\n */\n public getUdsServer(): UDSServer {\n return this.udsServer;\n }\n\n /**\n * Returns the WebSocket server for graceful shutdown coordination.\n */\n public getWsServer(): WSServer {\n return this.wsServer;\n }\n\n private getHealthSnapshot(): HealthSnapshot {\n const status = this.getStatus();\n\n return {\n status: 'ok',\n uptime: status.uptimeMs,\n consumers: status.websocket.consumerCount,\n events: status.eventBus.publishedEvents,\n droppedEvents: status.websocket.droppedEvents,\n };\n }\n\n private async handleHook(tool: ToolName, payload: unknown): Promise<void> {\n try {\n await this.handleHookInner(tool, payload);\n } catch (error: unknown) {\n logger.error(\n { error, tool },\n '๐Ÿ“– Unhandled error in hook handler โ€” swallowing to prevent daemon crash',\n );\n }\n }\n\n private async handleHookInner(tool: ToolName, payload: unknown): Promise<void> {\n if (!this.enabledTools.has(tool)) {\n logger.debug({ tool }, 'Ignoring hook for disabled tool');\n return;\n }\n\n const registeredHandler = this.hookHandlers.get(tool);\n\n if (registeredHandler) {\n await registeredHandler(payload);\n return;\n }\n\n const alreadyNormalizedEvent = AISnitchEventSchema.safeParse(payload);\n\n if (alreadyNormalizedEvent.success) {\n await this.publishEvent(alreadyNormalizedEvent.data);\n return;\n }\n\n const normalizedHook = HookIngressPayloadSchema.safeParse(payload);\n\n if (!normalizedHook.success) {\n logger.warn(\n {\n tool,\n issues: normalizedHook.error.issues,\n },\n 'Unable to normalize hook payload',\n );\n return;\n }\n\n const resolvedSessionId = resolveSessionId({\n activeFile: normalizedHook.data.data?.activeFile,\n cwd: normalizedHook.data.data?.cwd ?? normalizedHook.data.cwd,\n pid: normalizedHook.data.pid,\n project: normalizedHook.data.data?.project,\n projectPath: normalizedHook.data.data?.projectPath,\n sessionId: normalizedHook.data.sessionId,\n tool,\n transcriptPath: normalizedHook.data.transcriptPath,\n });\n const event = createEvent({\n source: normalizedHook.data.source ?? `aisnitch://hooks/${tool}`,\n type: normalizedHook.data.type,\n 'aisnitch.tool': tool,\n 'aisnitch.sessionid': resolvedSessionId,\n 'aisnitch.seqnum': normalizedHook.data.seqnum ?? 1,\n data: {\n ...normalizedHook.data.data,\n cwd:\n normalizedHook.data.data?.cwd ??\n normalizedHook.data.cwd,\n },\n });\n\n await this.publishEvent(event, {\n pid: normalizedHook.data.pid,\n env: normalizedHook.data.env,\n sessionId: resolvedSessionId,\n transcriptPath: normalizedHook.data.transcriptPath,\n hookPayload:\n normalizedHook.data.hookPayload ??\n (this.isPlainRecord(payload) ? payload : undefined),\n });\n }\n\n private isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n}\n","import type { AISnitchEvent, AISnitchEventType, CESPCategory } from './types.js';\n\n/**\n * @file src/core/events/cesp.ts\n * @description CESP compatibility helpers for mapping normalized AISnitch events into legacy categories.\n * @functions\n * โ†’ getCESPCategory\n * @exports CESP_MAP, getCESPCategory\n * @see ./types.ts\n */\n\n/**\n * ๐Ÿ“– Some normalized states have no direct CESP equivalent. Returning `null`\n * makes that gap explicit instead of inventing fake sound-pack categories.\n */\nexport const CESP_MAP: Record<AISnitchEventType, CESPCategory | null> = {\n 'session.start': 'session.start',\n 'session.end': 'session.end',\n 'task.start': 'task.acknowledge',\n 'task.complete': 'task.complete',\n 'agent.thinking': null,\n 'agent.coding': null,\n 'agent.tool_call': null,\n 'agent.streaming': null,\n 'agent.asking_user': 'input.required',\n 'agent.idle': null,\n 'agent.error': 'task.error',\n 'agent.compact': 'resource.limit',\n};\n\n/**\n * Resolves the CESP category for either a full event object or an event type.\n */\nexport function getCESPCategory(\n eventOrType: AISnitchEvent | AISnitchEventType,\n): CESPCategory | null {\n const eventType =\n typeof eventOrType === 'string' ? eventOrType : eventOrType.type;\n\n return CESP_MAP[eventType];\n}\n","/**\n * @file src/core/timeout.ts\n * @description Async operation timeout wrappers to prevent indefinite blocking.\n *\n * AISnitch processes many async operations (file reads, HTTP requests, process\n * detection, file watchers, adapter startup/shutdown). Without explicit timeouts,\n * any of these can block the entire daemon indefinitely if the underlying resource\n * becomes unresponsive (e.g., NFS mount stuck, disk I/O stalled, external API hanging).\n *\n * This module provides:\n * - `withTimeout()` โ€” race a promise against a deadline\n * - `TimeoutError` โ€” typed error thrown on timeout\n * - `DEFAULT_TIMEOUTS` โ€” sane defaults per operation type\n *\n * Usage:\n * ```typescript\n * // Fail-fast: don't wait more than 3s for a file read\n * const content = await withTimeout(\n * readFile('/path/to/transcript.jsonl', 'utf8'),\n * 3_000,\n * 'claude-transcript-read'\n * );\n * ```\n *\n * @functions\n * โ†’ withTimeout\n * โ†’ DEFAULT_TIMEOUTS\n * @exports DEFAULT_TIMEOUTS, withTimeout\n * @see ./errors.ts (TimeoutError)\n * @see ./graceful-shutdown.ts\n */\n\nimport { TimeoutError } from './errors.js';\nimport { logger } from './engine/logger.js';\n\n/**\n * Named timeout windows for common AISnitch operations.\n *\n * These defaults are conservative but reasonable for local development:\n * - File operations: fast on local SSDs, need headroom for larger logs\n * - HTTP requests: generous (30s) because AI tool hooks can be slow\n * - Process detection: frequent polling, keep each poll short\n * - Adapter lifecycle: moderate (10s) for graceful shutdowns\n *\n * Override per-call via the `withTimeout()` `timeoutMs` parameter.\n */\nexport const DEFAULT_TIMEOUTS = Object.freeze({\n /**\n * File read/write operations (JSONL transcripts, config files).\n * Default: 5 seconds\n */\n fileOperation: 5_000,\n\n /**\n * HTTP requests to health endpoint or external APIs.\n * Default: 30 seconds\n */\n httpRequest: 30_000,\n\n /**\n * Process detection commands (`pgrep`, `ps aux`).\n * Default: 3 seconds\n */\n processDetection: 3_000,\n\n /**\n * Adapter startup (file watchers, hook bridges, pollers).\n * Default: 10 seconds\n */\n adapterStartup: 10_000,\n\n /**\n * Adapter shutdown (graceful cleanup, watcher close).\n * Default: 5 seconds โ€” after this, resources are force-closed\n */\n adapterShutdown: 5_000,\n\n /**\n * Daemon graceful shutdown (stop all components in order).\n * Default: 30 seconds\n */\n daemonShutdown: 30_000,\n\n /**\n * WebSocket connection establishment.\n * Default: 10 seconds\n */\n wsConnection: 10_000,\n\n /**\n * Overall pipeline start (all components).\n * Default: 15 seconds\n */\n pipelineStartup: 15_000,\n} as const);\n\n/**\n * Type representing the keys of `DEFAULT_TIMEOUTS`.\n */\nexport type TimeoutName = keyof typeof DEFAULT_TIMEOUTS;\n\n/**\n * Races a promise against a deadline.\n *\n * If the promise resolves first, returns the resolved value.\n * If the timeout fires first, throws a `TimeoutError`.\n *\n * The timeout is implemented via `Promise.race()` so it does not\n * forcefully abort the underlying promise โ€” the promise continues\n * running in the background. For truly cancellable operations,\n * consider `AbortController` in addition to this utility.\n *\n * @example\n * ```typescript\n * try {\n * const result = await withTimeout(\n * fetch('http://example.com/slow-endpoint'),\n * 5_000,\n * 'external-api-call'\n * );\n * return await result.json();\n * } catch (error) {\n * if (error instanceof TimeoutError) {\n * logger.warn({ context: error.context }, 'Operation timed out');\n * return null;\n * }\n * throw error;\n * }\n * ```\n *\n * @param promise - The async operation to race\n * @param timeoutMs - Maximum time to wait in milliseconds\n * @param context - Human-readable label for logging and error context\n * @returns The resolved value if `promise` wins the race\n * @throws TimeoutError if the timeout fires first\n */\nexport function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n context: string,\n): Promise<T> {\n if (timeoutMs <= 0) {\n // Immediately reject invalid timeouts rather than silently hanging\n throw new TimeoutError(\n `Invalid timeout value: ${timeoutMs}ms (must be > 0)`,\n 'TIMEOUT_INVALID_VALUE',\n { context, timeoutMs },\n );\n }\n\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new TimeoutError(\n `Operation exceeded ${timeoutMs}ms deadline`,\n 'TIMEOUT_EXCEEDED',\n { context, timeoutMs },\n ),\n );\n }, timeoutMs);\n\n // Allow the timeout to be garbage-collected if the promise resolves\n timeoutId.unref();\n }),\n ]);\n}\n\n/**\n * Wraps a promise with a timeout and logs a warning if it times out.\n * Unlike `withTimeout()`, this never throws โ€” it falls through to the\n * original promise's result (or error) if the timeout fires first.\n *\n * Best-effort: useful for non-critical background operations where a\n * timeout should log a warning but not crash the flow.\n *\n * @example\n * ```typescript\n * // Log a warning but don't fail if process detection hangs\n * await timeoutWarning(\n * listProcesses(processListCommand),\n * DEFAULT_TIMEOUTS.processDetection,\n * 'claude-process-detection'\n * );\n * ```\n */\nexport async function timeoutWarning<T>(\n promise: Promise<T>,\n timeoutMs: number,\n context: string,\n): Promise<T> {\n try {\n return await withTimeout(promise, timeoutMs, context);\n } catch (error) {\n if (error instanceof TimeoutError) {\n logger.warn(\n { context: error.context, timeoutMs: error.context },\n `Best-effort operation timed out after ${timeoutMs}ms`,\n );\n // Fall through: the original promise may still resolve (fire-and-forget)\n // Return a rejected promise so the caller can handle it if needed\n return await promise;\n }\n\n throw error;\n }\n}\n\n/**\n * Gets the timeout value for a named operation.\n *\n * @example\n * ```typescript\n * const timeoutMs = getTimeout('adapterShutdown');\n * // โ†’ 5_000\n * ```\n */\nexport function getTimeout(name: TimeoutName): number {\n return DEFAULT_TIMEOUTS[name];\n}\n\n/**\n * Checks whether an error is a TimeoutError.\n * Shorthand for `error instanceof TimeoutError` with explicit return type.\n */\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return error instanceof TimeoutError;\n}\n","/**\n * @file src/core/graceful-shutdown.ts\n * @description Graceful shutdown coordination to prevent orphaned resources and partial state.\n *\n * Graceful shutdown is critical for a long-running daemon like AISnitch:\n * - **No orphaned servers**: HTTP/WebSocket/UDS servers must be closed cleanly\n * - **No resource leaks**: file watchers, pollers, timers must be stopped\n * - **Clean PID files**: stale PID files confuse subsequent launches\n * - **Clean state files**: daemon-state.json must be removed on exit\n *\n * This module provides:\n * - `withShutdownTimeout()` โ€” wrap a shutdown function with a deadline\n * - `shutdownInOrder()` โ€” stop components in reverse dependency order\n * - `GracefulShutdownManager` โ€” coordinates all shutdown signals (SIGTERM, SIGINT, SIGHUP)\n *\n * ## Shutdown order for AISnitch pipeline\n *\n * ```\n * 1. adapters.stopAll() โ€” stop watching files, kill pollers, close watchers\n * 2. httpReceiver.stop() โ€” close HTTP server\n * 3. udsServer.stop() โ€” close Unix Domain Socket\n * 4. wsServer.stop() โ€” close WebSocket server (consumers get disconnected)\n * 5. eventBus.unsubscribeAll() โ€” remove all listeners\n * 6. cleanup PID/state files โ€” prevent stale state on next launch\n * ```\n *\n * @functions\n * โ†’ withShutdownTimeout\n * โ†’ shutdownInOrder\n * @exports GracefulShutdownManager, ShutdownComponents, withShutdownTimeout, shutdownInOrder\n * @see ./errors.ts (TimeoutError)\n * @see ./timeout.ts (DEFAULT_TIMEOUTS)\n * @see ../cli/runtime.ts (shutdown orchestration)\n */\n\nimport { isTimeoutError, withTimeout } from './timeout.js';\nimport { logger } from './engine/logger.js';\nimport { DEFAULT_TIMEOUTS } from './timeout.js';\n\n/**\n * All AISnitch components that participate in graceful shutdown.\n * Stopped in reverse dependency order (last-started = first-stopped).\n */\nexport interface ShutdownComponents {\n readonly adapterRegistry?: {\n stopAll: () => Promise<void>;\n };\n readonly httpReceiver?: {\n stop: () => Promise<void>;\n };\n readonly udsServer?: {\n stop: () => Promise<void>;\n };\n readonly wsServer?: {\n stop: () => Promise<void>;\n };\n readonly eventBus?: {\n unsubscribeAll: () => void;\n };\n readonly cleanupFns?: ReadonlyArray<() => Promise<void> | void>;\n}\n\n/**\n * Wraps an async shutdown operation with a deadline.\n *\n * If the shutdown completes within `timeoutMs`, returns normally.\n * If the timeout fires first, logs a warning and continues (forces through).\n *\n * This ensures that a misbehaving component can never indefinitely block\n * daemon shutdown and leave the system in a half-dead state.\n *\n * @example\n * ```typescript\n * await withShutdownTimeout(\n * () => adapter.stop(),\n * DEFAULT_TIMEOUTS.adapterShutdown,\n * 'ClaudeCodeAdapter'\n * );\n * ```\n *\n * @param fn - Async shutdown function to execute\n * @param timeoutMs - Maximum time to wait in milliseconds\n * @param component - Human-readable name for logging\n */\nexport async function withShutdownTimeout(\n fn: () => Promise<void>,\n timeoutMs: number,\n component: string,\n): Promise<void> {\n if (timeoutMs <= 0) {\n // Execute without timeout if 0 or negative is passed (tests, forced shutdown)\n await fn();\n return;\n }\n\n const timeoutPromise = new Promise<'timed_out' | 'completed'>((resolve) => {\n setTimeout(() => {\n resolve('timed_out');\n }, timeoutMs).unref();\n });\n\n const result = await Promise.race([\n fn().then(() => 'completed' as const),\n timeoutPromise,\n ]);\n\n if (result === 'timed_out') {\n logger.warn(\n { component, timeoutMs },\n `Graceful shutdown exceeded ${timeoutMs}ms timeout โ€” forcing through`,\n );\n }\n}\n\n/**\n * Stops AISnitch components in safe reverse-dependency order with individual timeouts.\n *\n * ## Why reverse order?\n *\n * The pipeline starts: adapters โ†’ HTTP โ†’ UDS โ†’ WS โ†’ eventBus\n * If we stop WS before HTTP, new connections keep arriving at HTTP.\n * If we stop eventBus before WS, consumers get events from the bus but can't send them.\n * Therefore, stop in reverse: eventBus โ†’ WS โ†’ UDS โ†’ HTTP โ†’ adapters.\n *\n * @example\n * ```typescript\n * await shutdownInOrder(\n * {\n * eventBus: pipeline.getEventBus(),\n * wsServer: pipeline.getWSServer(),\n * httpReceiver: pipeline.getHTTPReceiver(),\n * udsServer: pipeline.getUDSServer(),\n * adapterRegistry: pipeline.getAdapterRegistry(),\n * cleanupFns: [\n * () => removePid(pathOptions),\n * () => removeDaemonState(pathOptions),\n * ],\n * },\n * {\n * eventBus: 1_000,\n * wsServer: 3_000,\n * httpReceiver: 2_000,\n * udsServer: 2_000,\n * adapterRegistry: 5_000,\n * },\n * 'AISnitch pipeline'\n * );\n * ```\n *\n * @param components - Components to shut down\n * @param timeouts - Per-component timeout in milliseconds\n * @param label - Human-readable label for logging\n */\nexport async function shutdownInOrder(\n components: ShutdownComponents,\n timeouts: Partial<Record<keyof ShutdownComponents, number>>,\n label: string,\n): Promise<void> {\n const getTimeout = (key: keyof ShutdownComponents): number => {\n return timeouts[key] ?? DEFAULT_TIMEOUTS.daemonShutdown;\n };\n\n const stopSafely = async (\n key: keyof ShutdownComponents,\n fn: () => Promise<void>,\n ): Promise<void> => {\n const timeoutMs = getTimeout(key);\n\n try {\n await withShutdownTimeout(fn, timeoutMs, `${label}.${key}`);\n } catch (error) {\n // Log but never re-throw โ€” one broken component must not abort the rest\n logger.warn(\n { error, key, label },\n `Error during shutdown of ${key} โ€” continuing with remaining components`,\n );\n }\n };\n\n // Shutdown in reverse dependency order\n if (components.cleanupFns) {\n for (const cleanupFn of components.cleanupFns) {\n try {\n await withShutdownTimeout(\n async () => {\n const result = cleanupFn();\n if (result instanceof Promise) {\n await result;\n }\n },\n 1_000,\n `${label}.cleanup`,\n );\n } catch (error) {\n logger.warn({ error, label }, 'Cleanup function failed');\n }\n }\n }\n\n if (components.eventBus) {\n components.eventBus.unsubscribeAll();\n }\n\n await stopSafely('wsServer', () => components.wsServer!.stop());\n\n await stopSafely('udsServer', () => components.udsServer!.stop());\n\n await stopSafely('httpReceiver', () => components.httpReceiver!.stop());\n\n if (components.adapterRegistry) {\n await stopSafely('adapterRegistry', () => components.adapterRegistry!.stopAll());\n }\n}\n\n/**\n * Coordinates all shutdown signals (SIGTERM, SIGINT, SIGHUP) for a process.\n *\n * ## Why a manager class?\n *\n * - Multiple signals can arrive in quick succession (e.g., SIGTERM then SIGINT)\n * - Handlers must be idempotent (second call does nothing)\n * - The manager tracks whether shutdown is already in progress\n * - It ensures the main process exits with the correct exit code\n *\n * @example\n * ```typescript\n * const manager = new GracefulShutdownManager({\n * onShutdown: async (signal) => {\n * await shutdownInOrder(pipeline, timeouts, 'pipeline');\n * await cleanupFiles(pathOptions);\n * },\n * signal: 'SIGTERM',\n * });\n *\n * process.on('SIGTERM', manager.handler);\n * process.on('SIGINT', manager.handler);\n *\n * // Call handler manually to trigger shutdown from anywhere\n * await manager.shutdown('manual-trigger');\n * ```\n */\nexport class GracefulShutdownManager {\n private shuttingDown = false;\n\n private readonly pendingHandlers = new Set<() => void>();\n\n /**\n * Creates a new shutdown manager.\n *\n * @param options - Configuration options\n * @param options.onShutdown - Async function called when shutdown is triggered\n * @param options.exitCode - Exit code to use (default: 0 for graceful, 1 for errors)\n * @param options.exitDelayMs - Delay before `process.exit()` (default: 100ms for flush)\n */\n public constructor(\n private readonly options: {\n readonly onShutdown: (signal: string) => Promise<void>;\n readonly exitCode?: number;\n readonly exitDelayMs?: number;\n },\n ) {}\n\n /**\n * Synchronous handler function suitable for `process.on()`.\n *\n * Multiple calls are safe โ€” only the first call executes `onShutdown`.\n * Subsequent calls queue to the internal pending set and run after the\n * first shutdown completes.\n */\n public get handler(): (signal: string) => void {\n return (signal: string) => {\n if (!this.shuttingDown) {\n this.shuttingDown = true;\n void this.runShutdown(signal);\n } else {\n // Queue additional signals to run after current shutdown finishes\n this.pendingHandlers.add(() => {\n void this.runShutdown(signal);\n });\n }\n };\n }\n\n /**\n * Manually triggers shutdown from async code (e.g., TUI quit button).\n *\n * @param signal - Signal name (for logging)\n */\n public shutdown(signal = 'manual'): void {\n this.handler(signal);\n }\n\n /**\n * Returns whether shutdown is currently in progress.\n */\n public isShuttingDown(): boolean {\n return this.shuttingDown;\n }\n\n private async runShutdown(signal: string): Promise<void> {\n const exitCode = this.options.exitCode ?? (signal === 'uncaughtException' || signal === 'unhandledRejection' ? 1 : 0);\n const exitDelayMs = this.options.exitDelayMs ?? 100;\n\n try {\n await this.options.onShutdown(signal);\n } catch (error) {\n logger.error(\n { error, signal },\n 'Error during graceful shutdown โ€” forcing exit',\n );\n } finally {\n // Allow buffered logs to flush before exiting\n await new Promise<void>((resolve) => {\n setTimeout(resolve, exitDelayMs).unref();\n });\n\n // Run any pending handlers from queued signals before we exit\n for (const pendingHandler of this.pendingHandlers) {\n pendingHandler();\n }\n\n process.exit(exitCode);\n }\n }\n}\n\n/**\n * Wraps a shutdown promise with an overall deadline.\n * If the overall shutdown exceeds the deadline, forces the process to exit.\n *\n * This is the last resort: no shutdown operation should ever take this long,\n * but a runaway deadlock could theoretically block forever without it.\n *\n * @example\n * ```typescript\n * const shutdownComplete = shutdownInOrder(components, timeouts, 'pipeline');\n * await withOverallShutdownTimeout(shutdownComplete, DEFAULT_TIMEOUTS.daemonShutdown, 'AISnitch');\n * ```\n */\nexport async function withOverallShutdownTimeout(\n shutdownPromise: Promise<void>,\n timeoutMs: number,\n label: string,\n): Promise<void> {\n try {\n await withTimeout(shutdownPromise, timeoutMs, `${label}-overall-shutdown`);\n } catch (error) {\n if (isTimeoutError(error)) {\n logger.error(\n { timeoutMs, label },\n `Overall shutdown timeout exceeded โ€” forcing process exit`,\n );\n }\n\n // Always exit after an overall timeout, regardless of error\n process.exit(1);\n }\n}\n","/**\n * @file src/core/result.ts\n * @description Simple Result type for explicit error handling without relying on try/catch.\n *\n * This is a lightweight alternative to fp-ts Either for cases where you want to force\n * callers to handle the error case explicitly but don't need the full fp-ts ecosystem.\n *\n * The `Result<T, E>` type has two states:\n * - `{ success: true, value: T }` โ€” operation succeeded with a value\n * - `{ success: false, error: E }` โ€” operation failed with an error\n *\n * Usage pattern:\n * ```typescript\n * function parseConfig(raw: unknown): Result<AISnitchConfig, ValidationError> {\n * const result = ConfigSchema.safeParse(raw);\n * if (!result.success) {\n * return err(new ValidationError(\n * 'Invalid config', 'VALIDATION_CONFIG_INVALID',\n * { issues: result.error.issues }\n * ));\n * }\n * return ok(result.data);\n * }\n *\n * // Caller must handle both cases\n * const result = parseConfig(raw);\n * if (isErr(result)) {\n * logger.error({ error: result.error }, 'Config parsing failed');\n * return;\n * }\n * // result.value is guaranteed to exist here\n * useConfig(result.value);\n * ```\n *\n * @functions\n * โ†’ ok\n * โ†’ err\n * โ†’ isOk\n * โ†’ isErr\n * โ†’ mapOk\n * โ†’ mapErr\n * โ†’ flatMap\n * โ†’ fromPromise\n * @exports Result, ok, err, isOk, isErr, mapOk, mapErr, flatMap, fromPromise\n * @see ./errors.ts\n * @see ./retry.ts\n */\n\n/**\n * Discriminated union representing either a successful value or a failure error.\n *\n * @typeParam T - The success value type\n * @typeParam E - The error type (defaults to `Error`)\n */\nexport type Result<T, E = Error> =\n | { readonly success: true; readonly value: T }\n | { readonly success: false; readonly error: E };\n\n/**\n * Narrowing type guard for the success case.\n *\n * @example\n * ```typescript\n * const result = maybeDoSomething();\n * if (isOk(result)) {\n * console.log(result.value); // TypeScript knows result.value exists\n * }\n * ```\n */\nexport function isOk<T, E>(result: Result<T, E>): result is { success: true; value: T } {\n return result.success === true;\n}\n\n/**\n * Narrowing type guard for the error case.\n *\n * @example\n * ```typescript\n * const result = maybeDoSomething();\n * if (isErr(result)) {\n * console.error(result.error); // TypeScript knows result.error exists\n * }\n * ```\n */\nexport function isErr<T, E>(result: Result<T, E>): result is { success: false; error: E } {\n return result.success === false;\n}\n\n/**\n * Constructs a successful result with a value.\n *\n * @example\n * ```typescript\n * const result = ok({ userId: 42, name: 'Alice' });\n * // { success: true, value: { userId: 42, name: 'Alice' } }\n * ```\n */\nexport function ok<T>(value: T): Result<T, never> {\n return Object.freeze({ success: true, value });\n}\n\n/**\n * Constructs a failed result with an error.\n *\n * @example\n * ```typescript\n * const result = err(new Error('Not found'));\n * // { success: false, error: Error('Not found') }\n * ```\n */\nexport function err<E extends Error = Error>(error: E): Result<never, E> {\n return Object.freeze({ success: false, error });\n}\n\n/**\n * Maps the success value through a transformation function.\n * Errors pass through unchanged.\n *\n * @example\n * ```typescript\n * const result: Result<User, Error> = ok({ id: 1, name: 'Alice' });\n * const mapped = mapOk(result, (user) => user.name.toUpperCase());\n * // { success: true, value: 'ALICE' }\n * ```\n */\nexport function mapOk<T, E, U>(\n result: Result<T, E>,\n fn: (value: T) => U,\n): Result<U, E> {\n if (!result.success) {\n // TypeScript needs this cast because it can't narrow both union branches at once\n return result as unknown as Result<U, E>;\n }\n\n return ok(fn(result.value));\n}\n\n/**\n * Maps the error value through a transformation function.\n * Success values pass through unchanged.\n *\n * @example\n * ```typescript\n * const result: Result<User, Error> = err(new Error('original'));\n * const mapped = mapErr(result, (error) => new CustomError(error.message));\n * // { success: false, error: CustomError('original') }\n * ```\n */\nexport function mapErr<T, E, F extends Error>(\n result: Result<T, E>,\n fn: (error: E) => F,\n): Result<T, F> {\n if (result.success) {\n return result as unknown as Result<T, F>;\n }\n\n return err(fn(result.error));\n}\n\n/**\n * Chains Result operations: if the first Result succeeds, apply `fn` to its value.\n * If it fails, propagate the error without calling `fn`.\n *\n * @example\n * ```typescript\n * const result = await flatMap(\n * await parseConfig(raw),\n * (config) => validateAdapters(config.adapters)\n * );\n * // Either returns parseConfig's error, or the error from validateAdapters\n * ```\n */\nexport async function flatMap<T, E, U, F extends Error>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F> | Promise<Result<U, F>>,\n): Promise<Result<U, E | F>> {\n if (!result.success) {\n return result as unknown as Result<U, E | F>;\n }\n\n const mapped = await fn(result.value);\n\n if (!mapped.success) {\n return mapped as unknown as Result<U, E | F>;\n }\n\n return ok(mapped.value);\n}\n\n/**\n * Converts a Promise to a Result, catching errors automatically.\n * Rejections become `{ success: false, error: E }`.\n *\n * @example\n * ```typescript\n * const result = await fromPromise(\n * fetch('http://127.0.0.1:4821/health'),\n * (error) => new NetworkError(\n * 'Health check failed',\n * 'NETWORK_HTTP_CONNECT_FAILED',\n * { cause: error }\n * )\n * );\n * if (isErr(result)) {\n * logger.warn({ error: result.error }, 'Daemon health check failed');\n * return null;\n * }\n * const health = await result.value.json();\n * ```\n */\nexport async function fromPromise<T, E extends Error>(\n promise: Promise<T>,\n mapError: (reason: unknown) => E,\n): Promise<Result<T, E>> {\n try {\n const value = await promise;\n return ok(value);\n } catch (reason) {\n return err(mapError(reason));\n }\n}\n\n/**\n * Synchronous version of `fromPromise` for non-async functions.\n *\n * @example\n * ```typescript\n * const result = fromSync(() => JSON.parse(rawJson), (e) =>\n * new ValidationError('Invalid JSON', 'VALIDATION_JSON_PARSE', { cause: e })\n * );\n * ```\n */\nexport function fromSync<T, E extends Error>(\n fn: () => T,\n mapError: (reason: unknown) => E,\n): Result<T, E> {\n try {\n return ok(fn());\n } catch (reason) {\n return err(mapError(reason));\n }\n}\n","/**\n * @file src/core/retry.ts\n * @description Exponential backoff retry utilities for transient operations.\n *\n * Retry logic is essential for resilience against:\n * - Network flakiness (connection refused, timeouts, DNS failures)\n * - Transient file-system contention (file locked, directory not ready)\n * - External API rate limits (backoff on 429 Too Many Requests)\n *\n * This module provides:\n * - `withRetry()` โ€” async function with exponential backoff\n * - `RetryOptions` โ€” configurable retry parameters\n * - `DefaultRetryOptions` โ€” sensible defaults for AISnitch workloads\n *\n * Usage:\n * ```typescript\n * const result = await withRetry(\n * () => fetchHealth(daemonPort),\n * {\n * attempts: 3,\n * delayMs: 500,\n * backoff: 2,\n * context: 'daemon-health-check',\n * }\n * );\n * ```\n *\n * @functions\n * โ†’ withRetry\n * โ†’ sleep\n * โ†’ DefaultRetryOptions\n * @exports RetryOptions, DefaultRetryOptions, withRetry, sleep\n * @see ./errors.ts\n * @see ./result.ts\n */\n\nimport { logger } from './engine/logger.js';\nimport { isRetryableError } from './errors.js';\n\n/**\n * Configuration for retry behaviour.\n */\nexport interface RetryOptions {\n /**\n * Maximum number of attempts before giving up.\n * @default 3\n */\n readonly attempts: number;\n\n /**\n * Initial delay in milliseconds between retries.\n * @default 500\n */\n readonly delayMs: number;\n\n /**\n * Multiplicative factor for delay after each attempt.\n * @default 2\n */\n readonly backoff: number;\n\n /**\n * Maximum total time in milliseconds across all retries.\n * @default 30_000\n */\n readonly maxTotalDelayMs: number;\n\n /**\n * Human-readable label used in log messages for traceability.\n */\n readonly context: string;\n\n /**\n * Optional predicate to filter which errors trigger a retry.\n * By default, `isRetryableError()` is used.\n * Return `true` to retry, `false` to give up immediately.\n */\n readonly shouldRetry?: (error: unknown) => boolean;\n\n /**\n * Set to `true` to jitter the delay slightly (ยฑ25%) to avoid thundering herd.\n * @default true\n */\n readonly jitter?: boolean;\n}\n\n/**\n * Sensible defaults tuned for AISnitch workloads:\n * - Quick first retry (500ms) for responsiveness\n * - Exponential backoff to back off gracefully\n * - 3 attempts to avoid long stalls\n * - Jitter enabled to spread load\n */\nexport const DefaultRetryOptions: Readonly<RetryOptions> = {\n attempts: 3,\n backoff: 2,\n context: 'unknown',\n delayMs: 500,\n jitter: true,\n maxTotalDelayMs: 30_000,\n shouldRetry: isRetryableError,\n};\n\n/**\n * Blocks the current async execution for the given number of milliseconds.\n *\n * @example\n * ```typescript\n * await sleep(1000); // wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms).unref();\n });\n}\n\n/**\n * Calculates the actual delay for a given attempt, applying jitter when enabled.\n */\nfunction computeDelay(\n attempt: number,\n baseDelayMs: number,\n backoff: number,\n jitter: boolean,\n): number {\n // Exponential backoff: baseDelay * backoff^(attempt-1)\n const exponentialDelay = baseDelayMs * Math.pow(backoff, attempt - 1);\n\n if (!jitter) {\n return exponentialDelay;\n }\n\n // Jitter: ยฑ25% of the delay to avoid thundering herd\n const jitterFactor = 0.75 + Math.random() * 0.5;\n return Math.round(exponentialDelay * jitterFactor);\n}\n\n/**\n * Wraps an async operation with exponential-backoff retry logic.\n *\n * ## How it works\n *\n * 1. Executes `fn` immediately (no initial delay)\n * 2. If it succeeds โ†’ returns the result\n * 3. If it throws and `shouldRetry(error)` returns `true` and attempts remain:\n * - Logs a warning at attempt level (warn) and at failure level (error)\n * - Waits `delayMs * backoff^attempt` milliseconds (with optional jitter)\n * - Repeats from step 1\n * 4. If it throws and `shouldRetry(error)` returns `false` โ†’ throws immediately\n * 5. If all attempts are exhausted โ†’ throws the last error\n *\n * ## When NOT to use this\n *\n * - **Permanent failures** (e.g., validation errors, missing required files)\n * โ†’ Use `isRetryableError()` to filter these out automatically\n * - **Operations that are not idempotent** โ†’ only retry if `fn` is safe to re-execute\n * - **User-facing latency-sensitive paths** โ†’ use a shorter `delayMs` and fewer `attempts`\n *\n * @example\n * ```typescript\n * // Retry a flaky health check up to 3 times\n * const health = await withRetry(\n * () => fetch('http://127.0.0.1:4821/health').then(r => r.json()),\n * {\n * ...DefaultRetryOptions,\n * context: 'daemon-health-check',\n * }\n * );\n * ```\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> & { context: string },\n): Promise<T> {\n const {\n attempts = DefaultRetryOptions.attempts,\n backoff = DefaultRetryOptions.backoff,\n delayMs = DefaultRetryOptions.delayMs,\n maxTotalDelayMs = DefaultRetryOptions.maxTotalDelayMs,\n jitter = DefaultRetryOptions.jitter,\n shouldRetry = DefaultRetryOptions.shouldRetry,\n } = options;\n\n let lastError: unknown;\n let totalDelayMs = 0;\n const shouldRetryWithDefault = shouldRetry ?? DefaultRetryOptions.shouldRetry!;\n\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n const retryable = shouldRetryWithDefault(error);\n const attemptsRemaining = attempt < attempts;\n\n if (!retryable || !attemptsRemaining) {\n // Non-retryable error or last attempt โ†’ propagate\n if (!retryable) {\n logger.debug(\n { attempt, context: options.context, error },\n 'Non-retryable error โ€” giving up immediately',\n );\n } else {\n logger.error(\n { attempt, attempts, context: options.context, error },\n 'All retry attempts exhausted',\n );\n }\n\n throw error;\n }\n\n const delay = computeDelay(attempt, delayMs, backoff, jitter ?? false);\n totalDelayMs += delay;\n\n if (totalDelayMs > maxTotalDelayMs) {\n logger.warn(\n { attempt, delay, totalDelayMs, maxTotalDelayMs, context: options.context },\n 'Retry max total delay exceeded โ€” giving up',\n );\n throw lastError;\n }\n\n logger.debug(\n { attempt, attempts, delay, nextDelayMs: delay, context: options.context },\n `Operation failed โ€” retrying in ${delay}ms`,\n );\n\n await sleep(delay);\n }\n }\n\n // Should never reach here, but TypeScript needs it\n throw lastError;\n}\n\n/**\n * Convenience wrapper for fire-and-forget retries (no return value needed).\n * Logs failures but never throws โ€” useful for non-critical background tasks.\n *\n * @example\n * ```typescript\n * // Best-effort metric reporting โ€” don't fail the main flow\n * fireAndForgetRetry(\n * () => sendMetrics(metrics),\n * { context: 'metrics-report', attempts: 2 }\n * );\n * ```\n */\nexport function fireAndForgetRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> & { context: string },\n): void {\n void withRetry(fn, {\n ...options,\n attempts: options.attempts ?? 2,\n }).catch((error) => {\n logger.warn(\n { error, context: options.context },\n 'Fire-and-forget retry also failed โ€” giving up silently',\n );\n });\n}\n\n/**\n * Builds a retry-enabled version of any async function.\n * The returned function will automatically retry on retryable errors.\n *\n * @example\n * ```typescript\n * const safeReadFile = withRetryOn(\n * (path: string) => readFile(path, 'utf8'),\n * { attempts: 3, delayMs: 200, context: 'file-read' }\n * );\n *\n * const content = await safeReadFile('/path/to/file.txt');\n * ```\n */\nexport function withRetryOn<T extends (...args: never[]) => Promise<unknown>>(\n fn: T,\n options: Partial<RetryOptions> & { context: string },\n): T {\n return ((...args: Parameters<T>) => withRetry(() => fn(...args), options)) as T;\n}\n","/**\n * @file src/core/safety.ts\n * @description Type-safe extraction helpers for working with untyped record data.\n *\n * AISnitch often deals with loosely-typed payloads:\n * - Hook payloads from third-party tools (Claude Code, OpenCode, etc.)\n * - JSONL transcript observations parsed from raw JSON\n * - Config files loaded from disk\n * - Event data fields that may be undefined\n *\n * This module provides:\n * - `getString()` / `getNumber()` / `getBoolean()` โ€” safe extractors with type narrowing\n * - `getStringOrDefault()` / `getNumberOrDefault()` โ€” with fallback defaults\n * - `getArray()` / `getObject()` โ€” structural validation\n * - `getSafeInteger()` โ€” integer with bounds checking\n * - `getPositiveNumber()` โ€” positive values only\n * - `isValidPort()` โ€” network port validation (1-65535)\n * - `isValidPathLength()` โ€” POSIX path limit check (4096 chars)\n * - `isValidStringLength()` โ€” max string length check\n *\n * ## Why not just use optional chaining?\n *\n * Optional chaining (`?.`) protects against null/undefined access chains, but it:\n * - Does NOT validate the type of the value (e.g., `obj.key` could be `string | number | null`)\n * - Does NOT enforce constraints (e.g., port range, string max length)\n * - Does NOT normalize values (e.g., trimming strings, clamping numbers)\n *\n * These helpers do all of the above in one call.\n *\n * @functions\n * โ†’ getString\n * โ†’ getNumber\n * โ†’ getBoolean\n * โ†’ getSafeInteger\n * โ†’ getPositiveNumber\n * โ†’ isValidPort\n * โ†’ isValidPathLength\n * โ†’ isValidStringLength\n * โ†’ getArray\n * โ†’ getObject\n * @exports getString, getNumber, getBoolean, getSafeInteger, getPositiveNumber, isValidPort, isValidPathLength, isValidStringLength, getArray, getObject\n * @see ./errors.ts\n * @see ./result.ts\n */\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Constants\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Maximum valid TCP/UDP port number.\n * Ports below 1024 require root privileges on Unix.\n */\nexport const MAX_PORT = 65_535;\n\n/**\n * Minimum valid TCP/UDP port number.\n */\nexport const MIN_PORT = 1;\n\n/**\n * Maximum path length per POSIX (NAME_MAX).\n * Most filesystems support 255 bytes per path component, but the total path\n * can grow much longer. 4096 is a safe upper bound for in-memory validation.\n */\nexport const MAX_PATH_LENGTH = 4_096;\n\n/**\n * Maximum string length for most AISnitch fields (file paths, model names, etc.).\n * Beyond this, truncation or rejection is safer than silent truncation.\n */\nexport const MAX_GENERIC_STRING_LENGTH = 10_000;\n\n/**\n * Maximum length for short labels (tool names, session IDs, event types).\n * These should always be kept short for display.\n */\nexport const MAX_LABEL_LENGTH = 255;\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// String extractors\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a non-empty trimmed string from a record field.\n *\n * @example\n * ```typescript\n * const model = getString(payload, 'model');\n * // โ†’ 'claude-sonnet-4-20250514' | undefined\n * ```\n */\nexport function getString(\n record: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = record[key];\n\n if (typeof value !== 'string') {\n return undefined;\n }\n\n const trimmed = value.trim();\n\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Extracts a string and enforces a maximum length.\n * If the string exceeds `maxLength`, it is truncated to that length.\n *\n * @example\n * ```typescript\n * const truncated = getStringWithMaxLength(payload, 'errorMessage', 10_000);\n * ```\n */\nexport function getStringWithMaxLength(\n record: Record<string, unknown>,\n key: string,\n maxLength: number,\n): string | undefined {\n const value = getString(record, key);\n\n if (value === undefined) {\n return undefined;\n }\n\n return value.length > maxLength ? value.slice(0, maxLength) : value;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Number extractors\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a finite number from a record field.\n *\n * Filters out `NaN`, `Infinity`, `-Infinity`.\n *\n * @example\n * ```typescript\n * const pid = getNumber(payload, 'pid');\n * // โ†’ 12345 | undefined\n * ```\n */\nexport function getNumber(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = record[key];\n\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return undefined;\n }\n\n return value;\n}\n\n/**\n * Extracts a finite integer within a range.\n *\n * @example\n * ```typescript\n * const seqnum = getSafeInteger(payload, 'seqnum', { min: 1 });\n * // โ†’ 42 | undefined\n * ```\n */\nexport function getSafeInteger(\n record: Record<string, unknown>,\n key: string,\n options: { min?: number; max?: number } = {},\n): number | undefined {\n const value = getNumber(record, key);\n\n if (value === undefined) {\n return undefined;\n }\n\n // Must be an integer (Math.floor === self for whole numbers)\n if (!Number.isInteger(value)) {\n return undefined;\n }\n\n if (options.min !== undefined && value < options.min) {\n return undefined;\n }\n\n if (options.max !== undefined && value > options.max) {\n return undefined;\n }\n\n return value;\n}\n\n/**\n * Extracts a positive number ( > 0).\n *\n * @example\n * ```typescript\n * const tokens = getPositiveNumber(payload, 'tokensUsed');\n * // โ†’ 1500 | undefined (rejects 0, negative)\n * ```\n */\nexport function getPositiveNumber(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = getNumber(record, key);\n\n return value !== undefined && value > 0 ? value : undefined;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Boolean extractor\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a boolean from a record field.\n *\n * Handles the common \"stringified boolean\" pattern where config files\n * or query parameters store booleans as strings ('true', 'false').\n *\n * @example\n * ```typescript\n * const enabled = getBoolean(record, 'enabled');\n * // โ†’ true | false | undefined\n * ```\n */\nexport function getBoolean(\n record: Record<string, unknown>,\n key: string,\n): boolean | undefined {\n const value = record[key];\n\n if (typeof value === 'boolean') {\n return value;\n }\n\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n\n if (lower === 'true' || lower === '1') {\n return true;\n }\n\n if (lower === 'false' || lower === '0') {\n return false;\n }\n }\n\n return undefined;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Structural validators\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts an array from a record field.\n *\n * @example\n * ```typescript\n * const parts = getArray(payload, 'content');\n * // โ†’ unknown[] | undefined\n * ```\n */\nexport function getArray<T = unknown>(\n record: Record<string, unknown>,\n key: string,\n): T[] | undefined {\n const value = record[key];\n\n return Array.isArray(value) ? (value as T[]) : undefined;\n}\n\n/**\n * Extracts a plain object from a record field.\n *\n * Returns `undefined` for arrays, class instances, `null`, primitives.\n *\n * @example\n * ```typescript\n * const toolInput = getObject(payload, 'tool_input');\n * // โ†’ Record<string, unknown> | undefined\n * ```\n */\nexport function getObject(\n record: Record<string, unknown>,\n key: string,\n): Record<string, unknown> | undefined {\n const value = record[key];\n\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return undefined;\n }\n\n return value as Record<string, unknown>;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Common constraint validators\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Validates whether a port number is within the valid TCP/UDP range (1-65535).\n *\n * @example\n * ```typescript\n * const port = getSafeInteger(payload, 'port', { min: 1, max: 65535 });\n * if (isValidPort(port)) {\n * server.listen(port);\n * }\n * ```\n */\nexport function isValidPort(port: number | undefined): port is number {\n return (\n port !== undefined &&\n Number.isInteger(port) &&\n port >= MIN_PORT &&\n port <= MAX_PORT\n );\n}\n\n/**\n * Validates whether a path string is within the POSIX NAME_MAX limit.\n *\n * Uses the conservative 4096-character limit (actual NAME_MAX varies by FS).\n * This check is useful for in-memory validation before file system operations.\n *\n * @example\n * ```typescript\n * const filePath = getString(payload, 'filePath');\n * if (filePath && isValidPathLength(filePath)) {\n * readFile(filePath);\n * }\n * ```\n */\nexport function isValidPathLength(path: string | undefined): path is string {\n return path !== undefined && path.length > 0 && path.length <= MAX_PATH_LENGTH;\n}\n\n/**\n * Validates whether a string does not exceed a maximum length.\n *\n * @example\n * ```typescript\n * const message = getString(payload, 'errorMessage');\n * if (message && isValidStringLength(message, 10_000)) {\n * log(message);\n * }\n * ```\n */\nexport function isValidStringLength(\n value: string | undefined,\n maxLength: number,\n): value is string {\n return value !== undefined && value.length <= maxLength;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Record predicate helpers\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Checks whether a value is a plain object (not null, not array, not class instance).\n *\n * Uses `Object.prototype.toString` to detect class instances:\n * - Plain objects return `'[object Object]'`\n * - Class instances return `'[object ClassName]'`\n *\n * @example\n * ```typescript\n * if (isRecord(payload)) {\n * const value = payload[key]; // TypeScript narrows to Record<string, unknown>\n * }\n * ```\n */\nexport function isRecord(\n value: unknown,\n): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n\n // Exclude class instances (Date, Map, Set, etc.)\n const proto = Object.prototype.toString.call(value);\n return proto === '[object Object]';\n}\n\n/**\n * Type guard to narrow any `unknown` to a non-null value.\n *\n * @example\n * ```typescript\n * const cleaned = value != null ? value : defaultValue;\n * // or using the guard:\n * if (isNotNull(value)) { ... }\n * ```\n */\nexport function isNotNull<T>(value: T): value is T & NonNullable<unknown> {\n return value != null;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Bounded value extractors (shortcuts for common patterns)\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a port number with full validation (in range, integer, finite).\n *\n * @example\n * ```typescript\n * const port = getPort(record, 'httpPort');\n * // โ†’ 4821 | undefined\n * ```\n */\nexport function getPort(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = getSafeInteger(record, key, { min: MIN_PORT, max: MAX_PORT });\n\n return value;\n}\n\n/**\n * Extracts a sequence number (positive integer >= 1).\n *\n * @example\n * ```typescript\n * const seqnum = getSeqnum(record, 'seqnum');\n * // โ†’ 42 | undefined\n * ```\n */\nexport function getSeqnum(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n return getSafeInteger(record, key, { min: 1 });\n}\n","import React from 'react';\nimport { render } from 'ink';\nimport { withFullScreen } from 'fullscreen-ink';\nimport WebSocket from 'ws';\n\nimport { AISNITCH_VERSION } from '../package-info.js';\nimport type { EventBus, PipelineStatus, ToolName } from '../core/index.js';\nimport { App } from './App.js';\nimport { ManagedDaemonApp } from './ManagedDaemonApp.js';\nimport type { ManagedTuiSnapshot, TuiInitialFilters } from './types.js';\n\n/**\n * @file src/tui/index.tsx\n * @description Foreground Ink renderer entrypoint plus barrel exports for TUI modules.\n * @functions\n * โ†’ renderForegroundTui\n * @exports renderForegroundTui and all TUI modules\n * @see ./App.tsx\n * @see ./live-monitor.ts\n * @see ../../tasks/05-tui/01_tui_foundation-layout_DONE.md\n */\n\n/**\n * Props required to render the foreground TUI.\n */\nexport interface ForegroundTuiOptions {\n readonly configuredAdapters: readonly ToolName[];\n readonly eventBus: EventBus;\n readonly initialFilters?: TuiInitialFilters;\n readonly onQuit?: () => void;\n readonly status: PipelineStatus;\n}\n\n/**\n * Props required to render the attached WebSocket TUI.\n */\nexport interface AttachedTuiOptions {\n readonly configuredAdapters: readonly ToolName[];\n readonly initialFilters?: TuiInitialFilters;\n readonly onQuit?: () => void;\n readonly status: {\n readonly consumerCount: number;\n readonly eventCount: number;\n readonly uptimeMs: number;\n };\n readonly wsUrl: string;\n}\n\n/**\n * Props required by the managed daemon dashboard renderer.\n */\nexport interface ManagedTuiOptions {\n readonly initialFilters?: TuiInitialFilters;\n readonly initialSnapshot: ManagedTuiSnapshot;\n readonly onQuit?: () => void;\n readonly refreshSnapshot: () => Promise<ManagedTuiSnapshot>;\n readonly toggleDaemon: () => Promise<ManagedTuiSnapshot>;\n}\n\n/**\n * Renders the foreground Ink TUI and resolves once the app exits.\n */\nexport async function renderForegroundTui(\n options: ForegroundTuiOptions,\n): Promise<void> {\n const ink = withFullScreen(\n <App\n configuredAdapters={options.configuredAdapters}\n initialFilters={options.initialFilters}\n onQuit={options.onQuit}\n source={{\n kind: 'event-bus',\n eventBus: options.eventBus,\n }}\n status={{\n connected: true,\n connectionLabel: 'Foreground Bus',\n consumerCount: options.status.websocket.consumerCount,\n eventCount: options.status.eventBus.publishedEvents,\n uptimeMs: options.status.uptimeMs,\n }}\n version={AISNITCH_VERSION}\n />,\n );\n\n await ink.start();\n await ink.waitUntilExit;\n}\n\n/**\n * Renders the TUI against a remote AISnitch daemon over WebSocket.\n */\nexport async function renderAttachedTui(\n options: AttachedTuiOptions,\n): Promise<void> {\n const socket = new WebSocket(options.wsUrl);\n const app = render(\n <App\n configuredAdapters={options.configuredAdapters}\n initialFilters={options.initialFilters}\n onQuit={options.onQuit}\n source={{\n kind: 'websocket',\n socket,\n }}\n status={{\n connected: true,\n connectionLabel: 'Attached Stream',\n consumerCount: options.status.consumerCount,\n eventCount: options.status.eventCount,\n uptimeMs: options.status.uptimeMs,\n }}\n version={AISNITCH_VERSION}\n />,\n );\n\n try {\n await app.waitUntilExit();\n } finally {\n if (\n socket.readyState === WebSocket.OPEN ||\n socket.readyState === WebSocket.CONNECTING\n ) {\n socket.close();\n }\n }\n}\n\n/**\n * Renders the PM2-style dashboard that can start/stop and attach to the daemon.\n */\nexport async function renderManagedTui(\n options: ManagedTuiOptions,\n): Promise<void> {\n const app = render(\n <ManagedDaemonApp\n initialFilters={options.initialFilters}\n initialSnapshot={options.initialSnapshot}\n onQuit={options.onQuit}\n refreshSnapshot={options.refreshSnapshot}\n toggleDaemon={options.toggleDaemon}\n version={AISNITCH_VERSION}\n />,\n );\n\n await app.waitUntilExit();\n}\n\nexport * from './App.js';\nexport * from './ManagedDaemonApp.js';\nexport * from './types.js';\nexport * from './filters.js';\nexport * from './theme.js';\nexport * from './live-monitor.js';\nexport * from './hooks/useEventStream.js';\nexport * from './hooks/useKeyBinds.js';\nexport * from './hooks/useSessions.js';\nexport * from './components/EventLine.js';\nexport * from './components/EventStream.js';\nexport * from './components/FilterBar.js';\nexport * from './components/GlobalBadge.js';\nexport * from './components/Header.js';\nexport * from './components/HelpOverlay.js';\nexport * from './components/Layout.js';\nexport * from './components/SessionPanel.js';\nexport * from './components/StatusBar.js';\n","import React, { useEffect, useState } from 'react';\nimport { Box, useApp, useStdout } from 'ink';\n\nimport type { ToolName } from '../core/index.js';\nimport { EventInspector } from './components/EventInspector.js';\nimport { EventStream } from './components/EventStream.js';\nimport { FilterBar } from './components/FilterBar.js';\nimport { Header } from './components/Header.js';\nimport { HelpOverlay } from './components/HelpOverlay.js';\nimport { Panel, PanelStack } from './components/Layout.js';\nimport { SessionPanel } from './components/SessionPanel.js';\nimport { StatusBar } from './components/StatusBar.js';\nimport {\n applyEventFilters,\n applySessionFilters,\n countActiveFilters,\n} from './filters.js';\nimport { buildEventInspectorLines } from './event-inspector.js';\nimport { TUI_THEME } from './theme.js';\nimport type { TuiInitialFilters, TuiStatusSnapshot } from './types.js';\nimport {\n getPendingFrozenEventCount,\n getVisibleEventWindow,\n type EventStreamSource,\n useEventStream,\n} from './hooks/useEventStream.js';\nimport { useKeyBinds } from './hooks/useKeyBinds.js';\nimport {\n deriveGlobalActivityStatus,\n useSessions,\n} from './hooks/useSessions.js';\n\n/**\n * @file src/tui/App.tsx\n * @description Root Ink application for the AISnitch terminal UI foundation, including layout chrome and live summary state.\n * @functions\n * โ†’ App\n * @exports App, type AppProps\n * @see ./index.tsx\n * @see ./hooks/useEventStream.ts\n * @see ./components/EventStream.tsx\n * @see ./components/Header.tsx\n * @see ./components/Layout.tsx\n * @see ./components/StatusBar.tsx\n */\n\n/**\n * Props injected by the foreground runtime renderer.\n */\nexport interface AppProps {\n readonly configuredAdapters: readonly ToolName[];\n readonly initialFilters?: TuiInitialFilters;\n readonly managerControls?: {\n readonly onRefreshStatus: () => Promise<void> | void;\n readonly onToggleDaemon: () => Promise<void> | void;\n };\n readonly onQuit?: () => void;\n readonly source: EventStreamSource;\n readonly status: TuiStatusSnapshot;\n readonly version: string;\n}\n\n/**\n * ๐Ÿ“– This first TUI pass focuses on shape and feel: strong header, framed\n * panels, responsive composition, and just enough live state to prove the\n * foreground runtime is now a real terminal app instead of a raw log stream.\n */\nexport function App({\n configuredAdapters,\n initialFilters,\n managerControls,\n onQuit,\n source,\n status,\n version,\n}: AppProps): React.JSX.Element {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const [columns, setColumns] = useState(stdout.columns ?? 80);\n const [rows, setRows] = useState(stdout.rows ?? 24);\n const [inspectorLineOffset, setInspectorLineOffset] = useState(0);\n const [selectedEventIndex, setSelectedEventIndex] = useState<number | null>(\n null,\n );\n const [uptimeMs, setUptimeMs] = useState(status.uptimeMs);\n const initialTuiFilters = {\n eventType: initialFilters?.type ?? null,\n query: initialFilters?.query ?? '',\n tool: initialFilters?.tool ?? null,\n };\n const initialFullDataMode = initialFilters?.view === 'full-data';\n\n useEffect(() => {\n const handleResize = (): void => {\n setColumns(stdout.columns ?? 80);\n setRows(stdout.rows ?? 24);\n };\n\n stdout.on('resize', handleResize);\n\n return () => {\n stdout.off('resize', handleResize);\n };\n }, [stdout]);\n\n const compactLayout = columns < 112;\n const eventStream = useEventStream(\n source,\n {\n initialTotalEvents: status.eventCount,\n visibleCount: compactLayout ? 4 : 6,\n },\n );\n const sessions = useSessions(eventStream.bufferedEvents);\n const [frozenFilteredEventCount, setFrozenFilteredEventCount] = useState<\n number | null\n >(null);\n const inspectorVisibleLineCount = Math.max(\n 10,\n compactLayout ? rows - 22 : rows - 18,\n );\n const keyBinds = useKeyBinds({\n fullDataModeEnabled: initialFullDataMode,\n initialFilters: initialTuiFilters,\n onClearStream: () => {\n eventStream.clearEvents();\n setFrozenFilteredEventCount(null);\n setSelectedEventIndex(null);\n setInspectorLineOffset(0);\n },\n onInspectorPageScroll: (delta) => {\n setInspectorLineOffset((currentValue) =>\n Math.max(0, currentValue + delta * inspectorVisibleLineCount),\n );\n },\n onInspectorScroll: (delta) => {\n setInspectorLineOffset((currentValue) =>\n Math.max(0, currentValue + delta),\n );\n },\n onQuit: () => {\n onQuit?.();\n exit();\n },\n onSelectNextEvent: () => {\n setSelectedEventIndex((currentValue) => {\n if (displayedEvents.length === 0) {\n return null;\n }\n\n return Math.min(\n displayedEvents.length - 1,\n (currentValue ?? displayedEvents.length - 1) + 1,\n );\n });\n },\n onSelectPreviousEvent: () => {\n setSelectedEventIndex((currentValue) => {\n if (displayedEvents.length === 0) {\n return null;\n }\n\n return Math.max(0, (currentValue ?? displayedEvents.length - 1) - 1);\n });\n },\n onToggleFreeze: () => {\n const nextFrozen = !eventStream.isFrozen;\n\n eventStream.toggleFrozen();\n setFrozenFilteredEventCount(nextFrozen ? displayedEvents.length : null);\n },\n onToggleFullDataMode: () => {\n setInspectorLineOffset(0);\n },\n onRefreshStatus: managerControls?.onRefreshStatus,\n onToggleDaemon: managerControls?.onToggleDaemon,\n toolOptions: configuredAdapters,\n });\n const displayedEvents = applyEventFilters(\n eventStream.bufferedEvents,\n keyBinds.filters,\n );\n const fullDataModeEnabled = keyBinds.viewMode === 'full-data';\n const displayedSessions = applySessionFilters(sessions, keyBinds.filters);\n const safeSelectedEventIndex =\n displayedEvents.length === 0\n ? null\n : Math.min(\n selectedEventIndex ?? displayedEvents.length - 1,\n displayedEvents.length - 1,\n );\n const selectedEvent =\n safeSelectedEventIndex === null\n ? null\n : displayedEvents[safeSelectedEventIndex] ?? null;\n const inspectorLines =\n selectedEvent === null ? [] : buildEventInspectorLines(selectedEvent);\n const maxInspectorLineOffset = Math.max(\n 0,\n inspectorLines.length - inspectorVisibleLineCount,\n );\n const pendingFilteredEvents = eventStream.isFrozen\n ? getPendingFrozenEventCount(\n displayedEvents.length,\n frozenFilteredEventCount,\n )\n : 0;\n const visibleEvents = getVisibleEventWindow(displayedEvents, {\n anchorIndex: fullDataModeEnabled ? safeSelectedEventIndex : null,\n frozenAtTotalEvents: eventStream.isFrozen ? frozenFilteredEventCount : null,\n totalEvents: displayedEvents.length,\n visibleCount: compactLayout ? 4 : 6,\n });\n const globalStatus = deriveGlobalActivityStatus(displayedSessions);\n const activeFilterCount = countActiveFilters(keyBinds.filters);\n\n useEffect(() => {\n const startedAt = Date.now() - status.uptimeMs;\n const uptimeTimer = setInterval(() => {\n setUptimeMs(Date.now() - startedAt);\n }, 1_000);\n uptimeTimer.unref();\n\n return () => {\n clearInterval(uptimeTimer);\n };\n }, [status.uptimeMs]);\n\n useEffect(() => {\n if (eventStream.isFrozen) {\n setFrozenFilteredEventCount(displayedEvents.length);\n }\n }, [\n displayedEvents.length,\n eventStream.isFrozen,\n keyBinds.filters.eventType,\n keyBinds.filters.query,\n keyBinds.filters.tool,\n ]);\n\n useEffect(() => {\n if (displayedEvents.length === 0) {\n setSelectedEventIndex(null);\n return;\n }\n\n if (!fullDataModeEnabled) {\n setSelectedEventIndex(displayedEvents.length - 1);\n return;\n }\n\n setSelectedEventIndex((currentValue) => {\n if (currentValue === null) {\n return displayedEvents.length - 1;\n }\n\n return Math.min(currentValue, displayedEvents.length - 1);\n });\n }, [displayedEvents.length, fullDataModeEnabled]);\n\n useEffect(() => {\n setInspectorLineOffset(0);\n }, [selectedEvent?.id]);\n\n useEffect(() => {\n setInspectorLineOffset((currentValue) =>\n Math.min(currentValue, maxInspectorLineOffset),\n );\n }, [maxInspectorLineOffset]);\n\n return (\n <Box flexDirection=\"column\">\n <Header\n adapterCount={configuredAdapters.length}\n columns={columns}\n connectionLabel={status.connectionLabel}\n connected={status.connected}\n daemon={status.daemon}\n globalStatus={globalStatus}\n version={version}\n />\n <FilterBar\n filters={keyBinds.filters}\n focusPanel={keyBinds.focusPanel}\n interaction={keyBinds.interaction}\n viewMode={keyBinds.viewMode}\n />\n {keyBinds.interaction.kind === 'help' ? <HelpOverlay /> : null}\n <Box marginTop={1}>\n <PanelStack compact={compactLayout}>\n <Panel\n accentColor={TUI_THEME.warning}\n focused={keyBinds.focusPanel === 'events'}\n title=\"Event Stream\"\n >\n <EventStream\n emptyState={\n eventStream.bufferedEvents.length === 0 ? 'no-events' : 'no-match'\n }\n events={visibleEvents}\n frozen={eventStream.isFrozen}\n pendingEventCount={pendingFilteredEvents}\n selectedEventId={selectedEvent?.id ?? null}\n />\n </Panel>\n <Panel\n accentColor={fullDataModeEnabled ? TUI_THEME.warning : TUI_THEME.success}\n focused={keyBinds.focusPanel === 'sessions'}\n title={fullDataModeEnabled ? 'Full Data Inspector' : 'Sessions'}\n >\n {fullDataModeEnabled ? (\n <EventInspector\n event={selectedEvent}\n lineOffset={inspectorLineOffset}\n selectedEventIndex={safeSelectedEventIndex}\n totalEventCount={displayedEvents.length}\n visibleLineCount={inspectorVisibleLineCount}\n />\n ) : (\n <SessionPanel sessions={displayedSessions} />\n )}\n </Panel>\n </PanelStack>\n </Box>\n <Box marginTop={1}>\n <StatusBar\n activeFilterCount={activeFilterCount}\n adapterCount={configuredAdapters.length}\n columns={columns}\n connected={status.connected}\n consumerCount={status.consumerCount}\n daemon={status.daemon}\n eventCount={eventStream.totalEvents}\n focusPanel={keyBinds.focusPanel}\n latestEvent={displayedEvents.at(-1) ?? eventStream.latestEvent}\n pendingEventCount={pendingFilteredEvents}\n streamFrozen={eventStream.isFrozen}\n uptimeMs={uptimeMs}\n viewMode={keyBinds.viewMode}\n />\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { AISnitchEvent } from '../../core/index.js';\nimport {\n buildEventInspectorLines,\n getVisibleInspectorWindow,\n} from '../event-inspector.js';\nimport { TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/EventInspector.tsx\n * @description Scrollable full-data event inspector for the Ink TUI, rendering colorful metadata and the complete selected payload.\n * @functions\n * โ†’ EventInspector\n * @exports EventInspector, type EventInspectorProps\n * @see ../event-inspector.ts\n * @see ../App.tsx\n */\n\n/**\n * Props required by the full-data inspector panel.\n */\nexport interface EventInspectorProps {\n readonly event: AISnitchEvent | null;\n readonly lineOffset: number;\n readonly selectedEventIndex: number | null;\n readonly totalEventCount: number;\n readonly visibleLineCount: number;\n}\n\n/**\n * Renders the currently selected event with a colorful, scrollable full-data view.\n */\nexport function EventInspector({\n event,\n lineOffset,\n selectedEventIndex,\n totalEventCount,\n visibleLineCount,\n}: EventInspectorProps): React.JSX.Element {\n if (event === null || selectedEventIndex === null) {\n return (\n <Box flexDirection=\"column\">\n <Text color={TUI_THEME.panelTitle}>\n No event selected yet.\n </Text>\n <Text color={TUI_THEME.muted}>\n Press [v] to open full-data mode, then use [โ†‘/โ†“] on the event panel to pick one event.\n </Text>\n </Box>\n );\n }\n\n const inspectorLines = buildEventInspectorLines(event);\n const visibleLines = getVisibleInspectorWindow(inspectorLines, {\n lineOffset,\n visibleLineCount,\n });\n const hiddenAbove = Math.max(0, lineOffset);\n const hiddenBelow = Math.max(\n 0,\n inspectorLines.length - (lineOffset + visibleLines.length),\n );\n\n return (\n <Box flexDirection=\"column\">\n <Text color={TUI_THEME.panelBody}>\n {`Selected ${selectedEventIndex + 1}/${totalEventCount} โ€ข ${inspectorLines.length} lines โ€ข [v] close โ€ข [โ†‘/โ†“] scroll โ€ข [[/]] page`}\n </Text>\n {hiddenAbove > 0 ? (\n <Text color={TUI_THEME.muted}>\n {`โ†‘ ${hiddenAbove} line${hiddenAbove === 1 ? '' : 's'} above`}\n </Text>\n ) : null}\n {visibleLines.map((line, lineIndex) => (\n <Text key={`${event.id}:${lineOffset + lineIndex}`}>\n {line.length === 0 || line.every((segment) => segment.text.length === 0)\n ? ' '\n : line.map((segment, segmentIndex) => (\n <Text\n key={`${event.id}:${lineOffset + lineIndex}:${segmentIndex}`}\n bold={segment.bold}\n color={segment.color}\n >\n {segment.text}\n </Text>\n ))}\n </Text>\n ))}\n {hiddenBelow > 0 ? (\n <Text color={TUI_THEME.muted}>\n {`โ†“ ${hiddenBelow} line${hiddenBelow === 1 ? '' : 's'} below`}\n </Text>\n ) : null}\n </Box>\n );\n}\n","import type { AISnitchEvent } from '../core/events/types.js';\n\n/**\n * @file src/tui/event-details.ts\n * @description Shared event-detail extraction for the Ink stream and plain-text monitor output.\n * @functions\n * โ†’ formatEventDetail\n * โ†’ getEventDetailSegments\n * @exports formatEventDetail, getEventDetailSegments\n * @see ./components/EventLine.tsx\n * @see ./live-monitor.ts\n */\n\nconst DETAIL_SEGMENT_LIMIT = 120;\n\n/**\n * ๐Ÿ“– The adapters already stash richer source-native payloads in `data.raw`.\n * This helper squeezes the high-signal parts back out into short human-readable\n * fragments so operators can see prompts, thinking, tool targets, and streamed\n * assistant text without opening raw JSON.\n */\nexport function formatEventDetail(event: AISnitchEvent): string | null {\n const segments = getEventDetailSegments(event);\n\n return segments.length > 0 ? segments.join(' | ') : null;\n}\n\n/**\n * Returns stable, truncated detail segments for one event.\n */\nexport function getEventDetailSegments(event: AISnitchEvent): string[] {\n const raw = getRecord(event.data.raw);\n const segments: Array<string | undefined> = [];\n\n switch (event.type) {\n case 'agent.tool_call':\n case 'agent.coding':\n segments.push(formatToolSegment(event));\n segments.push(formatModelSegment(event.data.model));\n segments.push(formatTokenSegment(event.data.tokensUsed));\n break;\n\n case 'agent.thinking':\n segments.push(formatThinkingSegment(raw));\n segments.push(formatModelSegment(event.data.model));\n segments.push(formatTokenSegment(event.data.tokensUsed));\n segments.push(event.data.activeFile ?? event.data.cwd);\n break;\n\n case 'agent.streaming':\n segments.push(formatStreamingSegment(raw));\n segments.push(formatModelSegment(event.data.model));\n segments.push(formatTokenSegment(event.data.tokensUsed));\n segments.push(event.data.activeFile ?? event.data.cwd);\n break;\n\n case 'task.start':\n segments.push(formatPromptSegment(raw));\n segments.push(event.data.projectPath ?? event.data.project ?? event.data.cwd);\n break;\n\n case 'task.complete':\n segments.push(\n event.data.duration !== undefined\n ? `duration ${event.data.duration}ms`\n : undefined,\n );\n segments.push(formatTokenSegment(event.data.tokensUsed));\n segments.push(event.data.activeFile ?? event.data.projectPath ?? event.data.cwd);\n break;\n\n case 'agent.error':\n segments.push(event.data.errorType);\n segments.push(event.data.errorMessage);\n break;\n\n case 'agent.compact':\n segments.push('context compaction');\n segments.push(event.data.projectPath ?? event.data.cwd);\n break;\n\n case 'agent.asking_user':\n segments.push(\n getString(raw, 'notification_type') ??\n getString(raw, 'notificationType') ??\n getString(raw, 'type'),\n );\n segments.push(event.data.errorMessage ?? extractLooseString(raw, [\n 'message',\n 'reason',\n ]));\n break;\n\n case 'agent.idle':\n segments.push(event.data.activeFile ?? event.data.projectPath ?? event.data.cwd);\n break;\n\n case 'session.start':\n case 'session.end':\n segments.push(event.data.projectPath ?? event.data.project ?? event.data.cwd);\n segments.push(formatModelSegment(event.data.model));\n break;\n\n default:\n break;\n }\n\n return segments\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .map((value) => truncateSegment(value));\n}\n\nfunction formatToolSegment(event: AISnitchEvent): string | undefined {\n const toolName = event.data.toolName;\n const filePath = event.data.toolInput?.filePath ?? event.data.activeFile;\n const command = event.data.toolInput?.command;\n\n if (!toolName && !filePath && !command) {\n return undefined;\n }\n\n const label = toolName ?? 'tool';\n\n if (filePath && command) {\n return `${label}: ${filePath} | cmd ${command}`;\n }\n\n if (filePath) {\n return `${label}: ${filePath}`;\n }\n\n if (command) {\n return `${label}: ${command}`;\n }\n\n return label;\n}\n\nfunction formatThinkingSegment(\n raw: Record<string, unknown> | undefined,\n): string | undefined {\n const snippet =\n extractContentPart(raw, 'thinking', 'thinking') ??\n extractLooseString(raw, ['thinking', 'message']);\n\n return snippet ? `thinking: ${snippet}` : undefined;\n}\n\nfunction formatStreamingSegment(\n raw: Record<string, unknown> | undefined,\n): string | undefined {\n const snippet =\n extractContentPart(raw, 'text', 'text') ??\n extractLooseString(raw, ['message', 'text', 'content']);\n\n return snippet ? `reply: ${snippet}` : undefined;\n}\n\nfunction formatPromptSegment(\n raw: Record<string, unknown> | undefined,\n): string | undefined {\n const snippet = extractLooseString(raw, [\n 'prompt',\n 'query',\n 'message',\n 'text',\n 'content',\n ]);\n\n return snippet ? `prompt: ${snippet}` : undefined;\n}\n\nfunction formatModelSegment(model: string | undefined): string | undefined {\n return model ? `model ${model}` : undefined;\n}\n\nfunction formatTokenSegment(tokensUsed: number | undefined): string | undefined {\n return tokensUsed !== undefined ? `${tokensUsed.toLocaleString('en-US')} tok` : undefined;\n}\n\nfunction extractContentPart(\n raw: Record<string, unknown> | undefined,\n partType: string,\n valueKey: string,\n): string | undefined {\n if (!raw) {\n return undefined;\n }\n\n const message = getRecord(raw.message);\n const content = message?.content ?? raw.content;\n\n if (!Array.isArray(content)) {\n return undefined;\n }\n\n for (const part of content) {\n const record = getRecord(part);\n\n if (!record || getString(record, 'type') !== partType) {\n continue;\n }\n\n const value = getString(record, valueKey);\n\n if (value) {\n return value;\n }\n }\n\n return undefined;\n}\n\nfunction extractLooseString(\n raw: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!raw) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(raw, key);\n\n if (directValue) {\n return directValue;\n }\n\n const nestedRecord = getRecord(raw[key]);\n const nestedValue =\n getString(nestedRecord, 'text') ??\n getString(nestedRecord, 'message') ??\n getString(nestedRecord, 'content');\n\n if (nestedValue) {\n return nestedValue;\n }\n }\n\n return undefined;\n}\n\nfunction truncateSegment(value: string): string {\n const normalized = value.replace(/\\s+/gu, ' ').trim();\n\n if (normalized.length <= DETAIL_SEGMENT_LIMIT) {\n return normalized;\n }\n\n return `${normalized.slice(0, DETAIL_SEGMENT_LIMIT - 1)}โ€ฆ`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n","import type { AISnitchEventType, ToolName } from '../core/index.js';\n\n/**\n * @file src/tui/theme.ts\n * @description Shared color palette and presentation constants for the Ink-based AISnitch terminal UI.\n * @functions\n * โ†’ none\n * @exports TOOL_COLORS, EVENT_COLORS, TUI_THEME, type TuiThemeColor\n * @see ./App.tsx\n * @see ./components/Header.tsx\n * @see ./components/StatusBar.tsx\n */\n\n/**\n * Hex color string used across the terminal UI theme.\n */\nexport type TuiThemeColor = `#${string}`;\n\n/**\n * ๐Ÿ“– Tools keep distinct colors so operators can scan mixed activity without\n * having to read every label in a busy stream.\n */\nexport const TOOL_COLORS: Record<ToolName, TuiThemeColor> = {\n 'aider': '#14b8a6',\n 'amp': '#fb7185',\n 'augment-code': '#c084fc',\n 'claude-code': '#f59e0b',\n 'cline': '#f43f5e',\n 'codex': '#f97316',\n 'continue': '#06b6d4',\n 'copilot-cli': '#60a5fa',\n 'cursor': '#8b5cf6',\n 'devin': '#f59e0b',\n 'gemini-cli': '#38bdf8',\n 'goose': '#ec4899',\n 'kilo': '#84cc16',\n 'kiro': '#06b6d4',\n 'mistral': '#fb923c',\n 'openhands': '#facc15',\n 'openclaw': '#ef4444',\n 'opencode': '#10b981',\n 'pi': '#1db954',\n 'qwen-code': '#22c55e',\n 'unknown': '#94a3b8',\n 'windsurf': '#a855f7',\n 'zed': '#e85d04',\n};\n\n/**\n * Event types get their own accents so state changes read as a visual rhythm.\n */\nexport const EVENT_COLORS: Record<AISnitchEventType, TuiThemeColor> = {\n 'agent.asking_user': '#ef4444',\n 'agent.coding': '#22c55e',\n 'agent.compact': '#f97316',\n 'agent.error': '#ef4444',\n 'agent.idle': '#64748b',\n 'agent.streaming': '#22d3ee',\n 'agent.thinking': '#facc15',\n 'agent.tool_call': '#fb7185',\n 'session.end': '#94a3b8',\n 'session.start': '#10b981',\n 'task.complete': '#34d399',\n 'task.start': '#60a5fa',\n};\n\n/**\n * Global palette used for layout chrome and section accents.\n */\nexport const TUI_THEME = {\n background: '#111827',\n border: '#1f2937',\n danger: '#ef4444',\n footer: '#0f172a',\n frame: '#334155',\n headerGradient: ['#f59e0b', '#fb7185', '#22d3ee'] as const,\n muted: '#94a3b8',\n panelBody: '#e2e8f0',\n panelTitle: '#f8fafc',\n success: '#22c55e',\n warning: '#facc15',\n} as const;\n","import { formatSessionLabelFromEvent, type AISnitchEvent } from '../core/index.js';\nimport { formatEventDetail } from './event-details.js';\nimport { EVENT_COLORS, TOOL_COLORS, TUI_THEME, type TuiThemeColor } from './theme.js';\n\n/**\n * @file src/tui/event-inspector.ts\n * @description Visual full-data formatter for the TUI event inspector, including colorful metadata rows and syntax-highlighted JSON blocks.\n * @functions\n * โ†’ buildEventInspectorLines\n * โ†’ getVisibleInspectorWindow\n * @exports InspectorSegment, InspectorLine, buildEventInspectorLines, getVisibleInspectorWindow\n * @see ./components/EventInspector.tsx\n * @see ./App.tsx\n */\n\nconst JSON_TOKEN_PATTERN =\n /(\"(?:\\\\.|[^\"])*\"(?=\\s*:))|(\"(?:\\\\.|[^\"])*\")|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|[[\\]{}:,]/gu;\n\n/**\n * Small token model rendered by the Ink inspector component.\n */\nexport interface InspectorSegment {\n readonly bold?: boolean;\n readonly color?: TuiThemeColor;\n readonly text: string;\n}\n\n/**\n * One rendered line inside the full-data inspector.\n */\nexport type InspectorLine = readonly InspectorSegment[];\n\n/**\n * ๐Ÿ“– The inspector deliberately mixes curated metadata with raw pretty JSON.\n * Operators get a friendly summary first, then the complete payload without\n * needing to mentally decode one enormous unstyled blob.\n */\nexport function buildEventInspectorLines(\n event: AISnitchEvent,\n): readonly InspectorLine[] {\n const eventColor = EVENT_COLORS[event.type];\n const toolColor = TOOL_COLORS[event['aisnitch.tool']];\n const sessionLabel = formatSessionLabelFromEvent(event);\n const detailSummary = formatEventDetail(event);\n const normalizedData = removeRawPayload(event.data);\n const rawPayload = event.data.raw ?? {\n note: 'No adapter raw payload was attached to this event.',\n };\n\n return [\n [\n { color: eventColor, text: 'โ—‰ ' },\n {\n bold: true,\n color: eventColor,\n text: event.type,\n },\n { color: TUI_THEME.muted, text: ' ' },\n { bold: true, color: toolColor, text: `[${event['aisnitch.tool']}]` },\n ],\n [\n { color: TUI_THEME.muted, text: 'session ' },\n { color: TUI_THEME.panelBody, text: sessionLabel },\n { color: TUI_THEME.muted, text: ' โ€ข ' },\n { color: TUI_THEME.panelBody, text: formatEventTimestamp(event.time) },\n { color: TUI_THEME.muted, text: ' โ€ข seq ' },\n { color: TUI_THEME.panelBody, text: `#${event['aisnitch.seqnum']}` },\n ],\n [\n { color: TUI_THEME.warning, text: 'โ”โ” Spotlight โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildOptionalKeyValueLines([\n ['summary', detailSummary],\n ['project', event.data.projectPath ?? event.data.project],\n ['cwd', event.data.cwd],\n ['active_file', event.data.activeFile],\n ['command', event.data.toolInput?.command],\n ['model', event.data.model],\n [\n 'tokens',\n event.data.tokensUsed !== undefined\n ? `${event.data.tokensUsed.toLocaleString('en-US')} tok`\n : undefined,\n ],\n ['terminal', event.data.terminal],\n ['pid', event.data.pid],\n [\n 'instance',\n event.data.instanceIndex !== undefined &&\n event.data.instanceTotal !== undefined\n ? `${event.data.instanceIndex}/${event.data.instanceTotal}`\n : event.data.instanceId,\n ],\n ]),\n [{ text: '' }],\n [\n { color: TUI_THEME.warning, text: 'โ”โ” Envelope โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildKeyValueLines([\n ['id', event.id],\n ['source', event.source],\n ['specversion', event.specversion],\n ['seq', String(event['aisnitch.seqnum'])],\n ['session_id', event['aisnitch.sessionid']],\n ['tool', event['aisnitch.tool']],\n ['time', event.time],\n ['type', event.type],\n ]),\n [{ text: '' }],\n [\n { color: TUI_THEME.success, text: 'โ”โ” Normalized Data โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildJsonLines(normalizedData),\n [{ text: '' }],\n [\n { color: TUI_THEME.warning, text: 'โ”โ” Raw Source Payload โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildJsonLines(rawPayload),\n ];\n}\n\n/**\n * Returns the visible scroll window for inspector lines.\n */\nexport function getVisibleInspectorWindow(\n lines: readonly InspectorLine[],\n options: {\n readonly lineOffset: number;\n readonly visibleLineCount: number;\n },\n): readonly InspectorLine[] {\n const safeLineOffset = Math.max(0, options.lineOffset);\n const safeVisibleLineCount = Math.max(1, options.visibleLineCount);\n\n return lines.slice(safeLineOffset, safeLineOffset + safeVisibleLineCount);\n}\n\nfunction buildKeyValueLines(\n entries: readonly (readonly [string, unknown])[],\n): readonly InspectorLine[] {\n return entries.map(([key, value]) => [\n { color: TUI_THEME.muted, text: ' ' },\n { color: '#7dd3fc', text: `${key}: ` },\n { color: TUI_THEME.panelBody, text: formatKeyValue(value) },\n ]);\n}\n\nfunction buildOptionalKeyValueLines(\n entries: readonly (readonly [string, unknown])[],\n): readonly InspectorLine[] {\n return buildKeyValueLines(\n entries.filter((entry): entry is readonly [string, unknown] => {\n const [, value] = entry;\n\n return hasDisplayValue(value);\n }),\n );\n}\n\nfunction buildJsonLines(value: unknown): readonly InspectorLine[] {\n const prettyJson = JSON.stringify(value, null, 2);\n\n if (!prettyJson) {\n return [[{ color: TUI_THEME.muted, text: ' (empty)' }]];\n }\n\n return prettyJson.split('\\n').map((line) => highlightJsonLine(line));\n}\n\nfunction highlightJsonLine(line: string): InspectorLine {\n if (line.length === 0) {\n return [{ text: '' }];\n }\n\n const segments: InspectorSegment[] = [];\n let lastIndex = 0;\n\n for (const match of line.matchAll(JSON_TOKEN_PATTERN)) {\n const matchedValue = match[0];\n const matchIndex = match.index ?? 0;\n\n if (matchIndex > lastIndex) {\n segments.push({\n color: TUI_THEME.panelBody,\n text: line.slice(lastIndex, matchIndex),\n });\n }\n\n segments.push({\n color: resolveJsonTokenColor(matchedValue, match),\n text: matchedValue,\n });\n lastIndex = matchIndex + matchedValue.length;\n }\n\n if (lastIndex < line.length) {\n segments.push({\n color: TUI_THEME.panelBody,\n text: line.slice(lastIndex),\n });\n }\n\n return segments.length > 0\n ? segments\n : [{ color: TUI_THEME.panelBody, text: line }];\n}\n\nfunction resolveJsonTokenColor(\n token: string,\n match: RegExpMatchArray,\n): TuiThemeColor {\n if (match[1]) {\n return '#7dd3fc';\n }\n\n if (match[2]) {\n return '#86efac';\n }\n\n if (token === 'true' || token === 'false') {\n return '#c084fc';\n }\n\n if (token === 'null') {\n return TUI_THEME.muted;\n }\n\n if (/^-?\\d/u.test(token)) {\n return '#fb923c';\n }\n\n return TUI_THEME.muted;\n}\n\nfunction removeRawPayload(\n data: AISnitchEvent['data'],\n): Record<string, unknown> {\n const { raw: _raw, ...normalizedData } = data;\n\n return normalizedData;\n}\n\nfunction formatKeyValue(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n\n if (value === null || value === undefined) {\n return 'n/a';\n }\n\n return JSON.stringify(value);\n}\n\nfunction hasDisplayValue(value: unknown): boolean {\n if (value === undefined || value === null) {\n return false;\n }\n\n if (typeof value === 'string') {\n return value.length > 0;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n return Object.keys(value).length > 0;\n}\n\nfunction formatEventTimestamp(timestamp: string): string {\n return new Intl.DateTimeFormat('en-GB', {\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n month: '2-digit',\n second: '2-digit',\n }).format(new Date(timestamp));\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { AISnitchEvent } from '../../core/index.js';\nimport { TUI_THEME } from '../theme.js';\nimport { EventLine } from './EventLine.js';\n\n/**\n * @file src/tui/components/EventStream.tsx\n * @description Live event stream panel content for the Ink TUI, rendering the visible event window and frozen-state hints.\n * @functions\n * โ†’ EventStream\n * @exports EventStream, type EventStreamProps\n * @see ./EventLine.tsx\n * @see ../hooks/useEventStream.ts\n */\n\n/**\n * Props accepted by the live event stream component.\n */\nexport interface EventStreamProps {\n readonly emptyState?: 'no-events' | 'no-match';\n readonly events: readonly AISnitchEvent[];\n readonly frozen: boolean;\n readonly pendingEventCount: number;\n readonly selectedEventId?: string | null;\n}\n\n/**\n * Renders the current visible portion of the live event stream.\n */\nexport function EventStream({\n emptyState = 'no-events',\n events,\n frozen,\n pendingEventCount,\n selectedEventId = null,\n}: EventStreamProps): React.JSX.Element {\n if (events.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text color={TUI_THEME.panelTitle}>\n {emptyState === 'no-events'\n ? 'No events yet. Start with Claude Code or OpenCode and the foreground bus will light up here.'\n : 'No buffered events match the current filters.'}\n </Text>\n <Text color={TUI_THEME.muted}>\n {emptyState === 'no-events'\n ? 'Use [f], [t], [/], and [?] to shape the live view once events start flowing.'\n : 'Change the active filters or clear them with Esc.'}\n </Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {events.map((event) => (\n <EventLine\n key={event.id}\n event={event}\n selected={selectedEventId === event.id}\n />\n ))}\n <Text color={TUI_THEME.muted}>\n {frozen\n ? `Frozen tail: ${pendingEventCount} newer ${\n pendingEventCount === 1 ? 'event is' : 'events are'\n } buffered.`\n : 'Live tail: newest events stay in view automatically.'}\n </Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport {\n formatSessionLabelFromEvent,\n type AISnitchEvent,\n type AISnitchEventType,\n} from '../../core/index.js';\nimport { formatEventDetail } from '../event-details.js';\nimport { EVENT_COLORS, TOOL_COLORS, TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/EventLine.tsx\n * @description Single formatted event row for the Ink live stream, including icon mapping, timestamp formatting, and optional detail output.\n * @functions\n * โ†’ EventLine\n * โ†’ formatEventTime\n * โ†’ formatEventDetail\n * @exports EVENT_ICONS, EventLine, formatEventTime, formatEventDetail\n * @see ./EventStream.tsx\n * @see ../hooks/useEventStream.ts\n */\n\n/**\n * ๐Ÿ“– The stream gets much easier to scan when each normalized state has a\n * stable visual marker instead of relying on color alone.\n */\nexport const EVENT_ICONS: Record<AISnitchEventType, string> = {\n 'session.start': '๐Ÿš€',\n 'session.end': '๐Ÿ‘‹',\n 'task.start': '๐Ÿ“',\n 'task.complete': 'โœ…',\n 'agent.thinking': '๐Ÿค”',\n 'agent.coding': 'โŒจ๏ธ',\n 'agent.tool_call': '๐Ÿ”ง',\n 'agent.streaming': '๐Ÿ’ฌ',\n 'agent.asking_user': 'โœ‹',\n 'agent.idle': '๐Ÿ’ค',\n 'agent.error': 'โŒ',\n 'agent.compact': '๐Ÿง ',\n};\n\n/**\n * Props required to render one formatted event row.\n */\nexport interface EventLineProps {\n readonly event: AISnitchEvent;\n readonly selected?: boolean;\n}\n\n/**\n * Renders a single event row plus its optional detail line.\n */\nexport function EventLine({\n event,\n selected = false,\n}: EventLineProps): React.JSX.Element {\n const detail = formatEventDetail(event);\n const sessionLabel = formatSessionLabelFromEvent(event);\n\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text color={selected ? TUI_THEME.warning : TUI_THEME.muted}>\n {selected ? 'โ€บ' : ' '}\n </Text>\n <Text> </Text>\n <Text color={TUI_THEME.muted}>{formatEventTime(event.time)}</Text>\n <Text> </Text>\n <Text>{EVENT_ICONS[event.type]}</Text>\n <Text> </Text>\n <Text color={TOOL_COLORS[event['aisnitch.tool']]}>\n [{event['aisnitch.tool']}]\n </Text>\n <Text> </Text>\n <Text bold color={EVENT_COLORS[event.type]}>\n {event.type}\n </Text>\n {sessionLabel !== event['aisnitch.tool'] ? (\n <>\n <Text color={TUI_THEME.muted}> ยท </Text>\n <Text color={TUI_THEME.muted}>{sessionLabel}</Text>\n </>\n ) : null}\n </Box>\n {detail ? (\n <Box marginLeft={4}>\n <Text color={selected ? TUI_THEME.panelBody : TUI_THEME.muted}>\n โ””โ”€ {detail}\n </Text>\n </Box>\n ) : null}\n </Box>\n );\n}\n\n/**\n * Converts an ISO timestamp into a compact wall-clock string.\n */\nexport function formatEventTime(timestamp: string): string {\n return new Intl.DateTimeFormat('en-GB', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n }).format(new Date(timestamp));\n}\nexport { formatEventDetail } from '../event-details.js';\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport { countActiveFilters, type TuiFilters } from '../filters.js';\nimport type {\n FocusedPanel,\n TuiInteractionMode,\n} from '../hooks/useKeyBinds.js';\nimport { TUI_THEME } from '../theme.js';\nimport type { TuiViewMode } from '../types.js';\n\n/**\n * @file src/tui/components/FilterBar.tsx\n * @description Filter and command prompt bar for the AISnitch TUI, showing active filters, focus, and current interaction mode.\n * @functions\n * โ†’ FilterBar\n * @exports FilterBar, type FilterBarProps\n * @see ../hooks/useKeyBinds.ts\n * @see ../filters.ts\n * @see ../App.tsx\n */\n\n/**\n * Props accepted by the TUI filter bar.\n */\nexport interface FilterBarProps {\n readonly filters: TuiFilters;\n readonly focusPanel: FocusedPanel;\n readonly interaction: TuiInteractionMode;\n readonly viewMode: TuiViewMode;\n}\n\n/**\n * Renders the currently active filters and the inline prompt state.\n */\nexport function FilterBar({\n filters,\n focusPanel,\n interaction,\n viewMode,\n}: FilterBarProps): React.JSX.Element {\n const activeFilterCount = countActiveFilters(filters);\n const focusLabel =\n focusPanel === 'events'\n ? 'events'\n : viewMode === 'full-data'\n ? 'inspector'\n : 'sessions';\n\n return (\n <Box\n borderColor={TUI_THEME.border}\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginTop={1}\n paddingX={1}\n >\n <Text color={TUI_THEME.panelBody}>\n {`Focus ${focusLabel} | View ${viewMode} | Active filters ${activeFilterCount} | ${formatFilterSummary(\n filters,\n )}`}\n </Text>\n <Text color={TUI_THEME.muted}>\n {formatInteractionHint(interaction, focusPanel, viewMode)}\n </Text>\n </Box>\n );\n}\n\nfunction formatFilterSummary(filters: TuiFilters): string {\n const parts = [\n filters.tool ? `tool=${filters.tool}` : null,\n filters.eventType ? `type=${filters.eventType}` : null,\n filters.query.trim().length > 0 ? `search=\"${filters.query}\"` : null,\n ].filter((value): value is string => value !== null);\n\n return parts.length > 0 ? parts.join(' | ') : 'no filters active';\n}\n\nfunction formatInteractionHint(\n interaction: TuiInteractionMode,\n focusPanel: FocusedPanel,\n viewMode: TuiViewMode,\n): string {\n switch (interaction.kind) {\n case 'tool-filter':\n return `Tool filter > ${\n interaction.options[interaction.selectedIndex]?.label ?? 'All tools'\n } (โ†‘/โ†“ select, Enter apply, Esc clear)`;\n case 'type-filter':\n return `Type filter > ${\n interaction.options[interaction.selectedIndex]?.label ?? 'All event types'\n } (โ†‘/โ†“ select, Enter apply, Esc clear)`;\n case 'search':\n return `Search > ${interaction.draft}`;\n case 'help':\n return 'Help open (? or Esc to close)';\n default:\n if (viewMode === 'full-data') {\n return focusPanel === 'events'\n ? 'Commands: [v] summary [โ†‘/โ†“ or j/k] select event [Tab] inspector [f/t//] filters'\n : 'Commands: [v] summary [โ†‘/โ†“ or j/k] scroll [[/]] page [Tab] events';\n }\n\n return 'Commands: [v] full-data [f] tool [t] type [/] search [Esc] clear filters [Tab] focus';\n }\n}\n","import type {\n AISnitchEvent,\n AISnitchEventType,\n ToolName,\n} from '../core/index.js';\nimport { formatEventDetail } from './event-details.js';\n\n/**\n * @file src/tui/filters.ts\n * @description Pure filtering helpers shared by the TUI event stream, session panel, and CLI pre-filter handling.\n * @functions\n * โ†’ applyEventFilters\n * โ†’ applySessionFilters\n * โ†’ countActiveFilters\n * @exports TuiFilters, SessionFilterTarget, DEFAULT_TUI_FILTERS, applyEventFilters, applySessionFilters, countActiveFilters\n * @see ./App.tsx\n * @see ./hooks/useKeyBinds.ts\n * @see ./hooks/useSessions.ts\n */\n\n/**\n * Global filter state applied across the TUI.\n */\nexport interface TuiFilters {\n readonly eventType: AISnitchEventType | null;\n readonly query: string;\n readonly tool: ToolName | null;\n}\n\n/**\n * Structural session shape accepted by the generic session filter helper.\n */\nexport interface SessionFilterTarget {\n readonly activeFile?: string;\n readonly currentState: AISnitchEventType;\n readonly cwd?: string;\n readonly displayLabel?: string;\n readonly project?: string;\n readonly projectPath?: string;\n readonly sessionId: string;\n readonly shortSessionId?: string;\n readonly tool: ToolName;\n}\n\n/**\n * Default empty filter state used by the TUI.\n */\nexport const DEFAULT_TUI_FILTERS: TuiFilters = {\n eventType: null,\n query: '',\n tool: null,\n};\n\n/**\n * Filters buffered events by tool, event type, and free-text search.\n */\nexport function applyEventFilters(\n events: readonly AISnitchEvent[],\n filters: TuiFilters,\n): readonly AISnitchEvent[] {\n return events.filter((event) => {\n if (filters.tool !== null && event['aisnitch.tool'] !== filters.tool) {\n return false;\n }\n\n if (filters.eventType !== null && event.type !== filters.eventType) {\n return false;\n }\n\n if (!matchesTextQuery(getEventSearchFields(event), filters.query)) {\n return false;\n }\n\n return true;\n });\n}\n\n/**\n * Filters active sessions using the same global TUI filter state.\n */\nexport function applySessionFilters<T extends SessionFilterTarget>(\n sessions: readonly T[],\n filters: TuiFilters,\n): readonly T[] {\n return sessions.filter((session) => {\n if (filters.tool !== null && session.tool !== filters.tool) {\n return false;\n }\n\n if (filters.eventType !== null && session.currentState !== filters.eventType) {\n return false;\n }\n\n if (\n !matchesTextQuery(\n [\n session.sessionId,\n session.tool,\n session.currentState,\n session.displayLabel,\n session.project,\n session.projectPath,\n session.cwd,\n session.activeFile,\n session.shortSessionId,\n ],\n filters.query,\n )\n ) {\n return false;\n }\n\n return true;\n });\n}\n\n/**\n * Counts how many filter categories are currently active.\n */\nexport function countActiveFilters(filters: TuiFilters): number {\n let count = 0;\n\n if (filters.tool !== null) {\n count += 1;\n }\n\n if (filters.eventType !== null) {\n count += 1;\n }\n\n if (filters.query.trim().length > 0) {\n count += 1;\n }\n\n return count;\n}\n\nfunction getEventSearchFields(event: AISnitchEvent): readonly (string | undefined)[] {\n return [\n event['aisnitch.tool'],\n event.type,\n event['aisnitch.sessionid'],\n formatEventDetail(event) ?? undefined,\n event.data.toolName,\n event.data.toolInput?.filePath,\n event.data.toolInput?.command,\n event.data.activeFile,\n event.data.errorMessage,\n event.data.cwd,\n event.data.project,\n event.data.projectPath,\n ];\n}\n\nfunction matchesTextQuery(\n values: readonly (string | undefined)[],\n query: string,\n): boolean {\n const normalizedQuery = query.trim().toLowerCase();\n\n if (normalizedQuery.length === 0) {\n return true;\n }\n\n return values.some((value) => value?.toLowerCase().includes(normalizedQuery));\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport BigText from 'ink-big-text';\nimport Gradient from 'ink-gradient';\nimport Spinner from 'ink-spinner';\n\nimport type { GlobalActivityStatus } from '../hooks/useSessions.js';\nimport { TUI_THEME } from '../theme.js';\nimport type { TuiDaemonSnapshot } from '../types.js';\nimport { GlobalBadge } from './GlobalBadge.js';\n\n/**\n * @file src/tui/components/Header.tsx\n * @description Header chrome for the AISnitch TUI, including title treatment and connection status badge.\n * @functions\n * โ†’ Header\n * @exports Header, type HeaderProps\n * @see ../App.tsx\n * @see ./StatusBar.tsx\n */\n\n/**\n * Props accepted by the header component.\n */\nexport interface HeaderProps {\n readonly adapterCount: number;\n readonly columns: number;\n readonly connectionLabel: string;\n readonly connected: boolean;\n readonly daemon?: TuiDaemonSnapshot;\n readonly globalStatus: GlobalActivityStatus;\n readonly version: string;\n}\n\n/**\n * ๐Ÿ“– The header does the \"vitrine\" job from the spec: bold title treatment,\n * a little theater, and the essential runtime badges in one glance.\n */\nexport function Header({\n adapterCount,\n columns,\n connectionLabel,\n connected,\n daemon,\n globalStatus,\n version,\n}: HeaderProps): React.JSX.Element {\n const showBigTitle = columns >= 88;\n const daemonBusyAction = daemon?.busyAction ?? null;\n\n return (\n <Box\n borderColor={TUI_THEME.border}\n borderStyle=\"round\"\n flexDirection=\"column\"\n paddingX={1}\n paddingY={0}\n >\n <Box justifyContent=\"space-between\">\n <Text color={TUI_THEME.muted}>memory-only live bridge</Text>\n <Text color={TUI_THEME.muted}>v{version}</Text>\n </Box>\n <Box justifyContent=\"space-between\">\n <Box flexDirection=\"column\" flexGrow={1}>\n {showBigTitle ? (\n <Gradient colors={[...TUI_THEME.headerGradient]}>\n <BigText font=\"tiny\" text=\"AISnitch\" />\n </Gradient>\n ) : (\n <Gradient colors={[...TUI_THEME.headerGradient]}>\n <Text bold> AISnitch </Text>\n </Gradient>\n )}\n <Text color={TUI_THEME.muted}>\n live AI tool telemetry with adapter-driven normalization\n </Text>\n </Box>\n <Box\n alignItems=\"flex-end\"\n flexDirection=\"column\"\n marginLeft={2}\n minWidth={38}\n >\n <Box>\n {daemon ? (\n daemonBusyAction ? (\n <>\n <Text bold color={TUI_THEME.warning}>\n <Spinner type=\"dots\" />\n </Text>\n <Text color={TUI_THEME.warning}>\n {' '}\n daemon {daemonBusyAction}\n </Text>\n </>\n ) : daemon.active ? (\n <Text bold color={TUI_THEME.success}>\n โ— Daemon active ยท PID {daemon.pid ?? 'none'}\n </Text>\n ) : (\n <Text bold color={TUI_THEME.warning}>\n โ—‹ Daemon not active\n </Text>\n )\n ) : connected ? (\n <Text bold color={TUI_THEME.success}>\n โ— Connected ยท {connectionLabel}\n </Text>\n ) : (\n <>\n <Text bold color={TUI_THEME.warning}>\n <Spinner type=\"dots\" />\n </Text>\n <Text color={TUI_THEME.warning}> reconnecting</Text>\n </>\n )}\n </Box>\n {daemon ? (\n <>\n <Text color={connected ? TUI_THEME.success : TUI_THEME.warning}>\n {connected ? `โ— ${connectionLabel}` : `โ—‹ ${connectionLabel}`}\n </Text>\n <Text color={TUI_THEME.muted}>WS {daemon.wsUrl}</Text>\n </>\n ) : null}\n <GlobalBadge status={globalStatus} />\n <Text color={TUI_THEME.muted}>{adapterCount} adapters armed</Text>\n </Box>\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Text } from 'ink';\n\nimport type { GlobalActivityStatus } from '../hooks/useSessions.js';\nimport { TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/GlobalBadge.tsx\n * @description Compact activity badge for the TUI header, summarizing whether the system is idle, busy, or waiting on the user.\n * @functions\n * โ†’ GlobalBadge\n * @exports GlobalBadge, type GlobalBadgeProps\n * @see ./Header.tsx\n * @see ../hooks/useSessions.ts\n */\n\n/**\n * Props accepted by the global activity badge.\n */\nexport interface GlobalBadgeProps {\n readonly status: GlobalActivityStatus;\n}\n\n/**\n * Renders the high-level activity badge displayed in the TUI header.\n */\nexport function GlobalBadge({\n status,\n}: GlobalBadgeProps): React.JSX.Element {\n switch (status) {\n case 'action-required':\n return (\n <Text bold color={TUI_THEME.danger}>\n โœ‹ Action Required\n </Text>\n );\n case 'working':\n return (\n <Text bold color={TUI_THEME.warning}>\n โœฆ Working\n </Text>\n );\n default:\n return (\n <Text bold color={TUI_THEME.success}>\n โ—‡ Ready\n </Text>\n );\n }\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport { TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/HelpOverlay.tsx\n * @description Compact help overlay listing the current AISnitch TUI keybinds.\n * @functions\n * โ†’ HelpOverlay\n * @exports HelpOverlay\n * @see ../hooks/useKeyBinds.ts\n * @see ../App.tsx\n */\n\nconst HELP_LINES = [\n 'q / Ctrl+C quit cleanly',\n 'v toggle full-data inspector',\n 'f filter by tool',\n 't filter by event type',\n '/ free-text search',\n 'Esc clear filters',\n 'Space freeze or resume stream',\n 'c clear buffered stream',\n 'โ†‘/โ†“ or j/k inspect-mode navigate / scroll',\n '[ / ] inspect-mode page scroll',\n '? toggle help',\n 'Tab cycle focused panel',\n];\n\n/**\n * Renders the help box shown above the main panels.\n */\nexport function HelpOverlay(): React.JSX.Element {\n return (\n <Box\n borderColor={TUI_THEME.warning}\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginTop={1}\n paddingX={1}\n >\n <Text bold color={TUI_THEME.panelTitle}>\n Keybinds\n </Text>\n {HELP_LINES.map((line) => (\n <Text key={line} color={TUI_THEME.panelBody}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport { TUI_THEME, type TuiThemeColor } from '../theme.js';\n\n/**\n * @file src/tui/components/Layout.tsx\n * @description Reusable layout primitives for bordered panels and responsive panel stacks in the AISnitch TUI.\n * @functions\n * โ†’ Panel\n * โ†’ PanelStack\n * @exports Panel, PanelStack, type PanelProps, type PanelStackProps\n * @see ../App.tsx\n * @see ./Header.tsx\n * @see ./StatusBar.tsx\n */\n\n/**\n * Props for a single framed panel.\n */\nexport interface PanelProps {\n readonly accentColor: TuiThemeColor;\n readonly children: React.ReactNode;\n readonly flexGrow?: number;\n readonly focused?: boolean;\n readonly title: string;\n}\n\n/**\n * Props for a responsive panel stack.\n */\nexport interface PanelStackProps {\n readonly children: React.ReactNode;\n readonly compact?: boolean;\n}\n\n/**\n * ๐Ÿ“– A thin panel primitive keeps the TUI consistent without hiding Ink's\n * flexbox model behind too much framework glue.\n */\nexport function Panel({\n accentColor,\n children,\n flexGrow = 1,\n focused = false,\n title,\n}: PanelProps): React.JSX.Element {\n return (\n <Box\n borderColor={focused ? accentColor : TUI_THEME.frame}\n borderStyle=\"round\"\n flexDirection=\"column\"\n flexGrow={flexGrow}\n minHeight={8}\n paddingX={1}\n paddingY={0}\n >\n <Box marginBottom={1}>\n <Text bold color={accentColor}>\n {title}\n </Text>\n </Box>\n <Box flexDirection=\"column\" flexGrow={1}>\n {children}\n </Box>\n </Box>\n );\n}\n\n/**\n * Renders the main body panels side by side on wide terminals and stacked on narrow ones.\n */\nexport function PanelStack({\n children,\n compact = false,\n}: PanelStackProps): React.JSX.Element {\n return (\n <Box\n columnGap={1}\n flexDirection={compact ? 'column' : 'row'}\n flexGrow={1}\n rowGap={1}\n >\n {children}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport Spinner from 'ink-spinner';\n\nimport type { SessionState } from '../hooks/useSessions.js';\nimport { TOOL_COLORS, TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/SessionPanel.tsx\n * @description Grouped active-session renderer for the AISnitch TUI, including state-specific visual cues and durations.\n * @functions\n * โ†’ SessionPanel\n * @exports SessionPanel, type SessionPanelProps\n * @see ../hooks/useSessions.ts\n * @see ../App.tsx\n */\n\n/**\n * Props accepted by the session panel renderer.\n */\nexport interface SessionPanelProps {\n readonly sessions: readonly SessionState[];\n}\n\n/**\n * ๐Ÿ“– Session grouping stays intentionally compact so operators can tell \"who\n * is doing what\" without the panel becoming wider than the event stream.\n */\nexport function SessionPanel({\n sessions,\n}: SessionPanelProps): React.JSX.Element {\n if (sessions.length === 0) {\n return (\n <Text color={TUI_THEME.muted}>\n No active sessions match the current view.\n </Text>\n );\n }\n\n const groupedSessions = groupSessionsByTool(sessions);\n\n return (\n <Box flexDirection=\"column\">\n {groupedSessions.map(([toolName, toolSessions]) => (\n <Box key={toolName} flexDirection=\"column\" marginBottom={1}>\n <Text bold color={TOOL_COLORS[toolName]}>\n {toolName} ({toolSessions.length})\n </Text>\n {toolSessions.map((session) => (\n <Box key={session.sessionId} flexDirection=\"column\" marginLeft={1}>\n <Text color={TOOL_COLORS[session.tool]}>\n โ— {session.displayLabel}\n </Text>\n {formatSessionLocation(session) ? (\n <Text color={TUI_THEME.muted}>\n {` โ†ณ ${formatSessionLocation(session)}`}\n </Text>\n ) : null}\n <Box marginLeft={2}>\n {renderStateLabel(session)}\n <Text color={TUI_THEME.muted}>\n {` ยท ${session.eventCount} events ยท ${formatDuration(session.durationMs)}`}\n </Text>\n {session.shortSessionId ? (\n <Text color={TUI_THEME.muted}>\n {` ยท sid ${session.shortSessionId}`}\n </Text>\n ) : null}\n </Box>\n </Box>\n ))}\n </Box>\n ))}\n </Box>\n );\n}\n\nfunction renderStateLabel(session: SessionState): React.JSX.Element {\n switch (session.currentState) {\n case 'agent.coding':\n return (\n <Text color={TUI_THEME.success}>\n <Spinner type=\"runner\" /> coding\n </Text>\n );\n case 'agent.thinking':\n return (\n <Text color={TUI_THEME.warning}>\n <Spinner type=\"dots\" /> thinking\n </Text>\n );\n case 'agent.asking_user':\n return (\n <Text bold color={TUI_THEME.danger}>\n โœ‹ asking_user\n </Text>\n );\n case 'agent.error':\n return (\n <Text bold color={TUI_THEME.danger}>\n โŒ error\n </Text>\n );\n case 'agent.idle':\n return <Text color={TUI_THEME.muted}>idle</Text>;\n default:\n return (\n <Text color={TUI_THEME.panelBody}>{session.currentState}</Text>\n );\n }\n}\n\nfunction groupSessionsByTool(\n sessions: readonly SessionState[],\n): readonly [SessionState['tool'], readonly SessionState[]][] {\n const groupedSessions = new Map<SessionState['tool'], SessionState[]>();\n\n for (const session of sessions) {\n const toolSessions = groupedSessions.get(session.tool) ?? [];\n\n toolSessions.push(session);\n groupedSessions.set(session.tool, toolSessions);\n }\n\n return [...groupedSessions.entries()];\n}\n\nfunction formatSessionLocation(session: SessionState): string | null {\n return session.activeFile ?? session.projectPath ?? session.cwd ?? null;\n}\n\nfunction formatDuration(durationMs: number): string {\n const totalSeconds = Math.max(0, Math.floor(durationMs / 1_000));\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n\n if (minutes === 0) {\n return `${seconds}s`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { AISnitchEvent } from '../../core/index.js';\nimport type { FocusedPanel } from '../hooks/useKeyBinds.js';\nimport { TUI_THEME } from '../theme.js';\nimport type { TuiDaemonSnapshot, TuiViewMode } from '../types.js';\n\n/**\n * @file src/tui/components/StatusBar.tsx\n * @description Footer status bar for runtime counts, uptime, and keybind hints in the AISnitch TUI.\n * @functions\n * โ†’ StatusBar\n * @exports StatusBar, type StatusBarProps\n * @see ../App.tsx\n */\n\n/**\n * Props accepted by the status bar component.\n */\nexport interface StatusBarProps {\n readonly activeFilterCount: number;\n readonly adapterCount: number;\n readonly columns: number;\n readonly connected: boolean;\n readonly consumerCount: number;\n readonly daemon?: TuiDaemonSnapshot;\n readonly eventCount: number;\n readonly focusPanel: FocusedPanel;\n readonly latestEvent: AISnitchEvent | null;\n readonly pendingEventCount?: number;\n readonly streamFrozen: boolean;\n readonly uptimeMs: number;\n readonly viewMode: TuiViewMode;\n}\n\n/**\n * Renders the lower chrome with lightweight stats and keyboard hints.\n */\nexport function StatusBar({\n activeFilterCount,\n adapterCount,\n columns,\n connected,\n consumerCount,\n daemon,\n eventCount,\n focusPanel,\n latestEvent,\n pendingEventCount = 0,\n streamFrozen,\n uptimeMs,\n viewMode,\n}: StatusBarProps): React.JSX.Element {\n const streamState = streamFrozen\n ? `Frozen +${pendingEventCount}`\n : latestEvent?.type ?? 'Live';\n const focusLabel =\n focusPanel === 'events'\n ? 'events'\n : viewMode === 'full-data'\n ? 'inspector'\n : 'sessions';\n const daemonLabel =\n daemon === undefined\n ? null\n : daemon.busyAction\n ? `Daemon ${daemon.busyAction}`\n : daemon.active\n ? `Daemon active ยท ${daemon.wsUrl}`\n : `Daemon not active ยท ${daemon.wsUrl}`;\n\n return (\n <Box\n borderColor={TUI_THEME.border}\n borderStyle=\"round\"\n flexDirection=\"column\"\n paddingX={1}\n paddingY={0}\n >\n <Text color={TUI_THEME.panelBody}>\n {`Events ${eventCount} | Adapters ${adapterCount} | Consumers ${consumerCount} | Filters ${activeFilterCount} | Focus ${focusLabel} | View ${viewMode} | Up ${formatUptime(\n uptimeMs,\n )} | ${streamState}${daemonLabel ? ` | ${daemonLabel}` : ''} | Size ${columns}c`}\n </Text>\n <Text color={TUI_THEME.muted}>\n {daemon\n ? connected\n ? `${\n daemon.active ? '[d] stop daemon' : '[d] start daemon'\n } [r] refresh ${\n streamFrozen\n ? '[space] resume [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n : '[space] freeze [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n }`\n : `${daemon.active ? '[d] stop daemon' : '[d] start daemon'} [r] refresh [v] full-data [q] quit [?] help`\n : connected\n ? streamFrozen\n ? '[space] resume [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n : '[space] freeze [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n : '[q] quit waiting for foreground bus'}\n </Text>\n </Box>\n );\n}\n\nfunction formatUptime(uptimeMs: number): string {\n const totalSeconds = Math.max(0, Math.floor(uptimeMs / 1_000));\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n\n if (minutes === 0) {\n return `${seconds}s`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n","import { useEffect, useState } from 'react';\nimport type { RawData, WebSocket } from 'ws';\n\nimport {\n AISnitchEventSchema,\n type AISnitchEvent,\n type EventBus,\n} from '../../core/index.js';\n\n/**\n * @file src/tui/hooks/useEventStream.ts\n * @description React hook and pure helpers for collecting, bounding, and freezing the live AISnitch event stream.\n * @functions\n * โ†’ useEventStream\n * โ†’ appendEventToStream\n * โ†’ getVisibleEventWindow\n * โ†’ getPendingFrozenEventCount\n * @exports EVENT_STREAM_LIMIT, EventStreamSource, UseEventStreamOptions, UseEventStreamState, useEventStream, appendEventToStream, getVisibleEventWindow, getPendingFrozenEventCount\n * @see ../components/EventStream.tsx\n * @see ../../core/engine/event-bus.ts\n * @see ../../core/engine/ws-server.ts\n */\n\n/**\n * Maximum number of live events kept in memory for the TUI stream.\n */\nexport const EVENT_STREAM_LIMIT = 500;\n\n/**\n * Default number of rendered events kept in the visible terminal window.\n */\nexport const DEFAULT_VISIBLE_EVENT_COUNT = 8;\n\n/**\n * Supported live sources for the event stream hook.\n */\nexport type EventStreamSource =\n | {\n readonly kind: 'event-bus';\n readonly eventBus: EventBus;\n }\n | {\n readonly kind: 'websocket';\n readonly socket: Pick<WebSocket, 'on' | 'off'>;\n };\n\n/**\n * Configuration accepted by the event stream hook.\n */\nexport interface UseEventStreamOptions {\n readonly initialTotalEvents?: number;\n readonly limit?: number;\n readonly visibleCount?: number;\n}\n\n/**\n * State returned by the live event stream hook.\n */\nexport interface UseEventStreamState {\n readonly bufferedEvents: readonly AISnitchEvent[];\n readonly clearEvents: () => void;\n readonly isFrozen: boolean;\n readonly latestEvent: AISnitchEvent | null;\n readonly pendingEventCount: number;\n readonly toggleFrozen: () => void;\n readonly totalEvents: number;\n readonly visibleEvents: readonly AISnitchEvent[];\n}\n\n/**\n * ๐Ÿ“– The hook owns stream mechanics so `App` can stay focused on layout and\n * panel composition instead of juggling buffer trimming, freeze anchors, and\n * source-specific subscription code.\n */\nexport function useEventStream(\n source: EventStreamSource,\n options: UseEventStreamOptions = {},\n): UseEventStreamState {\n const limit = options.limit ?? EVENT_STREAM_LIMIT;\n const visibleCount = options.visibleCount ?? DEFAULT_VISIBLE_EVENT_COUNT;\n const [bufferedEvents, setBufferedEvents] = useState<readonly AISnitchEvent[]>(\n [],\n );\n const [totalEvents, setTotalEvents] = useState(options.initialTotalEvents ?? 0);\n const [latestEvent, setLatestEvent] = useState<AISnitchEvent | null>(null);\n const [frozenAtTotalEvents, setFrozenAtTotalEvents] = useState<number | null>(\n null,\n );\n\n useEffect(() => {\n const unsubscribe = subscribeToEventStream(source, (event) => {\n setLatestEvent(event);\n setTotalEvents((currentValue) => currentValue + 1);\n setBufferedEvents((currentValue) =>\n appendEventToStream(currentValue, event, limit),\n );\n });\n\n return () => {\n unsubscribe();\n };\n }, [limit, source]);\n\n const pendingEventCount = getPendingFrozenEventCount(\n totalEvents,\n frozenAtTotalEvents,\n );\n const visibleEvents = getVisibleEventWindow(bufferedEvents, {\n totalEvents,\n frozenAtTotalEvents,\n visibleCount,\n });\n\n return {\n bufferedEvents,\n clearEvents: () => {\n setBufferedEvents([]);\n setFrozenAtTotalEvents(null);\n setLatestEvent(null);\n },\n isFrozen: frozenAtTotalEvents !== null,\n latestEvent,\n pendingEventCount,\n toggleFrozen: () => {\n setFrozenAtTotalEvents((currentValue) =>\n currentValue === null ? totalEvents : null,\n );\n },\n totalEvents,\n visibleEvents,\n };\n}\n\n/**\n * Appends a new event while keeping the TUI stream buffer size bounded.\n */\nexport function appendEventToStream(\n currentEvents: readonly AISnitchEvent[],\n event: AISnitchEvent,\n limit = EVENT_STREAM_LIMIT,\n): readonly AISnitchEvent[] {\n const nextEvents = [...currentEvents, event];\n\n if (nextEvents.length <= limit) {\n return nextEvents;\n }\n\n return nextEvents.slice(-limit);\n}\n\n/**\n * Calculates the currently visible event window, respecting frozen tail mode.\n */\nexport function getVisibleEventWindow(\n bufferedEvents: readonly AISnitchEvent[],\n options: {\n readonly anchorIndex?: number | null;\n readonly frozenAtTotalEvents?: number | null;\n readonly totalEvents: number;\n readonly visibleCount: number;\n },\n): readonly AISnitchEvent[] {\n if (options.anchorIndex !== undefined && options.anchorIndex !== null) {\n const clampedAnchorIndex = Math.max(\n 0,\n Math.min(options.anchorIndex, Math.max(0, bufferedEvents.length - 1)),\n );\n const halfWindow = Math.floor(options.visibleCount / 2);\n const tentativeStartIndex = Math.max(0, clampedAnchorIndex - halfWindow);\n const tentativeEndIndex = Math.min(\n bufferedEvents.length,\n tentativeStartIndex + options.visibleCount,\n );\n const visibleStartIndex = Math.max(\n 0,\n tentativeEndIndex - options.visibleCount,\n );\n\n return bufferedEvents.slice(visibleStartIndex, tentativeEndIndex);\n }\n\n const pendingEventCount = getPendingFrozenEventCount(\n options.totalEvents,\n options.frozenAtTotalEvents ?? null,\n );\n const visibleEndIndex =\n pendingEventCount === 0\n ? bufferedEvents.length\n : Math.max(0, bufferedEvents.length - pendingEventCount);\n const visibleStartIndex = Math.max(0, visibleEndIndex - options.visibleCount);\n\n return bufferedEvents.slice(visibleStartIndex, visibleEndIndex);\n}\n\n/**\n * Returns how many newer events are hidden while the stream is frozen.\n */\nexport function getPendingFrozenEventCount(\n totalEvents: number,\n frozenAtTotalEvents: number | null,\n): number {\n if (frozenAtTotalEvents === null) {\n return 0;\n }\n\n return Math.max(0, totalEvents - frozenAtTotalEvents);\n}\n\nfunction subscribeToEventStream(\n source: EventStreamSource,\n onEvent: (event: AISnitchEvent) => void,\n): () => void {\n if (source.kind === 'event-bus') {\n return source.eventBus.subscribe(onEvent);\n }\n\n const handleMessage = (data: RawData): void => {\n const parsedPayload = parseSocketPayload(data);\n\n if (parsedPayload !== null) {\n onEvent(parsedPayload);\n }\n };\n\n source.socket.on('message', handleMessage);\n\n return () => {\n source.socket.off('message', handleMessage);\n };\n}\n\nfunction parseSocketPayload(data: RawData): AISnitchEvent | null {\n const parsedPayload = parseUnknownPayload(data);\n\n if (\n typeof parsedPayload === 'object' &&\n parsedPayload !== null\n ) {\n const messageCandidate = parsedPayload as Record<string, unknown>;\n\n if (messageCandidate.type === 'welcome') {\n return null;\n }\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n return parsedEvent.success ? parsedEvent.data : null;\n}\n\nfunction parseUnknownPayload(data: RawData): unknown {\n try {\n if (typeof data === 'string') {\n return JSON.parse(data) as unknown;\n }\n\n if (Array.isArray(data)) {\n return JSON.parse(Buffer.concat(data).toString('utf8')) as unknown;\n }\n\n if (data instanceof ArrayBuffer) {\n return JSON.parse(\n Buffer.from(new Uint8Array(data)).toString('utf8'),\n ) as unknown;\n }\n\n return JSON.parse(Buffer.from(data).toString('utf8')) as unknown;\n } catch {\n // ๐Ÿ“– Malformed WebSocket frame โ€” return null instead of crashing\n return null;\n }\n}\n","import { useState, type Dispatch, type SetStateAction } from 'react';\nimport { useInput } from 'ink';\n\nimport {\n AISNITCH_EVENT_TYPES,\n type AISnitchEventType,\n type ToolName,\n} from '../../core/index.js';\nimport {\n DEFAULT_TUI_FILTERS,\n type TuiFilters,\n} from '../filters.js';\nimport type { TuiViewMode } from '../types.js';\n\n/**\n * @file src/tui/hooks/useKeyBinds.ts\n * @description Centralized keyboard controller for the AISnitch TUI, including filters, focus, help, and stream actions.\n * @functions\n * โ†’ useKeyBinds\n * @exports FocusedPanel, SelectorOption, TuiInteractionMode, UseKeyBindsOptions, UseKeyBindsState, useKeyBinds\n * @see ../components/FilterBar.tsx\n * @see ../components/HelpOverlay.tsx\n * @see ../App.tsx\n */\n\n/**\n * Panel focus ids supported by the current TUI.\n */\nexport type FocusedPanel = 'events' | 'sessions';\n\n/**\n * Generic selector option used by tool/type filter pickers.\n */\nexport interface SelectorOption<TValue> {\n readonly label: string;\n readonly value: TValue;\n}\n\n/**\n * Current interactive mode of the TUI.\n */\nexport type TuiInteractionMode =\n | {\n readonly kind: 'normal';\n }\n | {\n readonly kind: 'help';\n }\n | {\n readonly kind: 'search';\n readonly draft: string;\n }\n | {\n readonly kind: 'tool-filter';\n readonly options: readonly SelectorOption<ToolName | null>[];\n readonly selectedIndex: number;\n }\n | {\n readonly kind: 'type-filter';\n readonly options: readonly SelectorOption<AISnitchEventType | null>[];\n readonly selectedIndex: number;\n };\n\n/**\n * Inputs needed by the keyboard controller.\n */\nexport interface UseKeyBindsOptions {\n readonly fullDataModeEnabled?: boolean;\n readonly initialFilters?: Partial<TuiFilters>;\n readonly onClearStream: () => void;\n readonly onInspectorPageScroll?: (delta: number) => void;\n readonly onInspectorScroll?: (delta: number) => void;\n readonly onQuit?: () => void;\n readonly onRefreshStatus?: () => Promise<void> | void;\n readonly onSelectNextEvent?: () => void;\n readonly onSelectPreviousEvent?: () => void;\n readonly onToggleDaemon?: () => Promise<void> | void;\n readonly onToggleFreeze: () => void;\n readonly onToggleFullDataMode?: () => void;\n readonly toolOptions: readonly ToolName[];\n}\n\n/**\n * State returned by the keyboard controller.\n */\nexport interface UseKeyBindsState {\n readonly filters: TuiFilters;\n readonly focusPanel: FocusedPanel;\n readonly interaction: TuiInteractionMode;\n readonly viewMode: TuiViewMode;\n}\n\n/**\n * ๐Ÿ“– Keeping key handling in one hook prevents `App` from turning into a pile\n * of unrelated `useInput` branches as the TUI grows more interactive.\n */\nexport function useKeyBinds(\n options: UseKeyBindsOptions,\n): UseKeyBindsState {\n const toolOptions = buildToolOptions(options.toolOptions);\n const typeOptions = buildTypeOptions();\n const [filters, setFilters] = useState<TuiFilters>({\n ...DEFAULT_TUI_FILTERS,\n ...options.initialFilters,\n query: options.initialFilters?.query ?? '',\n });\n const [focusPanel, setFocusPanel] = useState<FocusedPanel>('events');\n const [interaction, setInteraction] = useState<TuiInteractionMode>({\n kind: 'normal',\n });\n const [viewMode, setViewMode] = useState<TuiViewMode>(\n options.fullDataModeEnabled === true ? 'full-data' : 'summary',\n );\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n options.onQuit?.();\n return;\n }\n\n if (interaction.kind === 'search') {\n if (key.escape) {\n clearFilters(setFilters, setInteraction);\n return;\n }\n\n if (key.return) {\n setInteraction({\n kind: 'normal',\n });\n return;\n }\n\n if (key.backspace || key.delete) {\n const nextDraft = interaction.draft.slice(0, -1);\n\n setFilters((currentValue) => ({\n ...currentValue,\n query: nextDraft,\n }));\n setInteraction({\n kind: 'search',\n draft: nextDraft,\n });\n return;\n }\n\n if (!key.ctrl && !key.meta && input.length > 0) {\n const nextDraft = `${interaction.draft}${input}`;\n\n setFilters((currentValue) => ({\n ...currentValue,\n query: nextDraft,\n }));\n setInteraction({\n kind: 'search',\n draft: nextDraft,\n });\n }\n\n return;\n }\n\n if (\n interaction.kind === 'tool-filter' ||\n interaction.kind === 'type-filter'\n ) {\n if (key.escape) {\n clearFilters(setFilters, setInteraction);\n return;\n }\n\n if (key.upArrow || input === 'k') {\n setInteraction(moveSelector(interaction, -1));\n return;\n }\n\n if (key.downArrow || input === 'j') {\n setInteraction(moveSelector(interaction, 1));\n return;\n }\n\n if (key.return) {\n if (interaction.kind === 'tool-filter') {\n setFilters((currentValue) => ({\n ...currentValue,\n tool: interaction.options[interaction.selectedIndex]?.value ?? null,\n }));\n } else {\n setFilters((currentValue) => ({\n ...currentValue,\n eventType:\n interaction.options[interaction.selectedIndex]?.value ?? null,\n }));\n }\n\n setInteraction({\n kind: 'normal',\n });\n }\n\n return;\n }\n\n if (interaction.kind === 'help') {\n if (input === 'q') {\n options.onQuit?.();\n return;\n }\n\n if (input === '?' || key.escape || key.return) {\n setInteraction({\n kind: 'normal',\n });\n }\n\n return;\n }\n\n if (input === 'q') {\n options.onQuit?.();\n return;\n }\n\n if (input === 'v') {\n const nextViewMode = viewMode === 'summary' ? 'full-data' : 'summary';\n\n options.onToggleFullDataMode?.();\n setViewMode(nextViewMode);\n\n if (nextViewMode === 'summary' && focusPanel === 'sessions') {\n setFocusPanel('events');\n }\n\n return;\n }\n\n if (input === ' ') {\n options.onToggleFreeze();\n return;\n }\n\n if (input === 'c') {\n options.onClearStream();\n return;\n }\n\n if (input === 'd' && options.onToggleDaemon) {\n void options.onToggleDaemon();\n return;\n }\n\n if (input === 'r' && options.onRefreshStatus) {\n void options.onRefreshStatus();\n return;\n }\n\n if (input === '?') {\n setInteraction({\n kind: 'help',\n });\n return;\n }\n\n if (input === 'f') {\n setInteraction({\n kind: 'tool-filter',\n options: toolOptions,\n selectedIndex: getSelectedIndex(toolOptions, filters.tool),\n });\n return;\n }\n\n if (input === 't') {\n setInteraction({\n kind: 'type-filter',\n options: typeOptions,\n selectedIndex: getSelectedIndex(typeOptions, filters.eventType),\n });\n return;\n }\n\n if (input === '/') {\n setInteraction({\n kind: 'search',\n draft: filters.query,\n });\n return;\n }\n\n if (key.escape) {\n clearFilters(setFilters, setInteraction);\n return;\n }\n\n if (\n viewMode === 'full-data' &&\n (key.upArrow || input === 'k')\n ) {\n if (focusPanel === 'events') {\n options.onSelectPreviousEvent?.();\n } else {\n options.onInspectorScroll?.(-1);\n }\n return;\n }\n\n if (\n viewMode === 'full-data' &&\n (key.downArrow || input === 'j')\n ) {\n if (focusPanel === 'events') {\n options.onSelectNextEvent?.();\n } else {\n options.onInspectorScroll?.(1);\n }\n return;\n }\n\n if (viewMode === 'full-data' && input === '[') {\n options.onInspectorPageScroll?.(-1);\n return;\n }\n\n if (viewMode === 'full-data' && input === ']') {\n options.onInspectorPageScroll?.(1);\n return;\n }\n\n if (key.tab) {\n setFocusPanel((currentValue) =>\n currentValue === 'events' ? 'sessions' : 'events',\n );\n }\n });\n\n return {\n filters,\n focusPanel,\n interaction,\n viewMode,\n };\n}\n\nfunction buildToolOptions(\n tools: readonly ToolName[],\n): readonly SelectorOption<ToolName | null>[] {\n return [\n {\n label: 'All tools',\n value: null,\n },\n ...tools.map((tool) => ({\n label: tool,\n value: tool,\n })),\n ];\n}\n\nfunction buildTypeOptions(): readonly SelectorOption<AISnitchEventType | null>[] {\n return [\n {\n label: 'All event types',\n value: null,\n },\n ...AISNITCH_EVENT_TYPES.map((eventType) => ({\n label: eventType,\n value: eventType,\n })),\n ];\n}\n\nfunction getSelectedIndex<TValue>(\n options: readonly SelectorOption<TValue>[],\n value: TValue,\n): number {\n const selectedIndex = options.findIndex((option) => option.value === value);\n\n return selectedIndex === -1 ? 0 : selectedIndex;\n}\n\nfunction moveSelector(\n interaction:\n | Extract<TuiInteractionMode, { readonly kind: 'tool-filter' }>\n | Extract<TuiInteractionMode, { readonly kind: 'type-filter' }>,\n delta: number,\n):\n | Extract<TuiInteractionMode, { readonly kind: 'tool-filter' }>\n | Extract<TuiInteractionMode, { readonly kind: 'type-filter' }> {\n const nextIndex =\n (interaction.selectedIndex + delta + interaction.options.length) %\n interaction.options.length;\n\n return {\n ...interaction,\n selectedIndex: nextIndex,\n };\n}\n\nfunction clearFilters(\n setFilters: Dispatch<SetStateAction<TuiFilters>>,\n setInteraction: Dispatch<SetStateAction<TuiInteractionMode>>,\n): void {\n setFilters(DEFAULT_TUI_FILTERS);\n setInteraction({\n kind: 'normal',\n });\n}\n","import { useEffect, useState } from 'react';\n\nimport type {\n AISnitchEvent,\n AISnitchEventType,\n ToolName,\n} from '../../core/index.js';\nimport { formatSessionLabel, formatSessionShortId } from '../../core/index.js';\n\n/**\n * @file src/tui/hooks/useSessions.ts\n * @description Session aggregation helpers for the TUI, including active-session derivation and high-level activity status.\n * @functions\n * โ†’ useSessions\n * โ†’ deriveSessions\n * โ†’ deriveGlobalActivityStatus\n * @exports SESSION_STALE_AFTER_MS, SessionState, GlobalActivityStatus, useSessions, deriveSessions, deriveGlobalActivityStatus\n * @see ../components/SessionPanel.tsx\n * @see ../components/GlobalBadge.tsx\n * @see ../App.tsx\n */\n\n/**\n * Default timeout used to evict stale sessions that never emitted `session.end`.\n */\nexport const SESSION_STALE_AFTER_MS = 120_000;\n\n/**\n * Derived session model rendered by the TUI.\n */\nexport interface SessionState {\n readonly activeFile?: string;\n readonly cwd?: string;\n readonly currentState: AISnitchEventType;\n readonly displayLabel: string;\n readonly durationMs: number;\n readonly eventCount: number;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n readonly lastEventAt: string;\n readonly pid?: number;\n readonly project?: string;\n readonly projectPath?: string;\n readonly sessionId: string;\n readonly shortSessionId?: string;\n readonly startedAt: string;\n readonly tool: ToolName;\n}\n\n/**\n * High-level activity summary used by the header badge.\n */\nexport type GlobalActivityStatus = 'action-required' | 'ready' | 'working';\n\n/**\n * ๐Ÿ“– Sessions are derived from normalized events instead of being tracked as a\n * second independent runtime channel. That keeps the TUI honest: if the event\n * contract says one thing and the session panel says another, the bug is local\n * and debuggable.\n */\nexport function useSessions(\n events: readonly AISnitchEvent[],\n options: {\n readonly staleAfterMs?: number;\n } = {},\n): readonly SessionState[] {\n const [now, setNow] = useState(Date.now());\n\n useEffect(() => {\n const timer = setInterval(() => {\n setNow(Date.now());\n }, 1_000);\n timer.unref();\n\n return () => {\n clearInterval(timer);\n };\n }, []);\n\n return deriveSessions(events, {\n now,\n staleAfterMs: options.staleAfterMs,\n });\n}\n\n/**\n * Builds the active-session list from the normalized event buffer.\n */\nexport function deriveSessions(\n events: readonly AISnitchEvent[],\n options: {\n readonly now?: number;\n readonly staleAfterMs?: number;\n } = {},\n): readonly SessionState[] {\n const now = options.now ?? Date.now();\n const staleAfterMs = options.staleAfterMs ?? SESSION_STALE_AFTER_MS;\n const sessionMap = new Map<string, SessionState>();\n\n for (const event of events) {\n const existingSession = sessionMap.get(event['aisnitch.sessionid']);\n const startedAt =\n existingSession?.startedAt ??\n (event.type === 'session.start' ? event.time : event.time);\n const nextSession: SessionState = {\n activeFile: event.data.activeFile ?? existingSession?.activeFile,\n cwd: event.data.cwd ?? existingSession?.cwd,\n currentState: event.type,\n displayLabel: formatSessionLabel({\n activeFile: event.data.activeFile ?? existingSession?.activeFile,\n cwd: event.data.cwd ?? existingSession?.cwd,\n instanceIndex: event.data.instanceIndex ?? existingSession?.instanceIndex,\n instanceTotal: event.data.instanceTotal ?? existingSession?.instanceTotal,\n pid: event.data.pid ?? existingSession?.pid,\n project: event.data.project ?? existingSession?.project,\n projectPath: event.data.projectPath ?? existingSession?.projectPath,\n sessionId: event['aisnitch.sessionid'],\n tool: event['aisnitch.tool'],\n }),\n durationMs: Math.max(0, now - Date.parse(startedAt)),\n eventCount: (existingSession?.eventCount ?? 0) + 1,\n instanceIndex:\n event.data.instanceIndex ?? existingSession?.instanceIndex,\n instanceTotal:\n event.data.instanceTotal ?? existingSession?.instanceTotal,\n lastEventAt: event.time,\n pid: event.data.pid ?? existingSession?.pid,\n project: event.data.project ?? existingSession?.project,\n projectPath: event.data.projectPath ?? existingSession?.projectPath,\n sessionId: event['aisnitch.sessionid'],\n shortSessionId: formatSessionShortId(\n event['aisnitch.tool'],\n event['aisnitch.sessionid'],\n ),\n startedAt,\n tool: event['aisnitch.tool'],\n };\n\n sessionMap.set(event['aisnitch.sessionid'], nextSession);\n }\n\n return [...sessionMap.values()]\n .filter((session) => {\n if (session.currentState === 'session.end') {\n return false;\n }\n\n return now - Date.parse(session.lastEventAt) <= staleAfterMs;\n })\n .sort((left, right) => {\n return Date.parse(right.lastEventAt) - Date.parse(left.lastEventAt);\n });\n}\n\n/**\n * Derives the global activity badge state from the active sessions list.\n */\nexport function deriveGlobalActivityStatus(\n sessions: readonly SessionState[],\n): GlobalActivityStatus {\n if (\n sessions.some((session) =>\n session.currentState === 'agent.asking_user' ||\n session.currentState === 'agent.error',\n )\n ) {\n return 'action-required';\n }\n\n if (\n sessions.some((session) =>\n session.currentState === 'agent.coding' ||\n session.currentState === 'agent.thinking' ||\n session.currentState === 'agent.tool_call' ||\n session.currentState === 'agent.streaming' ||\n session.currentState === 'task.start',\n )\n ) {\n return 'working';\n }\n\n return 'ready';\n}\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport WebSocket, { type RawData } from 'ws';\n\nimport { EventBus, AISnitchEventSchema } from '../core/index.js';\nimport type { AISnitchEvent } from '../core/index.js';\nimport { App } from './App.js';\nimport type {\n ManagedTuiSnapshot,\n TuiInitialFilters,\n TuiStatusSnapshot,\n} from './types.js';\n\n/**\n * @file src/tui/ManagedDaemonApp.tsx\n * @description PM2-style dashboard wrapper that keeps the TUI open even when the AISnitch daemon is offline.\n * @functions\n * โ†’ ManagedDaemonApp\n * โ†’ parseSocketPayload\n * @exports ManagedDaemonApp, type ManagedDaemonAppProps\n * @see ./App.tsx\n * @see ../cli/runtime.ts\n */\n\nconst DASHBOARD_REFRESH_INTERVAL_MS = 1_500;\n\n/**\n * Props required by the managed dashboard wrapper.\n */\nexport interface ManagedDaemonAppProps {\n readonly initialFilters?: TuiInitialFilters;\n readonly initialSnapshot: ManagedTuiSnapshot;\n readonly onQuit?: () => void;\n readonly refreshSnapshot: () => Promise<ManagedTuiSnapshot>;\n readonly toggleDaemon: () => Promise<ManagedTuiSnapshot>;\n readonly version: string;\n}\n\n/**\n * ๐Ÿ“– The managed dashboard keeps a local EventBus mirror so the UI can stay\n * mounted while daemon connectivity comes and goes underneath it.\n */\nexport function ManagedDaemonApp({\n initialFilters,\n initialSnapshot,\n onQuit,\n refreshSnapshot,\n toggleDaemon,\n version,\n}: ManagedDaemonAppProps): React.JSX.Element {\n const eventBus = useMemo(() => new EventBus(), []);\n const [snapshot, setSnapshot] = useState(initialSnapshot);\n const [busyAction, setBusyAction] = useState<'starting' | 'stopping' | null>(\n null,\n );\n const socketRef = useRef<WebSocket | null>(null);\n const refreshInFlightRef = useRef(false);\n\n useEffect(() => {\n let disposed = false;\n\n const refresh = async (): Promise<void> => {\n if (disposed || refreshInFlightRef.current || busyAction !== null) {\n return;\n }\n\n refreshInFlightRef.current = true;\n\n try {\n const nextSnapshot = await refreshSnapshot();\n\n if (!disposed) {\n setSnapshot(nextSnapshot);\n }\n } finally {\n refreshInFlightRef.current = false;\n }\n };\n\n const timer = setInterval(() => {\n void refresh();\n }, DASHBOARD_REFRESH_INTERVAL_MS);\n\n timer.unref();\n\n return () => {\n disposed = true;\n clearInterval(timer);\n };\n }, [busyAction, refreshSnapshot]);\n\n useEffect(() => {\n const daemon = snapshot.status.daemon;\n const currentSocket = socketRef.current;\n\n if (!daemon?.active) {\n if (currentSocket !== null) {\n socketRef.current = null;\n currentSocket.removeAllListeners();\n currentSocket.close();\n }\n\n return;\n }\n\n if (\n currentSocket !== null &&\n currentSocket.url === daemon.wsUrl &&\n (currentSocket.readyState === WebSocket.OPEN ||\n currentSocket.readyState === WebSocket.CONNECTING)\n ) {\n return;\n }\n\n if (currentSocket !== null) {\n socketRef.current = null;\n currentSocket.removeAllListeners();\n currentSocket.close();\n }\n\n const nextSocket = new WebSocket(daemon.wsUrl);\n socketRef.current = nextSocket;\n\n nextSocket.on('message', (payload: RawData) => {\n const parsedEvent = parseSocketPayload(payload);\n\n if (parsedEvent !== null) {\n eventBus.publish(parsedEvent);\n }\n });\n\n nextSocket.on('close', () => {\n if (socketRef.current === nextSocket) {\n socketRef.current = null;\n }\n });\n\n nextSocket.on('error', () => {\n if (socketRef.current === nextSocket) {\n socketRef.current = null;\n }\n });\n\n return () => {\n if (socketRef.current === nextSocket) {\n socketRef.current = null;\n }\n\n nextSocket.removeAllListeners();\n nextSocket.close();\n };\n }, [eventBus, snapshot.status.daemon]);\n\n useEffect(() => {\n return () => {\n const currentSocket = socketRef.current;\n\n if (currentSocket !== null) {\n currentSocket.removeAllListeners();\n currentSocket.close();\n }\n };\n }, []);\n\n async function handleRefresh(): Promise<void> {\n const nextSnapshot = await refreshSnapshot();\n setSnapshot(nextSnapshot);\n }\n\n async function handleToggleDaemon(): Promise<void> {\n const currentDaemon = snapshot.status.daemon;\n\n setBusyAction(currentDaemon?.active ? 'stopping' : 'starting');\n\n try {\n const nextSnapshot = await toggleDaemon();\n setSnapshot(nextSnapshot);\n } finally {\n setBusyAction(null);\n }\n }\n\n const effectiveStatus: TuiStatusSnapshot = {\n ...snapshot.status,\n daemon:\n snapshot.status.daemon === undefined\n ? undefined\n : {\n ...snapshot.status.daemon,\n busyAction,\n },\n };\n\n return (\n <App\n configuredAdapters={snapshot.configuredAdapters}\n initialFilters={initialFilters}\n managerControls={{\n onRefreshStatus: handleRefresh,\n onToggleDaemon: handleToggleDaemon,\n }}\n onQuit={onQuit}\n source={{\n kind: 'event-bus',\n eventBus,\n }}\n status={effectiveStatus}\n version={version}\n />\n );\n}\n\nfunction parseSocketPayload(data: RawData): AISnitchEvent | null {\n let parsedPayload: unknown;\n\n try {\n if (typeof data === 'string') {\n parsedPayload = JSON.parse(data) as unknown;\n } else if (Array.isArray(data)) {\n parsedPayload = JSON.parse(Buffer.concat(data).toString('utf8')) as unknown;\n } else if (data instanceof ArrayBuffer) {\n parsedPayload = JSON.parse(\n Buffer.from(new Uint8Array(data)).toString('utf8'),\n ) as unknown;\n } else {\n parsedPayload = JSON.parse(Buffer.from(data).toString('utf8')) as unknown;\n }\n } catch {\n // ๐Ÿ“– Malformed WebSocket frame โ€” silently ignore instead of crashing\n return null;\n }\n\n if (\n typeof parsedPayload === 'object' &&\n parsedPayload !== null &&\n 'type' in parsedPayload &&\n parsedPayload.type === 'welcome'\n ) {\n return null;\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n return parsedEvent.success ? parsedEvent.data : null;\n}\n","import type { AISnitchEventType, ToolName } from '../core/index.js';\n\n/**\n * @file src/tui/types.ts\n * @description Shared TUI runtime types reused by the renderer entrypoints, app shell, and CLI integration layer.\n * @functions\n * โ†’ none\n * @exports TUI_VIEW_MODES, TuiViewMode, TuiInitialFilters, TuiDaemonSnapshot, TuiStatusSnapshot, ManagedTuiSnapshot\n * @see ./App.tsx\n * @see ./index.tsx\n */\n\n/**\n * Supported body views for the interactive TUI.\n */\nexport const TUI_VIEW_MODES = ['summary', 'full-data'] as const;\n\n/**\n * Union of the TUI body views accepted by CLI and renderer code.\n */\nexport type TuiViewMode = (typeof TUI_VIEW_MODES)[number];\n\n/**\n * CLI or runtime-provided filters applied when the TUI opens.\n */\nexport interface TuiInitialFilters {\n readonly query?: string;\n readonly tool?: ToolName;\n readonly type?: AISnitchEventType;\n readonly view?: TuiViewMode;\n}\n\n/**\n * Optional daemon-management metadata displayed by the PM2-style dashboard.\n */\nexport interface TuiDaemonSnapshot {\n readonly active: boolean;\n readonly busyAction?: 'starting' | 'stopping' | null;\n readonly httpUrl: string;\n readonly pid: number | null;\n readonly socketPath: string | null;\n readonly wsUrl: string;\n}\n\n/**\n * Lightweight runtime snapshot consumed by the TUI shell.\n */\nexport interface TuiStatusSnapshot {\n readonly connected: boolean;\n readonly connectionLabel: string;\n readonly consumerCount: number;\n readonly daemon?: TuiDaemonSnapshot;\n readonly eventCount: number;\n readonly uptimeMs: number;\n}\n\n/**\n * Full renderer snapshot used by the managed dashboard mode.\n */\nexport interface ManagedTuiSnapshot {\n readonly configuredAdapters: readonly ToolName[];\n readonly status: TuiStatusSnapshot;\n}\n","import { once } from 'node:events';\n\nimport WebSocket, { type RawData } from 'ws';\n\nimport { AISnitchEventSchema } from '../core/events/index.js';\nimport type {\n AISnitchEvent,\n EventBus,\n WelcomeMessage,\n} from '../core/index.js';\nimport { formatSessionLabelFromEvent } from '../core/index.js';\nimport { formatEventDetail } from './event-details.js';\n\n/**\n * @file src/tui/live-monitor.ts\n * @description Lightweight plain-text live event monitor formatter retained for tests and fallback console output.\n * @functions\n * โ†’ formatEventLine\n * โ†’ formatWelcomeLine\n * โ†’ attachEventBusMonitor\n * โ†’ attachWebSocketMonitor\n * @exports MonitorOutput, MonitorCloseHandler, formatEventLine, formatWelcomeLine, attachEventBusMonitor, attachWebSocketMonitor\n * @see ../core/engine/ws-server.ts\n * @see ../core/events/schema.ts\n */\n\n/**\n * Minimal output contract shared by CLI monitor renderers.\n */\nexport interface MonitorOutput {\n readonly stdout: (text: string) => void;\n readonly stderr: (text: string) => void;\n}\n\n/**\n * Async close callback returned by monitor attach helpers.\n */\nexport type MonitorCloseHandler = () => Promise<void> | void;\n\n/**\n * ๐Ÿ“– The Ink TUI is now the primary operator surface, but these formatters are\n * still useful for tests and any future low-friction text fallbacks.\n */\nexport function formatEventLine(event: AISnitchEvent): string {\n const detail = formatEventDetail(event);\n const summary = detail ? ` :: ${detail}` : '';\n\n return [\n `[${event.time}]`,\n event['aisnitch.tool'],\n event.type,\n `session=${formatSessionLabelFromEvent(event)}`,\n `sid=${event['aisnitch.sessionid']}`,\n event.data.cwd ? `cwd=${event.data.cwd}` : undefined,\n ]\n .filter((value): value is string => typeof value === 'string')\n .join(' ') + summary;\n}\n\n/**\n * Formats the WebSocket welcome payload for human-readable output.\n */\nexport function formatWelcomeLine(message: WelcomeMessage): string {\n const tools =\n message.tools.length > 0 ? message.tools.join(', ') : 'none configured';\n\n return `Connected to AISnitch ${message.version} (tools: ${tools})`;\n}\n\n/**\n * Attaches a live writer to the in-process EventBus.\n */\nexport function attachEventBusMonitor(\n eventBus: EventBus,\n output: MonitorOutput,\n): MonitorCloseHandler {\n output.stdout('AISnitch live monitor attached (foreground mode).\\n');\n\n return eventBus.subscribe((event) => {\n output.stdout(`${formatEventLine(event)}\\n`);\n });\n}\n\n/**\n * Attaches to an existing daemon over WebSocket and streams monitor lines.\n */\nexport async function attachWebSocketMonitor(\n url: string,\n output: MonitorOutput,\n): Promise<MonitorCloseHandler> {\n const socket = new WebSocket(url);\n\n socket.on('message', (data) => {\n const parsedPayload = parseSocketMessage(data);\n\n if (isWelcomeMessage(parsedPayload)) {\n output.stdout(`${formatWelcomeLine(parsedPayload)}\\n`);\n return;\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n if (parsedEvent.success) {\n output.stdout(`${formatEventLine(parsedEvent.data)}\\n`);\n return;\n }\n\n output.stderr('Received an unrecognized monitor payload.\\n');\n });\n\n socket.on('error', (error) => {\n output.stderr(\n `AISnitch attach socket error: ${\n error instanceof Error ? error.message : 'unknown error'\n }\\n`,\n );\n });\n\n await once(socket, 'open');\n\n return async () => {\n if (\n socket.readyState === WebSocket.CLOSING ||\n socket.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n socket.close();\n await once(socket, 'close');\n };\n}\n\nfunction parseSocketMessage(data: RawData): unknown {\n try {\n if (typeof data === 'string') {\n return JSON.parse(data) as unknown;\n }\n\n if (Array.isArray(data)) {\n return JSON.parse(Buffer.concat(data).toString('utf8')) as unknown;\n }\n\n if (data instanceof ArrayBuffer) {\n return JSON.parse(\n Buffer.from(new Uint8Array(data)).toString('utf8'),\n ) as unknown;\n }\n\n return JSON.parse(Buffer.from(data).toString('utf8')) as unknown;\n } catch {\n // ๐Ÿ“– Malformed WebSocket frame โ€” return null instead of crashing\n return null;\n }\n}\n\nfunction isWelcomeMessage(payload: unknown): payload is WelcomeMessage {\n if (typeof payload !== 'object' || payload === null) {\n return false;\n }\n\n const candidate = payload as Record<string, unknown>;\n\n return (\n candidate.type === 'welcome' &&\n typeof candidate.version === 'string' &&\n Array.isArray(candidate.tools)\n );\n}\n"],"mappings":"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","names":["basename","z","z","basename","execFileCallback","readFile","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","readFile","basename","execFileCallback","readFile","readdir","stat","basename","dirname","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getRecord","readFile","collectFilesRecursively","stat","listProcesses","mergedMetadata","isErrnoException","basename","dirname","readdir","execFileCallback","readFile","stat","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","readFile","stat","listProcesses","isRecord","getString","parseProcessLine","isErrnoException","execFileCallback","readFile","readdir","stat","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","readFile","basename","getRecord","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","parseProcessLine","execFileCallback","readFile","readdir","stat","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","getRecord","extractToolInput","readFile","basename","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","parseProcessLine","execFileCallback","readFile","readdir","stat","join","dirname","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","readFile","dirname","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","getRecord","parseProcessLine","execFileCallback","stat","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","stat","isRecord","getString","getRecord","extractLooseString","listProcesses","getNumber","parseJsonRecord","extractFirstString","execFileCallback","readFile","readdir","stat","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","getRecord","extractToolInput","readFile","basename","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","parseProcessLine","execFileCallback","readFile","readdir","stat","basename","dirname","extname","join","promisify","watch","pidCwd","execFile","promisify","execFileCallback","join","pidCwd","watch","isRecord","getNumber","collectFilesRecursively","stat","parseJsonRecord","dirname","getString","basename","readFile","readdir","extname","getRecord","execFileCallback","promisify","execFile","promisify","execFileCallback","isRecord","getString","getNumber","getRecord","listProcesses","execFile","join","promisify","promisify","execFile","join","readFile","basename","join","join","readFile","basename","basename","execFileCallback","basename","promisify","pidCwd","execFile","promisify","execFileCallback","basename","pidCwd","basename","resolve","z","z","readFile","homedir","dirname","join","dirname","join","homedir","readFile","resolve","once","createServer","createServer","once","resolve","createServer","once","createServer","once","resolve","join","z","z","join","resolve","getTimeout","resolve","getString","getNumber","getBoolean","isRecord","WebSocket","useEffect","useState","Box","getRecord","getString","extractLooseString","isRecord","Box","Text","Box","Text","jsx","jsxs","Box","Text","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","Text","jsx","Text","Fragment","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","Spinner","jsx","jsxs","Text","Box","Spinner","Box","Text","jsx","jsxs","Box","Text","visibleStartIndex","useState","useState","useEffect","useState","useState","useEffect","jsx","jsxs","useState","useEffect","Box","useEffect","useState","WebSocket","jsx","useState","useEffect","WebSocket","parseSocketPayload","once","WebSocket","WebSocket","once","jsx","WebSocket"]}
1
+ {"version":3,"sources":["../src/adapters/aider.ts","../src/core/engine/logger.ts","../src/core/session-identity.ts","../src/adapters/base.ts","../src/core/errors.ts","../src/core/circuit-breaker.ts","../src/core/events/schema.ts","../src/core/events/factory.ts","../src/adapters/claude-code.ts","../src/adapters/copilot-cli.ts","../src/adapters/codex.ts","../src/adapters/cursor.ts","../src/adapters/devin.ts","../src/adapters/gemini-cli.ts","../src/adapters/goose.ts","../src/adapters/kilo.ts","../src/adapters/openclaw.ts","../src/adapters/opencode.ts","../src/adapters/pi.ts","../src/adapters/zed.ts","../src/adapters/registry.ts","../src/adapters/generic-pty.ts","../src/core/engine/context-detector.ts","../src/adapters/index.ts","../src/core/config/schema.ts","../src/core/config/defaults.ts","../src/core/config/loader.ts","../src/core/engine/event-bus.ts","../src/core/engine/ring-buffer.ts","../src/core/engine/ws-server.ts","../src/package-info.ts","../src/core/engine/http-receiver.ts","../src/core/engine/uds-server.ts","../src/core/engine/pipeline.ts","../src/core/events/cesp.ts","../src/core/timeout.ts","../src/core/graceful-shutdown.ts","../src/core/result.ts","../src/core/retry.ts","../src/core/safety.ts","../src/tui/index.tsx","../src/tui/App.tsx","../src/tui/components/EventInspector.tsx","../src/tui/event-details.ts","../src/tui/theme.ts","../src/tui/event-inspector.ts","../src/tui/components/EventStream.tsx","../src/tui/components/EventLine.tsx","../src/tui/components/FilterBar.tsx","../src/tui/filters.ts","../src/tui/components/Header.tsx","../src/tui/components/GlobalBadge.tsx","../src/tui/components/HelpOverlay.tsx","../src/tui/components/Layout.tsx","../src/tui/components/SessionPanel.tsx","../src/tui/components/StatusBar.tsx","../src/tui/hooks/useEventStream.ts","../src/tui/hooks/useKeyBinds.ts","../src/tui/hooks/useSessions.ts","../src/tui/ManagedDaemonApp.tsx","../src/tui/types.ts","../src/tui/live-monitor.ts"],"sourcesContent":["import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\nimport pidCwd from 'pid-cwd';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n AISnitchEventType,\n ErrorType,\n EventData,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/aider.ts\n * @description Aider adapter combining passive markdown history parsing, notifications-command hooks, and active process discovery.\n * @functions\n * โ†’ parseAiderHistoryMarkdown\n * @exports AiderAdapter, AiderAdapterOptions, AiderHistoryObservation, AiderHistoryParseResult, parseAiderHistoryMarkdown\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/03_adapters-secondary_aider-pty_DONE.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst DEFAULT_AIDER_HISTORY_FILE = '.aider.chat.history.md';\nconst AIDER_ERROR_HINT =\n /failed|error|exception|keyboardinterrupt|did not conform|traceback/iu;\nconst AIDER_ASKING_USER_HINT =\n /\\b\\(Y(?:es)?\\/N(?:o)?\\)|\\bPress Enter\\b|\\bcontinue\\?\\b|\\bcontinue to exit\\b/iu;\nconst AIDER_FILE_COMMAND_HINT = /^\\/(?:add|drop|read-only)\\b/iu;\nconst AIDER_STARTUP_STATUS_HINT =\n /^(?:\\/.+\\/aider|Aider v|Main model:|Model:|Weak model:|Git repo:|Repo-map:)/u;\n\nexport interface AiderAdapterOptions extends AdapterRuntimeOptions {\n readonly cwdResolver?: (pid: number) => Promise<string | undefined>;\n readonly historyFileName?: string;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface AiderProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface AiderSessionRuntime {\n readonly cwd: string;\n readonly historyPath: string;\n readonly pids: readonly number[];\n readonly sessionId: string;\n readonly model?: string;\n}\n\ninterface AiderHistoryWatcher {\n readonly fingerprints: Set<string>;\n readonly watcher: FSWatcher;\n}\n\ninterface AiderHistoryParseOptions {\n readonly cwd: string;\n readonly historyPath: string;\n readonly initialModel?: string;\n}\n\nexport interface AiderHistoryObservation {\n readonly fingerprint: string;\n readonly type: AISnitchEventType;\n readonly data: Omit<EventData, 'state'>;\n}\n\nexport interface AiderHistoryParseResult {\n readonly lastModel?: string;\n readonly observations: readonly AiderHistoryObservation[];\n}\n\n/**\n * ๐Ÿ“– Aider's transcript is markdown, not a stable machine API. The parser\n * therefore sticks to high-signal structures: prompts, quoted status lines,\n * assistant prose, and SEARCH/REPLACE file blocks.\n */\nexport class AiderAdapter extends BaseAdapter {\n public override readonly displayName = 'Aider';\n\n public override readonly name = 'aider' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'log-watch',\n 'process-detect',\n ];\n\n private readonly cwdResolver: (pid: number) => Promise<string | undefined>;\n\n private readonly historyFileName: string;\n\n private readonly historySessions = new Map<string, AiderSessionRuntime>();\n\n private readonly historyWatchers = new Map<string, AiderHistoryWatcher>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: AiderAdapterOptions) {\n super(options);\n this.cwdResolver =\n options.cwdResolver ??\n (async (pid) => {\n return await pidCwd(pid);\n });\n this.historyFileName = options.historyFileName ?? DEFAULT_AIDER_HISTORY_FILE;\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', '(^|[ /])aider([ ]|$)']).then(\n (result) => result.stdout,\n ));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startProcessPolling();\n\n return Promise.resolve();\n }\n\n public override async stop(): Promise<void> {\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n for (const watcherHandle of this.historyWatchers.values()) {\n await watcherHandle.watcher.close();\n }\n\n this.historySessions.clear();\n this.historyWatchers.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload === null) {\n logger.debug({ payload }, 'Aider ignores non-normalized hook payloads');\n return;\n }\n\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs > 0) {\n this.processPoller = setInterval(() => {\n void this.pollAiderProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n }\n\n void this.pollAiderProcesses();\n }\n\n private async pollAiderProcesses(): Promise<void> {\n const processes = await listAiderProcesses(this.processListCommand);\n const nextSessions = new Map<string, AiderSessionRuntime>();\n\n for (const processInfo of processes) {\n const cwd = await this.cwdResolver(processInfo.pid);\n\n if (!cwd) {\n continue;\n }\n\n const historyPath = resolveAiderHistoryPath(\n cwd,\n processInfo.command,\n this.historyFileName,\n );\n const existingSession = nextSessions.get(historyPath);\n\n if (existingSession) {\n nextSessions.set(historyPath, {\n ...existingSession,\n pids: [...existingSession.pids, processInfo.pid],\n });\n continue;\n }\n\n const previousSession = this.historySessions.get(historyPath);\n const sessionId =\n previousSession?.sessionId ??\n resolveSessionId({\n cwd,\n tool: this.name,\n transcriptPath: historyPath,\n });\n\n nextSessions.set(historyPath, {\n cwd,\n historyPath,\n model: previousSession?.model,\n pids: [processInfo.pid],\n sessionId,\n });\n }\n\n for (const [historyPath, session] of nextSessions) {\n if (this.historySessions.has(historyPath)) {\n this.historySessions.set(historyPath, session);\n continue;\n }\n\n this.historySessions.set(historyPath, session);\n await this.ensureHistoryWatcher(session);\n await this.emitHistoryEvent(\n session,\n 'session.start',\n {\n project: basename(session.cwd) || session.cwd,\n projectPath: session.cwd,\n raw: {\n historyPath,\n pids: session.pids,\n source: 'process-detect',\n },\n },\n {\n pid: session.pids[0],\n source: 'aisnitch://adapters/aider/process-detect',\n },\n );\n await this.emitHistoryEvent(\n session,\n 'agent.idle',\n {\n model: session.model,\n project: basename(session.cwd) || session.cwd,\n projectPath: session.cwd,\n raw: {\n historyPath,\n source: 'process-detect',\n },\n },\n {\n pid: session.pids[0],\n source: 'aisnitch://adapters/aider/process-detect',\n },\n );\n }\n\n for (const [historyPath, previousSession] of this.historySessions) {\n if (nextSessions.has(historyPath)) {\n continue;\n }\n\n await this.emitHistoryEvent(\n previousSession,\n 'session.end',\n {\n model: previousSession.model,\n project: basename(previousSession.cwd) || previousSession.cwd,\n projectPath: previousSession.cwd,\n raw: {\n historyPath,\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n pid: previousSession.pids[0],\n source: 'aisnitch://adapters/aider/process-detect',\n },\n );\n await this.releaseHistoryWatcher(historyPath);\n this.historySessions.delete(historyPath);\n }\n }\n\n private async ensureHistoryWatcher(\n session: AiderSessionRuntime,\n ): Promise<void> {\n if (this.historyWatchers.has(session.historyPath)) {\n return;\n }\n\n const fingerprintSet = new Set<string>();\n const seedResult = await readOptionalAiderHistory(session);\n\n if (seedResult !== null) {\n for (const observation of seedResult.observations) {\n fingerprintSet.add(observation.fingerprint);\n }\n\n if (seedResult.lastModel) {\n this.historySessions.set(session.historyPath, {\n ...session,\n model: seedResult.lastModel,\n });\n }\n }\n\n const watcher = this.watcherFactory(session.historyPath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n watcher.on('add', () => {\n void this.processHistoryUpdate(session.historyPath);\n });\n watcher.on('change', () => {\n void this.processHistoryUpdate(session.historyPath);\n });\n watcher.on('error', (error) => {\n logger.warn(\n {\n error,\n historyPath: session.historyPath,\n },\n 'Aider history watcher error',\n );\n });\n\n this.historyWatchers.set(session.historyPath, {\n fingerprints: fingerprintSet,\n watcher,\n });\n }\n\n private async processHistoryUpdate(historyPath: string): Promise<void> {\n const session = this.historySessions.get(historyPath);\n const watcherHandle = this.historyWatchers.get(historyPath);\n\n if (!session || !watcherHandle) {\n return;\n }\n\n const parseResult = await readOptionalAiderHistory(session);\n\n if (parseResult === null) {\n return;\n }\n\n if (parseResult.lastModel !== session.model) {\n this.historySessions.set(historyPath, {\n ...session,\n model: parseResult.lastModel,\n });\n }\n\n for (const observation of parseResult.observations) {\n if (watcherHandle.fingerprints.has(observation.fingerprint)) {\n continue;\n }\n\n watcherHandle.fingerprints.add(observation.fingerprint);\n await this.emitHistoryEvent(\n this.historySessions.get(historyPath) ?? session,\n observation.type,\n observation.data,\n {\n pid: session.pids[0],\n source: 'aisnitch://adapters/aider/history',\n },\n );\n }\n }\n\n private async emitHistoryEvent(\n session: AiderSessionRuntime,\n type: AISnitchEventType,\n data: Omit<EventData, 'state'>,\n context: Omit<AdapterPublishContext, 'sessionId' | 'cwd' | 'transcriptPath'>,\n ): Promise<void> {\n await this.emitStateChange(\n type,\n {\n cwd: session.cwd,\n model: data.model ?? session.model,\n project: data.project ?? (basename(session.cwd) || session.cwd),\n projectPath: data.projectPath ?? session.cwd,\n ...data,\n },\n {\n ...context,\n cwd: session.cwd,\n sessionId: session.sessionId,\n transcriptPath: session.historyPath,\n },\n );\n }\n\n private async releaseHistoryWatcher(historyPath: string): Promise<void> {\n const watcherHandle = this.historyWatchers.get(historyPath);\n\n if (!watcherHandle) {\n return;\n }\n\n await watcherHandle.watcher.close();\n this.historyWatchers.delete(historyPath);\n }\n}\n\n/**\n * Parses an aider markdown history file into normalized AISnitch observations.\n */\nexport function parseAiderHistoryMarkdown(\n markdown: string,\n options: AiderHistoryParseOptions,\n): AiderHistoryParseResult {\n const observations: AiderHistoryObservation[] = [];\n const lines = markdown.split(/\\r?\\n/u);\n let model = options.initialModel;\n\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index] ?? '';\n\n if (line.startsWith('# aider chat started at ')) {\n continue;\n }\n\n if (line.startsWith('#### ')) {\n const prompt = line.slice(5).trim();\n\n if (prompt.length === 0) {\n continue;\n }\n\n observations.push(createPromptObservation(prompt, index, {\n cwd: options.cwd,\n historyPath: options.historyPath,\n model,\n }));\n continue;\n }\n\n if (line.startsWith('>')) {\n const block = collectQuotedBlock(lines, index);\n const parsedBlock = parseQuotedOutputBlock(block.lines, {\n cwd: options.cwd,\n historyPath: options.historyPath,\n lineIndex: index,\n model,\n });\n\n observations.push(...parsedBlock.observations);\n model = parsedBlock.lastModel ?? model;\n index = block.nextIndex - 1;\n continue;\n }\n\n if (isAiderPatchBlockStart(lines, index)) {\n const patchBlock = collectPatchBlock(lines, index);\n observations.push(\n createCodingObservation(\n patchBlock.activeFile,\n patchBlock.body,\n index,\n {\n cwd: options.cwd,\n historyPath: options.historyPath,\n model,\n },\n ),\n );\n index = patchBlock.nextIndex - 1;\n continue;\n }\n\n if (line.trim().length === 0) {\n continue;\n }\n\n const proseBlock = collectProseBlock(lines, index);\n\n if (proseBlock.body.length > 0) {\n observations.push(\n createStreamingObservation(proseBlock.body, index, {\n cwd: options.cwd,\n historyPath: options.historyPath,\n model,\n }),\n );\n }\n\n index = proseBlock.nextIndex - 1;\n }\n\n return {\n lastModel: model,\n observations,\n };\n}\n\nasync function readOptionalAiderHistory(\n session: AiderSessionRuntime,\n): Promise<AiderHistoryParseResult | null> {\n try {\n const content = await readFile(session.historyPath, 'utf8');\n\n return parseAiderHistoryMarkdown(content, {\n cwd: session.cwd,\n historyPath: session.historyPath,\n initialModel: session.model,\n });\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return null;\n }\n\n throw error;\n }\n}\n\nfunction createPromptObservation(\n prompt: string,\n lineIndex: number,\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly model?: string;\n },\n): AiderHistoryObservation {\n if (prompt.startsWith('/')) {\n const slashCommand = parseAiderSlashCommand(prompt);\n\n return {\n data: {\n activeFile: slashCommand.filePath,\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n prompt,\n source: 'history-markdown',\n },\n toolInput: slashCommand.filePath\n ? {\n filePath: slashCommand.filePath,\n }\n : {\n command: prompt,\n },\n toolName: `aider:${slashCommand.name}`,\n },\n fingerprint: createHistoryFingerprint(\n 'agent.tool_call',\n lineIndex,\n prompt,\n slashCommand.filePath,\n ),\n type: 'agent.tool_call',\n };\n }\n\n return {\n data: {\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n prompt,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint('task.start', lineIndex, prompt),\n type: 'task.start',\n };\n}\n\nfunction parseQuotedOutputBlock(\n quotedLines: readonly string[],\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly lineIndex: number;\n readonly model?: string;\n },\n): AiderHistoryParseResult {\n const observations: AiderHistoryObservation[] = [];\n let lastModel = context.model;\n const leftoverLines: string[] = [];\n\n for (let offset = 0; offset < quotedLines.length; offset += 1) {\n const rawLine = quotedLines[offset] ?? '';\n const line = rawLine.trim();\n\n if (line.length === 0) {\n continue;\n }\n\n const parsedModel = parseAiderModelLine(line);\n\n if (parsedModel) {\n lastModel = parsedModel;\n continue;\n }\n\n if (AIDER_STARTUP_STATUS_HINT.test(line)) {\n continue;\n }\n\n const tokenCount = parseAiderTokenUsage(line);\n\n if (tokenCount !== undefined) {\n observations.push({\n data: {\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n tokensUsed: tokenCount,\n },\n fingerprint: createHistoryFingerprint(\n 'agent.thinking',\n context.lineIndex + offset,\n line,\n ),\n type: 'agent.thinking',\n });\n continue;\n }\n\n const addedFileMatch = line.match(/^Added\\s+(.+?)\\s+to the chat$/u);\n\n if (addedFileMatch) {\n const addedFile = addedFileMatch[1]?.trim();\n\n if (addedFile) {\n observations.push({\n data: {\n activeFile: addedFile,\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n toolInput: {\n filePath: addedFile,\n },\n toolName: 'aider:/add',\n },\n fingerprint: createHistoryFingerprint(\n 'agent.tool_call',\n context.lineIndex + offset,\n line,\n addedFile,\n ),\n type: 'agent.tool_call',\n });\n continue;\n }\n }\n\n const appliedEditMatch = line.match(\n /^(?:Applied|Updated|Edited|Created|Wrote)\\s+(.+?)$/u,\n );\n\n if (appliedEditMatch) {\n const activeFile = appliedEditMatch[1]?.trim();\n\n if (activeFile) {\n observations.push(createCodingObservation(activeFile, line, context.lineIndex + offset, {\n cwd: context.cwd,\n historyPath: context.historyPath,\n model: lastModel,\n }));\n continue;\n }\n }\n\n if (AIDER_ASKING_USER_HINT.test(line)) {\n observations.push({\n data: {\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint(\n 'agent.asking_user',\n context.lineIndex + offset,\n line,\n ),\n type: 'agent.asking_user',\n });\n continue;\n }\n\n if (AIDER_ERROR_HINT.test(line)) {\n observations.push({\n data: {\n errorMessage: line,\n errorType: classifyAiderErrorType(line),\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: line,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint(\n 'agent.error',\n context.lineIndex + offset,\n line,\n ),\n type: 'agent.error',\n });\n continue;\n }\n\n leftoverLines.push(line);\n }\n\n if (leftoverLines.length > 0) {\n const body = leftoverLines.join('\\n').trim();\n\n observations.push({\n data: {\n model: lastModel,\n raw: {\n historyPath: context.historyPath,\n output: body,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint(\n 'agent.thinking',\n context.lineIndex,\n body,\n ),\n type: 'agent.thinking',\n });\n }\n\n return {\n lastModel,\n observations,\n };\n}\n\nfunction createStreamingObservation(\n body: string,\n lineIndex: number,\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly model?: string;\n },\n): AiderHistoryObservation {\n return {\n data: {\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n output: body,\n source: 'history-markdown',\n },\n },\n fingerprint: createHistoryFingerprint('agent.streaming', lineIndex, body),\n type: 'agent.streaming',\n };\n}\n\nfunction createCodingObservation(\n activeFile: string,\n body: string,\n lineIndex: number,\n context: {\n readonly cwd: string;\n readonly historyPath: string;\n readonly model?: string;\n },\n): AiderHistoryObservation {\n return {\n data: {\n activeFile,\n model: context.model,\n raw: {\n historyPath: context.historyPath,\n output: body,\n source: 'history-markdown',\n },\n toolInput: {\n filePath: activeFile,\n },\n toolName: 'search-replace',\n },\n fingerprint: createHistoryFingerprint(\n 'agent.coding',\n lineIndex,\n body,\n activeFile,\n ),\n type: 'agent.coding',\n };\n}\n\nfunction collectQuotedBlock(\n lines: readonly string[],\n startIndex: number,\n): {\n readonly lines: readonly string[];\n readonly nextIndex: number;\n} {\n const blockLines: string[] = [];\n let index = startIndex;\n\n while (index < lines.length) {\n const currentLine = lines[index];\n\n if (!currentLine?.startsWith('>')) {\n break;\n }\n\n blockLines.push(currentLine.replace(/^>\\s?/u, ''));\n index += 1;\n }\n\n return {\n lines: blockLines,\n nextIndex: index,\n };\n}\n\nfunction collectProseBlock(\n lines: readonly string[],\n startIndex: number,\n): {\n readonly body: string;\n readonly nextIndex: number;\n} {\n const proseLines: string[] = [];\n let index = startIndex;\n\n while (index < lines.length) {\n const currentLine = lines[index] ?? '';\n\n if (\n currentLine.trim().length === 0 ||\n currentLine.startsWith('# aider chat started at ') ||\n currentLine.startsWith('#### ') ||\n currentLine.startsWith('>') ||\n isAiderPatchBlockStart(lines, index)\n ) {\n break;\n }\n\n proseLines.push(currentLine);\n index += 1;\n }\n\n return {\n body: proseLines.join('\\n').trim(),\n nextIndex: index,\n };\n}\n\nfunction collectPatchBlock(\n lines: readonly string[],\n startIndex: number,\n): {\n readonly activeFile: string;\n readonly body: string;\n readonly nextIndex: number;\n} {\n const activeFile = (lines[startIndex] ?? '').trim();\n const blockLines = [activeFile];\n let index = startIndex + 1;\n\n while (index < lines.length) {\n const currentLine = lines[index] ?? '';\n\n if (\n currentLine.startsWith('#### ') ||\n currentLine.startsWith('# aider chat started at ') ||\n currentLine.startsWith('> ')\n ) {\n break;\n }\n\n if (\n currentLine.trim().length === 0 &&\n !looksLikePatchMarker(lines[index + 1] ?? '')\n ) {\n blockLines.push(currentLine);\n index += 1;\n break;\n }\n\n blockLines.push(currentLine);\n index += 1;\n }\n\n return {\n activeFile,\n body: blockLines.join('\\n').trim(),\n nextIndex: index,\n };\n}\n\nfunction isAiderPatchBlockStart(\n lines: readonly string[],\n index: number,\n): boolean {\n const currentLine = (lines[index] ?? '').trim();\n const nextLine = lines[index + 1] ?? '';\n\n if (\n currentLine.length === 0 ||\n currentLine.startsWith('#') ||\n currentLine.startsWith('>') ||\n currentLine.startsWith('#### ')\n ) {\n return false;\n }\n\n return looksLikePatchMarker(nextLine);\n}\n\nfunction looksLikePatchMarker(line: string): boolean {\n const trimmedLine = line.trim();\n\n return (\n trimmedLine.startsWith('<<<<<<< ') ||\n trimmedLine.startsWith('=======') ||\n trimmedLine.startsWith('>>>>>>> ')\n );\n}\n\nfunction parseAiderModelLine(line: string): string | undefined {\n const modelMatch = line.match(/^(?:Main model|Model):\\s*(.+?)(?:\\s+with\\s+|$)/u);\n\n return modelMatch?.[1]?.trim() || undefined;\n}\n\nfunction parseAiderTokenUsage(line: string): number | undefined {\n const tokenMatch = line.match(\n /Tokens:\\s+([0-9.]+[kKmM]?)\\s+sent,\\s+([0-9.]+[kKmM]?)\\s+received/u,\n );\n\n if (!tokenMatch) {\n return undefined;\n }\n\n const sentTokens = parseHumanTokenCount(tokenMatch[1]);\n const receivedTokens = parseHumanTokenCount(tokenMatch[2]);\n\n if (sentTokens === undefined || receivedTokens === undefined) {\n return undefined;\n }\n\n return sentTokens + receivedTokens;\n}\n\nfunction parseHumanTokenCount(rawValue: string | undefined): number | undefined {\n if (!rawValue) {\n return undefined;\n }\n\n const match = rawValue.trim().match(/^([0-9]+(?:\\.[0-9]+)?)([kKmM])?$/u);\n\n if (!match) {\n return undefined;\n }\n\n const numericValue = Number.parseFloat(match[1] ?? '');\n\n if (!Number.isFinite(numericValue)) {\n return undefined;\n }\n\n const suffix = match[2]?.toLowerCase();\n\n if (suffix === 'k') {\n return Math.round(numericValue * 1_000);\n }\n\n if (suffix === 'm') {\n return Math.round(numericValue * 1_000_000);\n }\n\n return Math.round(numericValue);\n}\n\nfunction parseAiderSlashCommand(prompt: string): {\n readonly filePath?: string;\n readonly name: string;\n} {\n const normalizedPrompt = prompt.trim();\n const commandName = normalizedPrompt\n .slice(1)\n .split(/\\s+/u)[0]\n ?.toLowerCase();\n const filePath = AIDER_FILE_COMMAND_HINT.test(normalizedPrompt)\n ? normalizedPrompt.split(/\\s+/u).slice(1).join(' ').trim() || undefined\n : undefined;\n\n return {\n filePath,\n name: commandName ?? 'command',\n };\n}\n\nfunction createHistoryFingerprint(\n type: AISnitchEventType,\n lineIndex: number,\n text: string,\n activeFile?: string,\n): string {\n return [\n type,\n String(lineIndex),\n activeFile ?? '',\n text.trim().replace(/\\s+/gu, ' ').slice(0, 240),\n ].join('::');\n}\n\nfunction classifyAiderErrorType(message: string): ErrorType {\n if (/rate limit|quota|too many requests/iu.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|context window/iu.test(message)) {\n return 'context_overflow';\n }\n\n if (/search\\/replace|edit format|apply|patch|write/iu.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nfunction resolveAiderHistoryPath(\n cwd: string,\n command: string,\n fallbackHistoryFileName: string,\n): string {\n const configuredHistoryPath =\n extractCommandOptionValue(command, 'chat-history-file') ??\n extractCommandOptionValue(command, 'chat_history_file');\n\n if (!configuredHistoryPath) {\n return join(cwd, fallbackHistoryFileName);\n }\n\n return configuredHistoryPath.startsWith('/')\n ? configuredHistoryPath\n : join(cwd, configuredHistoryPath);\n}\n\nfunction extractCommandOptionValue(\n command: string,\n optionName: string,\n): string | undefined {\n const matcher = new RegExp(\n `(?:^|\\\\s)--${escapeForRegExp(optionName)}(?:=|\\\\s+)(\"([^\"]+)\"|'([^']+)'|(\\\\S+))`,\n 'u',\n );\n const match = command.match(matcher);\n\n return match?.[2] ?? match?.[3] ?? match?.[4] ?? undefined;\n}\n\nfunction escapeForRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n}\n\nasync function listAiderProcesses(\n processListCommand: () => Promise<string>,\n): Promise<readonly AiderProcessInfo[]> {\n try {\n const output = await processListCommand();\n\n return output\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pid = Number.parseInt(match[1] ?? '', 10);\n const command = match[2]?.trim();\n\n if (!Number.isInteger(pid) || pid <= 0 || !command) {\n return null;\n }\n\n return {\n command,\n pid,\n } satisfies AiderProcessInfo;\n })\n .filter((processInfo): processInfo is AiderProcessInfo => processInfo !== null);\n } catch (error: unknown) {\n logger.debug({ error }, 'Aider process discovery returned no matches');\n return [];\n }\n}\n","import pino from 'pino';\n\n/**\n * @file src/core/engine/logger.ts\n * @description Shared structured logger for the in-memory AISnitch runtime.\n * @functions\n * โ†’ setLoggerLevel\n * @exports AISnitchLoggerLevel, logger, setLoggerLevel\n */\n\n/**\n * Supported logger levels for internal runtime usage.\n */\nexport type AISnitchLoggerLevel =\n | 'debug'\n | 'info'\n | 'warn'\n | 'error'\n | 'silent';\n\n/**\n * ๐Ÿ“– The logger writes to stdout only. The project is memory-only for runtime\n * data, so logging to files here would quietly violate that design.\n */\nexport const logger = pino({\n name: 'aisnitch',\n level: 'info',\n base: {\n service: 'aisnitch',\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n});\n\n/**\n * Updates the shared logger level at runtime.\n */\nexport function setLoggerLevel(level: AISnitchLoggerLevel): void {\n logger.level = level;\n}\n","import { basename, dirname, extname } from 'node:path';\n\nimport type { AISnitchEvent, ToolName } from './events/types.js';\n\n/**\n * @file src/core/session-identity.ts\n * @description Shared helpers for deriving stable session ids and readable session labels from partial runtime metadata.\n * @functions\n * โ†’ isGenericSessionId\n * โ†’ resolveSessionId\n * โ†’ formatSessionLabel\n * โ†’ formatSessionShortId\n * โ†’ formatSessionLabelFromEvent\n * @exports SessionIdentityInput, isGenericSessionId, resolveSessionId, formatSessionLabel, formatSessionShortId, formatSessionLabelFromEvent\n * @see ./engine/pipeline.ts\n * @see ../adapters/base.ts\n * @see ../tui/components/SessionPanel.tsx\n */\n\n/**\n * Shared metadata used to derive or display one session identity.\n */\nexport interface SessionIdentityInput {\n readonly activeFile?: string;\n readonly cwd?: string;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n readonly pid?: number;\n readonly project?: string;\n readonly projectPath?: string;\n readonly sessionId?: string;\n readonly tool: ToolName;\n readonly transcriptPath?: string;\n}\n\nconst GENERIC_SESSION_SUFFIXES = new Set([\n 'default',\n 'hook',\n 'hook-session',\n 'process',\n 'session',\n 'unknown',\n]);\n\n/**\n * ๐Ÿ“– Some tool hooks only expose a placeholder session id such as\n * `opencode-session` or `codex:hook-session`. Treating those as canonical\n * collapses unrelated runs together, so AISnitch upgrades them when richer\n * metadata exists.\n */\nexport function isGenericSessionId(\n tool: ToolName,\n sessionId: string,\n): boolean {\n const normalizedSessionId = sessionId.trim().toLowerCase();\n const normalizedTool = tool.toLowerCase();\n\n if (normalizedSessionId.length === 0) {\n return true;\n }\n\n if (\n normalizedSessionId === 'hook-session' ||\n normalizedSessionId === 'session'\n ) {\n return true;\n }\n\n for (const suffix of GENERIC_SESSION_SUFFIXES) {\n if (\n normalizedSessionId === `${normalizedTool}:${suffix}` ||\n normalizedSessionId === `${normalizedTool}-${suffix}`\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Returns the best-effort stable session id for one event source.\n */\nexport function resolveSessionId(input: SessionIdentityInput): string {\n if (input.sessionId && !isGenericSessionId(input.tool, input.sessionId)) {\n return input.sessionId;\n }\n\n const scopeToken = sanitizeToken(\n input.project ??\n getPathTail(input.projectPath) ??\n getPathTail(input.cwd) ??\n getPathTail(input.activeFile) ??\n getPathTail(input.transcriptPath ? dirname(input.transcriptPath) : undefined),\n );\n const transcriptToken = sanitizeToken(\n input.transcriptPath\n ? basename(input.transcriptPath, extname(input.transcriptPath))\n : undefined,\n );\n const pidToken = input.pid ? `p${input.pid}` : undefined;\n const parts = [\n input.tool,\n scopeToken,\n transcriptToken && transcriptToken !== scopeToken ? transcriptToken : undefined,\n pidToken,\n ].filter((value): value is string => typeof value === 'string' && value.length > 0);\n\n if (parts.length > 1) {\n return parts.join(':');\n }\n\n return input.sessionId ?? `${input.tool}:session`;\n}\n\n/**\n * Formats a compact human-readable label for logs and the TUI.\n */\nexport function formatSessionLabel(input: SessionIdentityInput): string {\n const scopeLabel =\n input.project ??\n getPathTail(input.projectPath) ??\n getPathTail(input.cwd) ??\n getPathTail(input.activeFile);\n const parts = [\n scopeLabel,\n input.instanceTotal && input.instanceTotal > 1\n ? `#${input.instanceIndex ?? 1}/${input.instanceTotal}`\n : undefined,\n input.pid ? `pid ${input.pid}` : formatSessionShortId(input.tool, input.sessionId),\n ].filter((value): value is string => typeof value === 'string' && value.length > 0);\n\n return parts.length > 0 ? parts.join(' ยท ') : input.tool;\n}\n\n/**\n * Formats a short session-id fragment for UI display without losing all entropy.\n */\nexport function formatSessionShortId(\n tool: ToolName,\n sessionId: string | undefined,\n): string | undefined {\n if (!sessionId || isGenericSessionId(tool, sessionId)) {\n return undefined;\n }\n\n const withoutToolPrefix = sessionId.startsWith(`${tool}:`)\n ? sessionId.slice(tool.length + 1)\n : sessionId;\n\n if (withoutToolPrefix.length <= 16) {\n return withoutToolPrefix;\n }\n\n return `${withoutToolPrefix.slice(0, 6)}โ€ฆ${withoutToolPrefix.slice(-4)}`;\n}\n\n/**\n * Builds a display label directly from a normalized AISnitch event.\n */\nexport function formatSessionLabelFromEvent(event: AISnitchEvent): string {\n return formatSessionLabel({\n activeFile: event.data.activeFile,\n cwd: event.data.cwd,\n instanceIndex: event.data.instanceIndex,\n instanceTotal: event.data.instanceTotal,\n pid: event.data.pid,\n project: event.data.project,\n projectPath: event.data.projectPath,\n sessionId: event['aisnitch.sessionid'],\n tool: event['aisnitch.tool'],\n });\n}\n\nfunction getPathTail(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const pathParts = value.split(/[\\\\/]+/u).filter((part) => part.length > 0);\n\n return pathParts.at(-1);\n}\n\nfunction sanitizeToken(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n\n const normalizedToken = value\n .trim()\n .replace(/[\\\\/]+/gu, '-')\n .replace(/[^A-Za-z0-9._-]+/gu, '-')\n .replace(/-+/gu, '-')\n .replace(/^[-_.]+|[-_.]+$/gu, '');\n\n return normalizedToken.length > 0 ? normalizedToken : undefined;\n}\n","import { homedir } from 'node:os';\n\nimport { z } from 'zod';\n\nimport { logger } from '../core/engine/logger.js';\n\nimport { SHARED_BREAKERS } from '../core/circuit-breaker.js';\nimport type { AISnitchConfig } from '../core/config/schema.js';\nimport { createEvent } from '../core/events/factory.js';\nimport { EventDataSchema, createUuidV7 } from '../core/events/schema.js';\nimport type {\n AISnitchEvent,\n AISnitchEventType,\n EventData,\n ToolName,\n} from '../core/events/types.js';\n\n/**\n * @file src/adapters/base.ts\n * @description Shared adapter primitives for lifecycle management, normalized event emission, and idle/session tracking.\n * @functions\n * โ†’ none\n * @exports InterceptionStrategy, AdapterPublishContext, AdapterRuntimeOptions, AdapterStatus, NormalizedAdapterHookPayload, BaseAdapter\n * @see ./registry.ts\n * @see ./claude-code.ts\n * @see ./opencode.ts\n */\n\nconst NormalizedAdapterHookPayloadSchema = z.strictObject({\n type: z.string().min(1),\n source: z.string().min(1).optional(),\n sessionId: z.string().min(1).optional(),\n seqnum: z.number().int().min(1).optional(),\n data: EventDataSchema.partial().optional(),\n pid: z.number().int().positive().optional(),\n transcriptPath: z.string().min(1).optional(),\n cwd: z.string().min(1).optional(),\n env: z.record(z.string(), z.string()).optional(),\n hookPayload: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Capture strategies supported by built-in and future community adapters.\n */\nexport type InterceptionStrategy =\n | 'hooks'\n | 'jsonl-watch'\n | 'log-watch'\n | 'sqlite-watch'\n | 'stream-json'\n | 'process-detect'\n | 'pty-wrap'\n | 'api-client';\n\n/**\n * Extra context that adapters can provide alongside emitted events.\n */\nexport interface AdapterPublishContext {\n readonly cwd?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly hookPayload?: Record<string, unknown>;\n readonly pid?: number;\n readonly sessionId?: string;\n readonly source?: string;\n readonly transcriptPath?: string;\n}\n\n/**\n * Dependency injection contract shared by all adapters.\n */\nexport interface AdapterRuntimeOptions {\n readonly config: AISnitchConfig;\n readonly env?: NodeJS.ProcessEnv;\n readonly homeDirectory?: string;\n readonly publishEvent: (\n event: AISnitchEvent,\n context?: AdapterPublishContext,\n ) => Promise<boolean>;\n}\n\n/**\n * Observable adapter runtime state exposed to the registry and CLI.\n */\nexport interface AdapterStatus {\n readonly activeSessions: number;\n readonly displayName: string;\n readonly eventsEmitted: number;\n readonly name: ToolName;\n readonly running: boolean;\n readonly strategies: readonly InterceptionStrategy[];\n}\n\n/**\n * Best-effort normalized payload shape accepted from hook/plugin bridges.\n */\nexport type NormalizedAdapterHookPayload = z.infer<\n typeof NormalizedAdapterHookPayloadSchema\n>;\n\n/**\n * ๐Ÿ“– Every concrete adapter gets the same boring-but-essential plumbing here:\n * session ids, sequence numbers, idle timers, and validated event emission.\n */\nexport abstract class BaseAdapter {\n public abstract readonly displayName: string;\n\n public abstract readonly name: ToolName;\n\n public abstract readonly strategies: readonly InterceptionStrategy[];\n\n protected currentSessionId: string | null = null;\n\n protected readonly env: NodeJS.ProcessEnv | undefined;\n\n protected readonly homeDirectory: string;\n\n protected sequenceNumber = 0;\n\n private readonly activeSessions = new Set<string>();\n\n private eventsEmitted = 0;\n\n private idleTimer: NodeJS.Timeout | null = null;\n\n private readonly idleTimeoutMs: number;\n\n private readonly publishEventImplementation: AdapterRuntimeOptions['publishEvent'];\n\n private running = false;\n\n protected constructor(options: AdapterRuntimeOptions) {\n this.env = options.env;\n this.homeDirectory = options.homeDirectory ?? homedir();\n this.idleTimeoutMs = options.config.idleTimeoutMs;\n this.publishEventImplementation = options.publishEvent;\n }\n\n /**\n * Starts the adapter-specific watchers, pollers, or hook bridges.\n */\n public abstract start(): Promise<void>;\n\n /**\n * Stops adapter-specific resources and clears runtime state.\n */\n public abstract stop(): Promise<void>;\n\n /**\n * Hook-based adapters override this to transform tool-native payloads.\n */\n public handleHook(_payload: unknown): Promise<void> {\n return Promise.reject(\n new Error(`${this.name} does not support hook payloads.`),\n );\n }\n\n /**\n * Returns the current observable adapter status snapshot.\n */\n public getStatus(): AdapterStatus {\n return {\n activeSessions: this.activeSessions.size,\n displayName: this.displayName,\n eventsEmitted: this.eventsEmitted,\n name: this.name,\n running: this.running,\n strategies: this.strategies,\n };\n }\n\n /**\n * Accepts the normalized hook payload shape used by setup-installed bridges.\n */\n protected parseNormalizedHookPayload(\n payload: unknown,\n ): NormalizedAdapterHookPayload | null {\n const parsedPayload = NormalizedAdapterHookPayloadSchema.safeParse(payload);\n\n if (!parsedPayload.success) {\n return null;\n }\n\n return parsedPayload.data;\n }\n\n /**\n * Emits one already-normalized payload through the common adapter lifecycle.\n */\n protected async emitNormalizedPayload(\n payload: NormalizedAdapterHookPayload,\n ): Promise<boolean> {\n return await this.emit(payload.type as AISnitchEventType, payload.data, {\n cwd: payload.cwd,\n env: payload.env,\n hookPayload: payload.hookPayload,\n pid: payload.pid,\n sessionId: payload.sessionId,\n source: payload.source,\n transcriptPath: payload.transcriptPath,\n });\n }\n\n /**\n * Emits a fully normalized AISnitch event and updates idle/session tracking.\n */\n protected async emit(\n type: AISnitchEventType,\n data: Omit<EventData, 'state'> = {},\n context: AdapterPublishContext = {},\n ): Promise<boolean> {\n const sessionId = this.resolveSessionId(context.sessionId);\n\n this.sequenceNumber += 1;\n\n const event = createEvent({\n source: context.source ?? `aisnitch://adapters/${this.name}`,\n type,\n 'aisnitch.tool': this.name,\n 'aisnitch.sessionid': sessionId,\n 'aisnitch.seqnum': this.sequenceNumber,\n data: {\n ...data,\n cwd: data.cwd ?? context.cwd,\n },\n });\n\n /**\n * Publishes event through circuit breaker to prevent cascading failures.\n * If circuit is open, returns false immediately.\n */\n let published: boolean;\n\n try {\n published = await SHARED_BREAKERS.adapterEmit.execute(async () => {\n return await this.publishEventImplementation(event, {\n cwd: context.cwd,\n env: context.env,\n hookPayload: context.hookPayload,\n pid: context.pid,\n sessionId,\n source: context.source,\n transcriptPath: context.transcriptPath,\n });\n });\n } catch (error: unknown) {\n // CircuitOpenError or other error โ€” log and return false, never crash\n if (error instanceof Error && error.name === 'CircuitOpenError') {\n logger.warn(\n { error, eventType: type, adapter: this.name },\n '๐Ÿ“– Adapter emit blocked by open circuit โ€” event dropped',\n );\n } else {\n logger.error(\n { error, eventType: type, adapter: this.name, sessionId },\n '๐Ÿ“– Failed to publish event โ€” swallowing to prevent daemon crash',\n );\n }\n published = false;\n }\n\n if (published) {\n this.eventsEmitted += 1;\n }\n\n if (type === 'session.end') {\n this.activeSessions.delete(sessionId);\n\n if (this.currentSessionId === sessionId) {\n this.currentSessionId = null;\n }\n\n this.clearIdleTimer();\n\n return published;\n }\n\n if (type !== 'agent.idle') {\n this.resetIdleTimer();\n }\n\n return published;\n }\n\n /**\n * Shortcut for emitting a plain state transition without extra boilerplate.\n */\n protected async emitStateChange(\n type: AISnitchEventType,\n data: Omit<EventData, 'state'> = {},\n context: AdapterPublishContext = {},\n ): Promise<boolean> {\n return await this.emit(type, data, context);\n }\n\n /**\n * Updates the active session id while keeping sequence numbers monotonic per session.\n */\n protected setSessionId(sessionId: string | null): void {\n if (sessionId === null) {\n this.currentSessionId = null;\n this.clearIdleTimer();\n return;\n }\n\n if (this.currentSessionId !== sessionId) {\n this.sequenceNumber = 0;\n }\n\n this.currentSessionId = sessionId;\n this.activeSessions.add(sessionId);\n }\n\n /**\n * Marks the adapter runtime as active or stopped.\n */\n protected setRunning(running: boolean): void {\n this.running = running;\n\n if (!running) {\n this.clearIdleTimer();\n this.currentSessionId = null;\n this.sequenceNumber = 0;\n this.activeSessions.clear();\n }\n }\n\n /**\n * Shared helper for adapters that need a stable testable home directory.\n */\n protected getUserHomeDirectory(): string {\n return this.homeDirectory;\n }\n\n private clearIdleTimer(): void {\n if (this.idleTimer !== null) {\n clearTimeout(this.idleTimer);\n this.idleTimer = null;\n }\n }\n\n private resetIdleTimer(): void {\n if (!this.running || this.currentSessionId === null) {\n return;\n }\n\n this.clearIdleTimer();\n this.idleTimer = setTimeout(() => {\n if (this.currentSessionId === null) {\n return;\n }\n\n void this.emitStateChange('agent.idle');\n }, this.idleTimeoutMs);\n this.idleTimer.unref();\n }\n\n private resolveSessionId(sessionId?: string): string {\n if (sessionId !== undefined) {\n this.setSessionId(sessionId);\n\n return sessionId;\n }\n\n if (this.currentSessionId === null) {\n this.setSessionId(`${this.name}:${createUuidV7()}`);\n }\n\n if (this.currentSessionId === null) {\n throw new Error(`Adapter \"${this.name}\" failed to resolve a session id.`);\n }\n\n return this.currentSessionId;\n }\n}\n","/**\n * @file src/core/errors.ts\n * @description Centralized error hierarchy for AISnitch with typed error codes and context.\n *\n * This module provides a consistent error taxonomy across the entire application:\n * - `AISnitchError` โ€” base class for all AISnitch-specific errors\n * - `AdapterError` โ€” adapter lifecycle, parsing, or emission failures\n * - `PipelineError` โ€” pipeline orchestration, component startup, or shutdown failures\n * - `ValidationError` โ€” Zod parsing failures and schema violations\n * - `NetworkError` โ€” HTTP, WebSocket, or Unix Domain Socket failures\n * - `TimeoutError` โ€” async operations that exceed their deadline\n *\n * Each error carries a machine-readable `code` field for programmatic handling\n * and an optional `context` bag for debugging. Errors serialize cleanly to JSON\n * so they can be logged via pino without losing structure.\n *\n * @functions\n * โ†’ none\n * @exports AISnitchError, AdapterError, PipelineError, ValidationError, NetworkError, TimeoutError, isAISnitchError, isRetryableError\n * @see ./result.ts\n * @see ./retry.ts\n * @see ./timeout.ts\n */\n\n/**\n * Base class for all AISnitch-specific errors.\n *\n * @example\n * ```typescript\n * throw new AISnitchError(\n * 'Event validation failed',\n * 'EVENT_VALIDATION_ERROR',\n * { eventId: event.id, issues: parseResult.error.issues }\n * );\n * ```\n */\nexport class AISnitchError extends Error {\n /**\n * Machine-readable error code for programmatic handling.\n * Format: `SUBCATEGORY_SPECIFIC_DETAIL` (uppercase with underscores).\n */\n public readonly code: string;\n\n /**\n * Arbitrary context bag forwarded to the logger for structured debugging.\n */\n public readonly context?: Readonly<Record<string, unknown>>;\n\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message);\n this.name = 'AISnitchError';\n this.code = code;\n this.context = context;\n\n // Maintains proper stack trace in V8 engines (Node.js, Chrome, Edge)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AISnitchError);\n }\n }\n\n /**\n * Full error chain for logging: `[name] code โ€” message`.\n */\n public override toString(): string {\n return `${this.name} [${this.code}] โ€” ${this.message}`;\n }\n\n /**\n * JSON serialization friendly to pino serializers.\n */\n public toJSON(): object {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Errors originating from adapter lifecycle, payload parsing, or event emission.\n *\n * @example\n * ```typescript\n * throw new AdapterError(\n * 'Claude Code transcript read failed',\n * 'ADAPTER_CLAUDE_CODE_FILE_ERROR',\n * { filePath: transcriptPath, cause: error }\n * );\n * ```\n */\nexport class AdapterError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'AdapterError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AdapterError);\n }\n }\n\n /**\n * Factory for adapter-specific errors with auto-generated codes.\n */\n public static withAutoCode(\n message: string,\n tool: string,\n context?: Readonly<Record<string, unknown>>,\n ): AdapterError {\n const sanitizedTool = tool.replace(/[^a-z0-9]/gi, '_').toUpperCase();\n const code = `ADAPTER_${sanitizedTool}_ERROR`;\n\n return new AdapterError(message, code, { tool, ...context });\n }\n}\n\n/**\n * Errors originating from pipeline orchestration, component startup, or shutdown.\n *\n * @example\n * ```typescript\n * throw new PipelineError(\n * 'Failed to start WebSocket server',\n * 'PIPELINE_WS_START_FAILED',\n * { port: configuredPort, cause: error }\n * );\n * ```\n */\nexport class PipelineError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'PipelineError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, PipelineError);\n }\n }\n}\n\n/**\n * Errors from Zod schema parsing failures and data validation violations.\n *\n * @example\n * ```typescript\n * const result = EventDataSchema.safeParse(rawPayload);\n * if (!result.success) {\n * throw new ValidationError(\n * 'Invalid event data payload',\n * 'VALIDATION_EVENT_DATA_INVALID',\n * { issues: result.error.issues }\n * );\n * }\n * ```\n */\nexport class ValidationError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'ValidationError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ValidationError);\n }\n }\n}\n\n/**\n * Errors from network operations: HTTP requests, WebSocket connections, UDS.\n *\n * @example\n * ```typescript\n * throw new NetworkError(\n * 'Health endpoint unreachable',\n * 'NETWORK_HTTP_CONNECT_FAILED',\n * { host: '127.0.0.1', port: 4821, cause: error }\n * );\n * ```\n */\nexport class NetworkError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'NetworkError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, NetworkError);\n }\n }\n}\n\n/**\n * Errors from async operations that exceed their configured deadline.\n *\n * @example\n * ```typescript\n * throw new TimeoutError(\n * 'Adapter stop timed out after 5 seconds',\n * 'TIMEOUT_SHUTDOWN',\n * { component: 'ClaudeCodeAdapter', timeoutMs: 5_000 }\n * );\n * ```\n */\nexport class TimeoutError extends AISnitchError {\n public constructor(\n message: string,\n code: string,\n context?: Readonly<Record<string, unknown>>,\n ) {\n super(message, code, context);\n this.name = 'TimeoutError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TimeoutError);\n }\n }\n}\n\n/**\n * Type guard to narrow any `unknown` error to an AISnitch error.\n *\n * @example\n * ```typescript\n * } catch (error: unknown) {\n * if (isAISnitchError(error)) {\n * console.error(`AISnitch error ${error.code}: ${error.message}`);\n * } else {\n * console.error('Unexpected error', error);\n * }\n * }\n * ```\n */\nexport function isAISnitchError(error: unknown): error is AISnitchError {\n return error instanceof AISnitchError;\n}\n\n/**\n * Determines whether an error is safe to retry (transient vs. permanent).\n *\n * Returns `true` for network timeouts, connection reset, and rate-limit errors.\n * Returns `false` for validation errors, authentication failures, and programming bugs.\n *\n * @example\n * ```typescript\n * try {\n * return await operation();\n * } catch (error: unknown) {\n * if (isRetryableError(error)) {\n * throw error; // let retry logic handle it\n * }\n * throw error; // propagate as-is (non-retryable)\n * }\n * ```\n */\nexport function isRetryableError(error: unknown): boolean {\n if (!isAISnitchError(error)) {\n // Native JS errors: network failures, ECONNREFUSED, ETIMEDOUT are retryable\n if (error instanceof Error) {\n const code = (error as NodeJS.ErrnoException).code;\n const retryableCodes = new Set([\n 'ECONNREFUSED',\n 'ECONNRESET',\n 'ETIMEDOUT',\n 'ENOTFOUND',\n 'EHOSTUNREACH',\n 'EPIPE',\n 'EPERM', // sometimes transient on macOS file locks\n ]);\n\n if (typeof code === 'string' && retryableCodes.has(code)) {\n return true;\n }\n }\n\n return false;\n }\n\n // AISnitch errors: timeout and network errors are retryable\n const retryableCategories = new Set(['TIMEOUT', 'NETWORK']);\n\n for (const category of retryableCategories) {\n if (error.code.startsWith(category)) {\n return true;\n }\n }\n\n // Adapter errors with specific patterns\n const retryablePatterns = [\n /^ADAPTER_.*_(FILE_IO|NETWORK|PROCESS_DETECT)_ERROR$/,\n /^PIPELINE_.*_(RETRY|RECONNECT)_ERROR$/,\n ];\n\n for (const pattern of retryablePatterns) {\n if (pattern.test(error.code)) {\n return true;\n }\n }\n\n return false;\n}\n","/**\n * @file src/core/circuit-breaker.ts\n * @description Circuit breaker pattern implementation for resilient adapter operation.\n *\n * The circuit breaker prevents cascading failures when an adapter repeatedly fails:\n *\n * ```\n * CLOSED (normal) โ”€โ”€[N failures]โ”€โ”€โ†’ OPEN (failing fast)\n * โ†‘ โ”‚\n * โ”‚ [half-open after timeout]\n * โ”‚ โ†“\n * โ””โ”€โ”€โ”€โ”€โ”€โ”€[success]โ”€โ”€โ”€โ”€ HALF-OPEN (testing recovery)\n * ```\n *\n * When an adapter fails `threshold` times within `windowMs`, the breaker opens:\n * - Subsequent calls fail immediately with `CircuitOpenError` (no network round-trips)\n * - After `halfOpenAfterMs`, one test call is allowed to check recovery\n * - If it succeeds โ†’ close the circuit (back to normal operation)\n * - If it fails โ†’ reopen and wait again\n *\n * ## When to use this\n *\n * - Adapter `emit()` calls that can fail repeatedly (file system errors, hook timeouts)\n * - Network operations with unreliable backends\n * - Any operation where persistent failure is worse than temporary unavailability\n *\n * ## When NOT to use this\n *\n * - One-off errors that are unlikely to repeat\n * - Validation failures (these indicate a programming bug, not a transient fault)\n * - Operations that are already idempotent with built-in retry (prefer `withRetry`)\n *\n * @functions\n * โ†’ none\n * @exports CircuitState, CircuitOpenError, CircuitBreaker\n * @see ./errors.ts\n * @see ./retry.ts\n * @see ./timeout.ts\n */\n\nimport { AISnitchError, isRetryableError } from './errors.js';\nimport { logger } from './engine/logger.js';\n\n/**\n * Observable state of a circuit breaker.\n */\nexport interface CircuitState {\n /**\n * Number of consecutive failures since last success.\n */\n readonly failures: number;\n /**\n * Timestamp of the last failure (ms since epoch), or null if never failed.\n */\n readonly lastFailureAt: number | null;\n /**\n * Current state of the circuit.\n * - `closed`: Normal operation, requests pass through\n * - `open`: Failing fast, requests are rejected immediately\n * - `half-open`: Testing recovery, one request is allowed through\n */\n readonly state: 'closed' | 'open' | 'half-open';\n}\n\n/**\n * Error thrown when a circuit is open and the operation is rejected.\n */\nexport class CircuitOpenError extends AISnitchError {\n public constructor(\n public readonly circuitId: string,\n public readonly state: CircuitState,\n ) {\n super(\n `Circuit \"${circuitId}\" is OPEN โ€” operation rejected`,\n 'CIRCUIT_OPEN',\n { circuitId, failures: state.failures, lastFailureAt: state.lastFailureAt },\n );\n this.name = 'CircuitOpenError';\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CircuitOpenError);\n }\n }\n\n public override toString(): string {\n return `${this.name} [${this.code}] \"${this.circuitId}\" โ€” failures=${this.state.failures}`;\n }\n}\n\n/**\n * Configuration for a circuit breaker instance.\n */\nexport interface CircuitBreakerOptions {\n /**\n * Number of consecutive failures before opening the circuit.\n * @default 5\n */\n readonly failureThreshold?: number;\n /**\n * Time window in milliseconds to count failures within.\n * @default 60_000 (1 minute)\n */\n readonly windowMs?: number;\n /**\n * Time to wait before transitioning from OPEN to HALF-OPEN.\n * @default 30_000 (30 seconds)\n */\n readonly halfOpenAfterMs?: number;\n /**\n * Human-readable identifier for this circuit (shown in logs).\n * @default 'unnamed'\n */\n readonly id?: string;\n /**\n * Optional predicate to decide which errors count toward the threshold.\n * Return `true` to count as a failure, `false` to ignore (success-like failure).\n * @default isRetryableError\n */\n readonly shouldCountAsFailure?: (error: unknown) => boolean;\n /**\n * Set to `true` to reset the failure counter after any success in CLOSED state.\n * Set to `false` to only reset after `failureThreshold` successes.\n * @default true\n */\n readonly resetOnSuccess?: boolean;\n}\n\nconst DEFAULT_OPTIONS: Required<CircuitBreakerOptions> = {\n failureThreshold: 5,\n halfOpenAfterMs: 30_000,\n id: 'unnamed',\n resetOnSuccess: true,\n shouldCountAsFailure: isRetryableError,\n windowMs: 60_000,\n};\n\n/**\n * Circuit breaker state machine.\n *\n * ## State transitions\n *\n * ```\n * CLOSED โ”€โ”€[failure + threshold reached]โ”€โ”€โ†’ OPEN\n * โ–ฒ โ”‚\n * โ”‚ [halfOpenAfterMs elapsed]\n * โ”‚ โ†“\n * โ”‚ HALF-OPEN\n * โ”‚ โ”‚\n * โ”‚ [test call succeeds]\n * โ”‚ โ†“\n * โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€[reset]โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n * ```\n *\n * ## Usage\n *\n * ```typescript\n * const breaker = new CircuitBreaker({\n * id: 'claude-code.emit',\n * failureThreshold: 3,\n * windowMs: 60_000,\n * });\n *\n * async function safeEmit(event: AISnitchEvent) {\n * return breaker.execute(() => adapter.emit(event));\n * }\n * ```\n */\nexport class CircuitBreaker {\n private failures = 0;\n private lastFailureAt: number | null = null;\n private state: CircuitState['state'] = 'closed';\n private halfOpenTestStartedAt: number | null = null;\n\n private readonly options: Required<CircuitBreakerOptions>;\n\n public constructor(options: CircuitBreakerOptions = {}) {\n this.options = {\n ...DEFAULT_OPTIONS,\n ...options,\n // Re-spread to ensure all fields have defaults\n failureThreshold: options.failureThreshold ?? DEFAULT_OPTIONS.failureThreshold,\n halfOpenAfterMs: options.halfOpenAfterMs ?? DEFAULT_OPTIONS.halfOpenAfterMs,\n id: options.id ?? DEFAULT_OPTIONS.id,\n resetOnSuccess: options.resetOnSuccess ?? DEFAULT_OPTIONS.resetOnSuccess,\n shouldCountAsFailure: options.shouldCountAsFailure ?? DEFAULT_OPTIONS.shouldCountAsFailure,\n windowMs: options.windowMs ?? DEFAULT_OPTIONS.windowMs,\n };\n }\n\n /**\n * Executes an async operation through the circuit breaker.\n *\n * - If the circuit is CLOSED โ†’ runs `fn` and updates state based on result\n * - If the circuit is HALF-OPEN โ†’ runs `fn` once to test recovery\n * - If the circuit is OPEN โ†’ throws `CircuitOpenError` immediately (no call)\n *\n * @param fn - The async operation to protect\n * @returns The result of `fn` if successful\n * @throws CircuitOpenError if the circuit is OPEN\n * @throws The error from `fn` if it throws (and `shouldCountAsFailure` returns true)\n */\n public async execute<T>(fn: () => Promise<T>): Promise<T> {\n switch (this.state) {\n case 'closed':\n return this.executeClosed(fn);\n case 'half-open':\n return this.executeHalfOpen(fn);\n case 'open':\n if (this.shouldTransitionToHalfOpen()) {\n this.transitionToHalfOpen();\n return this.executeHalfOpen(fn);\n }\n throw new CircuitOpenError(this.options.id, this.getState());\n // no default\n }\n }\n\n /**\n * Returns the current observable circuit state.\n */\n public getState(): CircuitState {\n return {\n failures: this.failures,\n lastFailureAt: this.lastFailureAt,\n state: this.state,\n };\n }\n\n /**\n * Forces the circuit to CLOSED (resets failure count and state).\n * Useful for manual recovery after a known-fix or after a maintenance window.\n */\n public reset(): void {\n this.failures = 0;\n this.lastFailureAt = null;\n this.state = 'closed';\n this.halfOpenTestStartedAt = null;\n\n logger.debug({ circuitId: this.options.id }, 'Circuit breaker manually reset');\n }\n\n /**\n * Pre-warms the circuit by performing one test call in HALF-OPEN state.\n * If the circuit is already HALF-OPEN, this does nothing.\n * If the circuit is CLOSED, this does nothing.\n */\n public async preWarm(fn: () => Promise<void>): Promise<void> {\n if (this.state !== 'open') {\n return;\n }\n\n this.transitionToHalfOpen();\n\n try {\n await fn();\n this.transitionToClosed();\n } catch {\n this.transitionToOpen();\n }\n }\n\n // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n // Private methods\n // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n private async executeClosed<T>(fn: () => Promise<T>): Promise<T> {\n try {\n const result = await fn();\n\n this.onSuccess();\n return result;\n } catch (error) {\n this.onFailure(error);\n throw error;\n }\n }\n\n private async executeHalfOpen<T>(fn: () => Promise<T>): Promise<T> {\n this.halfOpenTestStartedAt = Date.now();\n\n try {\n const result = await fn();\n\n this.transitionToClosed();\n return result;\n } catch (error) {\n this.transitionToOpen();\n throw error;\n }\n }\n\n private onSuccess(): void {\n if (this.options.resetOnSuccess) {\n // Immediately reset failure count on any success\n this.failures = 0;\n this.lastFailureAt = null;\n } else {\n // Decrement counter but don't go below zero\n this.failures = Math.max(0, this.failures - 1);\n\n if (this.failures === 0) {\n this.lastFailureAt = null;\n }\n }\n\n logger.debug(\n {\n circuitId: this.options.id,\n failures: this.failures,\n },\n 'Circuit breaker operation succeeded',\n );\n }\n\n private onFailure(error: unknown): void {\n if (!this.options.shouldCountAsFailure(error)) {\n // Error is not counted as a failure (e.g., validation error)\n logger.debug(\n { circuitId: this.options.id, error },\n 'Circuit breaker operation failed but error is not counted as failure',\n );\n return;\n }\n\n this.failures += 1;\n this.lastFailureAt = Date.now();\n\n // Check if we've exceeded the threshold\n if (this.failures >= this.options.failureThreshold) {\n this.transitionToOpen();\n } else {\n logger.debug(\n {\n circuitId: this.options.id,\n failures: this.failures,\n threshold: this.options.failureThreshold,\n },\n 'Circuit breaker recorded failure',\n );\n }\n }\n\n private transitionToOpen(): void {\n if (this.state === 'open') {\n return; // Already open, no transition needed\n }\n\n this.state = 'open';\n this.halfOpenTestStartedAt = null;\n\n logger.warn(\n {\n circuitId: this.options.id,\n failures: this.failures,\n windowMs: this.options.windowMs,\n },\n '๐Ÿ”ด Circuit breaker OPEN โ€” blocking operations',\n );\n }\n\n private transitionToHalfOpen(): void {\n this.state = 'half-open';\n this.halfOpenTestStartedAt = Date.now();\n\n logger.info(\n { circuitId: this.options.id },\n '๐ŸŸก Circuit breaker HALF-OPEN โ€” testing recovery',\n );\n }\n\n private transitionToClosed(): void {\n this.state = 'closed';\n this.failures = 0;\n this.lastFailureAt = null;\n this.halfOpenTestStartedAt = null;\n\n logger.info(\n { circuitId: this.options.id },\n '๐ŸŸข Circuit breaker CLOSED โ€” recovery successful',\n );\n }\n\n private shouldTransitionToHalfOpen(): boolean {\n if (this.lastFailureAt === null) {\n // Never failed, should open immediately for testing\n return true;\n }\n\n const elapsed = Date.now() - this.lastFailureAt;\n return elapsed >= this.options.halfOpenAfterMs;\n }\n}\n\n/**\n * Shared circuit breaker instances for common AISnitch operations.\n * These are module-level singletons to avoid creating new breakers on every call.\n *\n * Usage:\n * ```typescript\n * import { SHARED_BREAKERS } from './circuit-breaker.js';\n *\n * // Wrap an adapter emit call\n * await SHARED_BREAKERS.adapterEmit.execute(() => adapter.emit(event));\n * ```\n */\nexport const SHARED_BREAKERS = Object.freeze({\n /**\n * Breaker for adapter event emission.\n * Threshold: 5 failures in 60s โ†’ open for 30s โ†’ half-open test.\n */\n adapterEmit: new CircuitBreaker({\n id: 'adapter.emit',\n failureThreshold: 5,\n halfOpenAfterMs: 30_000,\n shouldCountAsFailure: isRetryableError,\n windowMs: 60_000,\n }),\n\n /**\n * Breaker for file system operations (transcript reading, config loading).\n * More tolerant: 10 failures in 60s โ†’ open for 30s.\n */\n fileSystem: new CircuitBreaker({\n id: 'filesystem',\n failureThreshold: 10,\n halfOpenAfterMs: 30_000,\n windowMs: 60_000,\n }),\n\n /**\n * Breaker for HTTP/HTTPS requests.\n * Stricter: 3 failures in 30s โ†’ open for 15s.\n */\n httpRequest: new CircuitBreaker({\n id: 'http-request',\n failureThreshold: 3,\n halfOpenAfterMs: 15_000,\n windowMs: 30_000,\n }),\n\n /**\n * Breaker for process detection operations.\n * Most tolerant: 20 failures in 60s โ†’ open for 10s.\n */\n processDetection: new CircuitBreaker({\n id: 'process-detection',\n failureThreshold: 20,\n halfOpenAfterMs: 10_000,\n windowMs: 60_000,\n }),\n});\n","import { validate as isUuid, v7 as uuidv7, version as uuidVersion } from 'uuid';\nimport { z } from 'zod';\n\n/**\n * @file src/core/events/schema.ts\n * @description Runtime Zod schemas and constants for the AISnitch CloudEvents-based event contract.\n * @functions\n * โ†’ createUuidV7\n * @exports AISNITCH_EVENT_TYPES, TOOL_NAMES, ERROR_TYPES, CESP_CATEGORIES, ToolInputSchema, ToolCallNameSchema, ThinkingContentSchema, FinalMessageSchema, ToolResultSchema, MessageContentSchema, EventDataSchema, AISnitchEventTypeSchema, ToolNameSchema, ErrorTypeSchema, CESPCategorySchema, AISnitchEventSchema, createUuidV7\n * @see ./types.ts\n * @see ./cesp.ts\n * @see ./factory.ts\n */\n\n/**\n * ๐Ÿ“– AISnitch keeps the event-type list as a constant tuple so every schema,\n * inferred type, and mapping table stays aligned from one source of truth.\n */\nexport const AISNITCH_EVENT_TYPES = [\n 'session.start',\n 'session.end',\n 'task.start',\n 'task.complete',\n 'agent.thinking',\n 'agent.coding',\n 'agent.tool_call',\n 'agent.streaming',\n 'agent.asking_user',\n 'agent.idle',\n 'agent.error',\n 'agent.compact',\n] as const;\n\n/**\n * Supported AI tool identifiers recognized by AISnitch.\n */\nexport const TOOL_NAMES = [\n 'claude-code',\n 'opencode',\n 'gemini-cli',\n 'codex',\n 'goose',\n 'copilot-cli',\n 'cursor',\n 'aider',\n 'amp',\n 'cline',\n 'continue',\n 'windsurf',\n 'qwen-code',\n 'openclaw',\n 'openhands',\n 'kilo',\n 'devin',\n 'kiro',\n 'augment-code',\n 'mistral',\n 'zed',\n 'pi',\n 'unknown',\n] as const;\n\n/**\n * Normalized error categories attached to `agent.error` events.\n */\nexport const ERROR_TYPES = [\n 'rate_limit',\n 'context_overflow',\n 'tool_failure',\n 'api_error',\n] as const;\n\n/**\n * CESP-compatible categories used by the current mapping layer.\n */\nexport const CESP_CATEGORIES = [\n 'session.start',\n 'session.end',\n 'task.acknowledge',\n 'task.complete',\n 'input.required',\n 'task.error',\n 'resource.limit',\n] as const;\n\nconst ISO_TIMESTAMP_SCHEMA = z.string().datetime({ offset: true });\n\nfunction isUuidV7(value: string): boolean {\n return isUuid(value) && uuidVersion(value) === 7;\n}\n\nfunction isValidUriReference(value: string): boolean {\n if (value.trim().length === 0 || /\\s/u.test(value)) {\n return false;\n }\n\n try {\n new URL(value);\n return true;\n } catch {\n try {\n new URL(value, 'https://aisnitch.local');\n return true;\n } catch {\n return false;\n }\n }\n}\n\n/**\n * Generates a UUIDv7 value that matches the event schema contract.\n */\nexport function createUuidV7(): string {\n return uuidv7();\n}\n\n/**\n * Tool input metadata attached when an agent runs a concrete tool.\n */\nexport const ToolInputSchema = z\n .strictObject({\n filePath: z.string().min(1).max(4_096).optional(),\n command: z.string().min(1).max(10_000).optional(),\n })\n .refine(\n (value) => value.filePath !== undefined || value.command !== undefined,\n 'toolInput must include filePath or command',\n );\n\n/**\n * ๐Ÿ“– Thinking content extracted from AI model reasoning chains.\n * This field captures the internal \"thinking\" or reasoning output that\n * models like Claude produce before generating their final response.\n */\nexport const ThinkingContentSchema = z\n .string()\n .max(100_000)\n .describe('Raw thinking/reasoning content from the AI model');\n\n/**\n * ๐Ÿ“– Tool call name โ€” the specific tool being invoked.\n * Examples: \"Edit\", \"Bash\", \"Grep\", \"Read\", \"Write\", \"WebSearch\"\n * Different from `toolInput` which contains the tool's parameters.\n */\nexport const ToolCallNameSchema = z\n .string()\n .min(1)\n .max(100)\n .describe('Name of the tool being invoked (e.g., Edit, Bash, Grep)');\n\n/**\n * ๐Ÿ“– Final message shown at the end of an AI run.\n * This is typically a summary, completion message, or result text\n * displayed to the user after the agent finishes its work.\n */\nexport const FinalMessageSchema = z\n .string()\n .max(50_000)\n .describe('End-of-run summary or completion message');\n\n/**\n * ๐Ÿ“– Tool execution result โ€” short result from a tool call.\n * Can include success messages, error messages, or short outputs.\n */\nexport const ToolResultSchema = z\n .string()\n .max(10_000)\n .describe('Tool execution result or output');\n\n/**\n * ๐Ÿ“– Raw message content from AI responses.\n * Captures the actual text generated by the model before tool calls.\n */\nexport const MessageContentSchema = z\n .string()\n .max(100_000)\n .describe('Raw text content from AI messages');\n\n/**\n * Runtime schema for the supported tool names.\n */\nexport const ToolNameSchema = z.enum(TOOL_NAMES);\n\n/**\n * Runtime schema for AISnitch event types.\n */\nexport const AISnitchEventTypeSchema = z.enum(AISNITCH_EVENT_TYPES);\n\n/**\n * Runtime schema for normalized AISnitch error categories.\n */\nexport const ErrorTypeSchema = z.enum(ERROR_TYPES);\n\n/**\n * Runtime schema for CESP categories.\n */\nexport const CESPCategorySchema = z.enum(CESP_CATEGORIES);\n\n/**\n * ๐Ÿ“– `raw` remains intentionally permissive because adapters need a safe place\n * to stash source-native payload fragments without forcing them into the\n * normalized contract too early.\n */\nexport const EventDataSchema = z.strictObject({\n state: AISnitchEventTypeSchema,\n project: z.string().min(1).max(255).optional(),\n projectPath: z.string().min(1).max(4_096).optional(),\n duration: z.number().int().min(0).optional(),\n toolName: z.string().min(1).max(100).optional(),\n toolInput: ToolInputSchema.optional(),\n activeFile: z.string().min(1).max(4_096).optional(),\n model: z.string().min(1).max(200).optional(),\n tokensUsed: z.number().int().min(0).optional(),\n inputTokens: z.number().int().min(0).optional(),\n outputTokens: z.number().int().min(0).optional(),\n cachedTokens: z.number().int().min(0).optional(),\n errorMessage: z.string().min(1).max(10_000).optional(),\n errorType: ErrorTypeSchema.optional(),\n raw: z.record(z.string(), z.unknown()).optional(),\n terminal: z.string().min(1).max(100).optional(),\n cwd: z.string().min(1).max(4_096).optional(),\n pid: z.number().int().positive().optional(),\n instanceId: z.string().min(1).max(255).optional(),\n instanceIndex: z.number().int().min(1).optional(),\n instanceTotal: z.number().int().min(1).optional(),\n // New fields for enhanced content capture\n thinkingContent: ThinkingContentSchema.optional(),\n toolCallName: ToolCallNameSchema.optional(),\n finalMessage: FinalMessageSchema.optional(),\n toolResult: ToolResultSchema.optional(),\n messageContent: MessageContentSchema.optional(),\n});\n\n/**\n * Runtime schema for the full normalized AISnitch event envelope.\n */\nexport const AISnitchEventSchema = z.strictObject({\n specversion: z.literal('1.0'),\n id: z.string().refine(isUuidV7, 'id must be a valid UUIDv7 string'),\n source: z\n .string()\n .max(2_000)\n .refine(\n isValidUriReference,\n 'source must be a valid non-empty CloudEvents URI-reference',\n ),\n type: AISnitchEventTypeSchema,\n time: ISO_TIMESTAMP_SCHEMA,\n 'aisnitch.tool': ToolNameSchema,\n 'aisnitch.sessionid': z.string().min(1).max(500),\n 'aisnitch.seqnum': z.number().int().min(1),\n data: EventDataSchema,\n});\n","import { AISnitchEventSchema, createUuidV7 } from './schema.js';\nimport type { AISnitchEvent, CreateEventInput } from './types.js';\n\n/**\n * @file src/core/events/factory.ts\n * @description Factory helpers for producing validated AISnitch events with generated CloudEvents fields.\n * @functions\n * โ†’ createEvent\n * @exports createEvent\n * @see ./schema.ts\n */\n\n/**\n * Builds a fully valid AISnitch event by attaching CloudEvents metadata and\n * validating the final payload before it leaves the factory.\n */\nexport function createEvent(input: CreateEventInput): AISnitchEvent {\n const eventCandidate = {\n ...input,\n specversion: '1.0' as const,\n id: createUuidV7(),\n time: new Date().toISOString(),\n data: {\n state: input.data?.state ?? input.type,\n ...input.data,\n },\n };\n\n /**\n * ๐Ÿ“– Parsing at the factory boundary gives every future adapter the same\n * guardrail: if it emits junk, it fails immediately and loudly.\n */\n return AISnitchEventSchema.parse(eventCandidate);\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n AISnitchEventType,\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/claude-code.ts\n * @description Claude Code adapter covering official hooks, transcript JSONL enrichment, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports ClaudeCodeAdapter, ClaudeCodeAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/04-adapters-priority/02_adapters-priority_claude-code.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst CLAUDE_CODE_CODING_TOOLS = new Set([\n 'Edit',\n 'MultiEdit',\n 'NotebookEdit',\n 'Write',\n]);\n\nconst ASKING_USER_NOTIFICATION_TYPES = new Set([\n 'elicitation_dialog',\n 'idle_prompt',\n 'permission_prompt',\n]);\n\n/**\n * The official Claude hooks reference currently documents 25 lifecycle events,\n * including newer events such as SessionEnd, PostCompact, and ElicitationResult.\n * AISnitch only maps the subset that materially improves live activity tracking.\n */\nexport interface ClaudeCodeAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly projectsDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface ClaudeProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface ClaudeTranscriptObservation {\n readonly context: AdapterPublishContext;\n readonly data: Omit<EventData, 'state'>;\n readonly type: AISnitchEventType;\n}\n\n/**\n * ๐Ÿ“– Claude Code is AISnitch's richest adapter: hooks give precise state\n * transitions, JSONL fills in thinking/streaming detail, and process polling\n * covers the ugly \"hooks were never installed\" case.\n */\nexport class ClaudeCodeAdapter extends BaseAdapter {\n public override readonly displayName = 'Claude Code';\n\n public override readonly name = 'claude-code' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'jsonl-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly projectsDirectory: string;\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: ClaudeCodeAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ?? (async () => await execFile('pgrep', ['-lf', 'claude']).then((result) => result.stdout));\n this.projectsDirectory =\n options.projectsDirectory ??\n join(this.getUserHomeDirectory(), '.claude', 'projects');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n const transcriptGlob = join(this.projectsDirectory, '**', '*.jsonl');\n this.watcher = this.watcherFactory(transcriptGlob, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processTranscriptUpdate(filePath, true);\n });\n this.watcher.on('change', (filePath) => {\n void this.processTranscriptUpdate(filePath, false);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Claude transcript watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Claude hook payload must be an object');\n return;\n }\n\n const hookEventName =\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hook_type');\n\n if (!hookEventName) {\n logger.warn({ payload }, 'Claude hook payload is missing its event name');\n return;\n }\n\n const sessionId = resolveSessionId({\n activeFile: extractActiveFile(payload),\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath:\n getString(payload, 'project_path') ??\n getString(payload, 'projectPath'),\n sessionId:\n getString(payload, 'session_id') ??\n getString(payload, 'sessionId'),\n tool: this.name,\n transcriptPath:\n getString(payload, 'transcript_path') ??\n getString(payload, 'transcriptPath'),\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n // ๐Ÿ“– Pass process.env so the context detector can detect the terminal\n // from TERM_PROGRAM, ITERM_SESSION_ID, etc. โ€” hooks don't carry env vars\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/claude-code',\n transcriptPath:\n getString(payload, 'transcript_path') ??\n getString(payload, 'transcriptPath'),\n };\n const sharedData = {\n activeFile: extractActiveFile(payload),\n cwd: context.cwd,\n model: getString(payload, 'model'),\n projectPath:\n getString(payload, 'project_path') ??\n getString(payload, 'projectPath'),\n raw: payload,\n toolInput: extractClaudeToolInput(payload),\n toolName:\n getString(payload, 'tool_name') ??\n getString(payload, 'toolName'),\n } satisfies Omit<EventData, 'state'>;\n\n switch (hookEventName) {\n case 'SessionStart': {\n this.fallbackProcessSessionId = null;\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'SessionEnd': {\n const finalMessage = extractFinalMessageFromPayload(payload);\n await this.emitStateChange('session.end', {\n ...sharedData,\n finalMessage,\n }, context);\n return;\n }\n case 'UserPromptSubmit':\n case 'TaskCreated':\n case 'SubagentStart': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'Stop':\n case 'TaskCompleted':\n case 'SubagentStop': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'PreToolUse': {\n const toolCallName = extractToolNameFromPayload(payload);\n await this.emitStateChange('agent.tool_call', {\n ...sharedData,\n toolCallName,\n }, context);\n return;\n }\n case 'PostToolUse': {\n const toolCallName = extractToolNameFromPayload(payload);\n const toolResult = extractToolResultFromPayload(payload);\n const emittedType = isClaudeCodingTool(sharedData.toolName)\n ? 'agent.coding'\n : 'agent.tool_call';\n await this.emitStateChange(emittedType, {\n ...sharedData,\n toolCallName,\n toolResult,\n }, context);\n return;\n }\n case 'PostToolUseFailure':\n case 'StopFailure': {\n await this.emitStateChange(\n 'agent.error',\n {\n ...sharedData,\n errorMessage:\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n 'Claude Code hook failure',\n errorType:\n getClaudeErrorType(payload) ??\n 'tool_failure',\n },\n context,\n );\n return;\n }\n case 'PermissionRequest': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n case 'Notification': {\n const notificationType =\n getString(payload, 'notification_type') ??\n getString(payload, 'type');\n\n if (notificationType && ASKING_USER_NOTIFICATION_TYPES.has(notificationType)) {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n }\n\n return;\n }\n case 'PreCompact':\n case 'PostCompact': {\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n case 'TeammateIdle': {\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n default: {\n logger.debug({ hookEventName }, 'Claude hook event ignored by adapter');\n }\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Claude transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ??\n (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Claude transcript line is not valid JSON');\n return;\n }\n\n const observations = extractClaudeTranscriptObservations(\n parsedLine,\n transcriptPath,\n );\n\n for (const observation of observations) {\n await this.emitStateChange(\n observation.type,\n observation.data,\n observation.context,\n );\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n const files = await collectFilesRecursively(this.projectsDirectory, '.jsonl');\n\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollClaudeProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollClaudeProcesses();\n }\n\n private async pollClaudeProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `claude-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/claude-code/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/claude-code/process-detect',\n },\n );\n }\n }\n}\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, {\n withFileTypes: true,\n });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractClaudeTranscriptObservations(\n payload: unknown,\n transcriptPath: string,\n): ClaudeTranscriptObservation[] {\n if (!isRecord(payload)) {\n return [];\n }\n\n const sessionId = resolveSessionId({\n sessionId:\n getString(payload, 'session_id') ??\n basename(transcriptPath, '.jsonl'),\n tool: 'claude-code',\n transcriptPath,\n });\n const contentParts = extractClaudeContentParts(payload);\n const model =\n getString(payload, 'model') ??\n getString(getRecord(payload.message), 'model');\n const tokens = extractTokenUsageDetailed(payload);\n const rawPayload = payload;\n const sharedContext: AdapterPublishContext = {\n // ๐Ÿ“– Pass process.env so terminal detection works from transcript path too\n env: process.env,\n hookPayload: rawPayload,\n sessionId,\n source: 'aisnitch://adapters/claude-code/transcript',\n transcriptPath,\n };\n const sharedData = {\n model,\n raw: rawPayload,\n tokensUsed: tokens.total,\n inputTokens: tokens.input,\n outputTokens: tokens.output,\n cachedTokens: tokens.cached,\n } satisfies Omit<EventData, 'state'>;\n const observations: ClaudeTranscriptObservation[] = [];\n\n if (contentParts.some((part) => part.type === 'thinking')) {\n const thinkingParts = contentParts.filter((part) => part.type === 'thinking');\n // ๐Ÿ“– Extract thinking content from thinking-type content parts\n const thinkingText = thinkingParts\n .map((part) => {\n const text = part.text;\n return typeof text === 'string' ? text : undefined;\n })\n .filter((text): text is string => text !== undefined)\n .join('\\n');\n\n observations.push({\n context: sharedContext,\n data: {\n ...sharedData,\n thinkingContent: thinkingText.length > 0 ? thinkingText : undefined,\n },\n type: 'agent.thinking',\n });\n }\n\n if (\n contentParts.some(\n (part) =>\n part.type === 'text' &&\n typeof part.text === 'string' &&\n part.text.trim().length > 0,\n )\n ) {\n // ๐Ÿ“– Extract message content from text-type content parts\n const messageTexts = contentParts\n .filter((part) => part.type === 'text')\n .map((part) => part.text as string)\n .filter((text) => text.trim().length > 0);\n const messageContent = messageTexts.join('\\n');\n\n observations.push({\n context: sharedContext,\n data: {\n ...sharedData,\n messageContent: messageContent.length > 0 ? messageContent : undefined,\n },\n type: 'agent.streaming',\n });\n }\n\n // Check for tool_use observations (tool calls in transcript)\n const toolUseParts = contentParts.filter(\n (part) => part.type === 'tool_use' || part.type === 'toolUse',\n );\n if (toolUseParts.length > 0) {\n const toolName = getString(toolUseParts[0], 'name') ?? getString(toolUseParts[0], 'tool');\n if (toolName) {\n observations.push({\n context: sharedContext,\n data: {\n ...sharedData,\n toolCallName: toolName,\n },\n type: 'agent.tool_call',\n });\n }\n }\n\n return observations;\n}\n\nfunction extractClaudeContentParts(\n payload: Record<string, unknown>,\n): Array<Record<string, unknown>> {\n const message = getRecord(payload.message);\n const content = message?.content ?? payload.content;\n\n if (!Array.isArray(content)) {\n return [];\n }\n\n return content.filter(isRecord);\n}\n\n\nfunction extractTokenUsageDetailed(payload: Record<string, unknown>): {\n total?: number;\n input?: number;\n output?: number;\n cached?: number;\n} {\n const tokens = getNumber(payload, 'tokens');\n if (tokens !== undefined) {\n return { total: tokens };\n }\n const usage = getRecord(payload.usage);\n if (!usage) {\n return {};\n }\n const totalTokens = getNumber(usage, 'total_tokens');\n if (totalTokens !== undefined) {\n return {\n total: totalTokens,\n input: getNumber(usage, 'input_tokens'),\n output: getNumber(usage, 'output_tokens'),\n cached: getNumber(usage, 'cached_tokens'),\n };\n }\n const inputTokens = getNumber(usage, 'input_tokens') ?? 0;\n const outputTokens = getNumber(usage, 'output_tokens') ?? 0;\n const usageSum = inputTokens + outputTokens;\n return usageSum > 0 ? { total: usageSum, input: inputTokens, output: outputTokens } : {};\n}\n\nfunction extractClaudeToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);\n\n if (!toolInput) {\n return undefined;\n }\n\n const filePath =\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'path');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction extractActiveFile(payload: Record<string, unknown>): string | undefined {\n const toolInput = extractClaudeToolInput(payload);\n\n if (toolInput?.filePath) {\n return toolInput.filePath;\n }\n\n return (\n getString(payload, 'active_file') ??\n getString(payload, 'activeFile') ??\n getString(payload, 'file_path')\n );\n}\n\nfunction getClaudeErrorType(payload: Record<string, unknown>): ErrorType | undefined {\n const rawErrorType =\n getString(payload, 'error_type') ??\n getString(payload, 'errorType') ??\n getString(payload, 'stop_reason');\n\n switch (rawErrorType) {\n case 'rate_limit':\n return 'rate_limit';\n case 'max_output_tokens':\n case 'context_overflow':\n return 'context_overflow';\n case 'api_error':\n case 'server_error':\n case 'authentication_failed':\n case 'billing_error':\n case 'invalid_request':\n return 'api_error';\n default:\n return undefined;\n }\n}\n\nfunction isClaudeCodingTool(toolName?: string): boolean {\n return toolName !== undefined && CLAUDE_CODE_CODING_TOOLS.has(toolName);\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<ClaudeProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map(parseProcessLine)\n .filter((processInfo): processInfo is ClaudeProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode = isErrnoException(error) ? String(error.code) : '';\n\n if (isErrnoException(error) && (errorCode === 'ENOENT' || errorCode === '1')) {\n return [];\n }\n\n logger.debug({ error }, 'Claude process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): ClaudeProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException & { code?: string | number } {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the tool name from Claude hook payload.\n * Claude hooks use `tool_use` or `toolName` fields to identify the tool.\n * Common tool names: Edit, Bash, Grep, Read, Write, WebSearch, etc.\n */\nfunction extractToolNameFromPayload(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct tool name field\n const directToolName = getString(payload, 'tool_name') ?? getString(payload, 'toolName');\n\n if (directToolName) {\n return directToolName;\n }\n\n // From tool_use object\n const toolUse = getRecord(payload.tool_use) ?? getRecord(payload.toolUse);\n if (toolUse) {\n return getString(toolUse, 'name') ?? getString(toolUse, 'tool');\n }\n\n // From tool_input object (tool name might be in parent or type field)\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);\n if (toolInput) {\n return getString(toolInput, 'tool_name') ?? getString(toolInput, 'type');\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the tool execution result from Claude hook payload.\n * Contains success messages, error outputs, or short tool results.\n */\nfunction extractToolResultFromPayload(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct result field\n const directResult = getString(payload, 'result') ?? getString(payload, 'output');\n\n if (directResult) {\n return directResult;\n }\n\n // From tool_result object\n const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);\n if (toolResult) {\n return getString(toolResult, 'content') ?? getString(toolResult, 'output');\n }\n\n // From error field if PostToolUseFailure\n const errorField = getString(payload, 'error') ?? getString(payload, 'error_message');\n if (errorField) {\n return errorField;\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the final/completion message from Claude hook payload.\n * This is the summary text shown at the end of an AI run.\n */\nfunction extractFinalMessageFromPayload(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct final message fields\n const directMessage =\n getString(payload, 'final_message') ??\n getString(payload, 'finalMessage') ??\n getString(payload, 'summary') ??\n getString(payload, 'completion_message');\n\n if (directMessage) {\n return directMessage;\n }\n\n // From result or output fields\n const result =\n getString(payload, 'result') ??\n getString(payload, 'output') ??\n getString(payload, 'message');\n\n if (result) {\n return result;\n }\n\n // From session data or stats\n const stats = getRecord(payload.stats);\n if (stats) {\n return getString(stats, 'summary') ?? getString(stats, 'completion_summary');\n }\n\n return undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, dirname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { ErrorType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/copilot-cli.ts\n * @description Copilot CLI adapter covering repository hooks, passive session-state JSONL watching, workspace metadata enrichment, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports CopilotCLIAdapter, CopilotCLIAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/02_adapters-secondary_goose-copilot_DONE.md\n */\n\nconst execFile = promisify(execFileCallback);\nconst COPILOT_CODING_TOOL_HINT =\n /apply|create|delete|edit|insert|move|patch|rename|replace|write/iu;\n\nexport interface CopilotCLIAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly sessionStateDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface CopilotProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface CopilotSessionMetadata {\n readonly branch?: string;\n readonly cwd?: string;\n readonly gitRoot?: string;\n readonly model?: string;\n readonly repository?: string;\n readonly sessionId: string;\n}\n\n/**\n * ๐Ÿ“– Copilot's local session-state files are rich enough that hooks become a\n * precision upgrade rather than the only usable signal. The adapter therefore\n * merges both paths instead of trusting just one.\n */\nexport class CopilotCLIAdapter extends BaseAdapter {\n public override readonly displayName = 'Copilot CLI';\n\n public override readonly name = 'copilot-cli' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'jsonl-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly observedEventIds = new Set<string>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionMetadata = new Map<string, CopilotSessionMetadata>();\n\n private readonly sessionStateDirectory: string;\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: CopilotCLIAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'copilot']).then(\n (result) => result.stdout,\n ));\n this.sessionStateDirectory =\n options.sessionStateDirectory ??\n join(this.getUserHomeDirectory(), '.copilot', 'session-state');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n const transcriptGlob = join(this.sessionStateDirectory, '**', '*.jsonl');\n this.watcher = this.watcherFactory(transcriptGlob, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processTranscriptUpdate(filePath, true);\n });\n this.watcher.on('change', (filePath) => {\n void this.processTranscriptUpdate(filePath, false);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Copilot session-state watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.observedEventIds.clear();\n this.sessionMetadata.clear();\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Copilot hook payload must be an object');\n return;\n }\n\n const hookEventName =\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hookEventName');\n\n if (!hookEventName) {\n logger.warn({ payload }, 'Copilot hook payload is missing its event name');\n return;\n }\n\n const sessionMetadata = await this.resolveSessionMetadata(\n this.resolveRawSessionId(payload) ?? 'copilot-hook-session',\n );\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd') ?? sessionMetadata.cwd,\n project: sessionMetadata.repository,\n projectPath: sessionMetadata.gitRoot ?? sessionMetadata.cwd,\n sessionId: this.resolveRawSessionId(payload),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd') ?? sessionMetadata.cwd,\n hookPayload: payload,\n sessionId,\n source: 'aisnitch://adapters/copilot-cli',\n };\n const toolInput = extractCopilotHookToolInput(payload);\n const toolName =\n getString(payload, 'toolName') ?? getString(payload, 'tool_name');\n const toolResult =\n getRecord(payload.toolResult) ?? getRecord(payload.tool_result);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: sessionMetadata.model,\n project: sessionMetadata.repository,\n projectPath: sessionMetadata.gitRoot ?? sessionMetadata.cwd,\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (hookEventName) {\n case 'sessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'userPromptSubmitted': {\n await this.emitStateChange(\n 'task.start',\n {\n ...sharedData,\n raw: {\n ...payload,\n prompt: getString(payload, 'prompt'),\n },\n },\n context,\n );\n return;\n }\n case 'preToolUse': {\n const emittedType = isCopilotCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'postToolUse': {\n const emittedType = isCopilotCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n const resultType =\n getString(toolResult, 'resultType') ??\n getString(toolResult, 'result_type');\n const resultText =\n getString(toolResult, 'textResultForLlm') ??\n getString(toolResult, 'text_result_for_llm') ??\n getString(toolResult, 'message');\n\n if (resultType === 'failure' || resultType === 'denied') {\n await this.emitStateChange(\n 'agent.error',\n {\n ...sharedData,\n errorMessage:\n resultText ??\n `Copilot tool ${toolName ?? 'unknown'} finished with ${resultType}.`,\n errorType: inferCopilotErrorType(resultText) ?? 'tool_failure',\n raw: payload,\n },\n context,\n );\n return;\n }\n\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'sessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'errorOccurred': {\n const errorPayload = getRecord(payload.error);\n const errorMessage =\n getString(errorPayload, 'message') ??\n getString(payload, 'message');\n\n await this.emitStateChange(\n 'agent.error',\n {\n ...sharedData,\n errorMessage,\n errorType: inferCopilotErrorType(errorMessage),\n raw: payload,\n },\n context,\n );\n return;\n }\n default:\n logger.debug({ hookEventName }, 'Copilot hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Copilot transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ??\n (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n filePath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, filePath }, 'Copilot transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n const rawSessionId = this.resolveRawSessionId(parsedLine) ?? inferSessionIdFromPath(filePath);\n\n if (!rawSessionId) {\n return;\n }\n\n const metadata = await this.resolveSessionMetadata(rawSessionId, parsedLine, filePath);\n const sessionId = resolveSessionId({\n cwd: metadata.cwd,\n project: metadata.repository,\n projectPath: metadata.gitRoot ?? metadata.cwd,\n sessionId: rawSessionId,\n tool: this.name,\n });\n const eventId = getString(parsedLine, 'id');\n const dedupeKey = eventId ? `${sessionId}:${eventId}` : undefined;\n\n if (dedupeKey) {\n if (this.observedEventIds.has(dedupeKey)) {\n return;\n }\n\n if (this.observedEventIds.size >= 4096) {\n this.observedEventIds.clear();\n }\n\n this.observedEventIds.add(dedupeKey);\n }\n\n const context: AdapterPublishContext = {\n cwd: metadata.cwd,\n sessionId,\n source: 'aisnitch://adapters/copilot-cli/session-state',\n transcriptPath: filePath,\n };\n const eventType = getString(parsedLine, 'type');\n const eventData = getRecord(parsedLine.data);\n\n switch (eventType) {\n case 'session.start': {\n await this.emitStateChange(\n 'session.start',\n buildCopilotEventData(metadata, {\n raw: parsedLine,\n }),\n context,\n );\n await this.emitStateChange(\n 'agent.idle',\n buildCopilotEventData(metadata, {\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'user.message': {\n await this.emitStateChange(\n 'task.start',\n buildCopilotEventData(metadata, {\n raw: {\n ...parsedLine,\n prompt: getString(eventData, 'content'),\n },\n }),\n context,\n );\n return;\n }\n case 'assistant.message': {\n await this.processAssistantMessage(parsedLine, metadata, context);\n return;\n }\n case 'tool.execution_start': {\n const toolName = getString(eventData, 'toolName');\n const toolInput = extractCopilotToolInput(eventData);\n const emittedType = isCopilotCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n\n await this.emitStateChange(\n emittedType,\n buildCopilotEventData(metadata, {\n activeFile: toolInput?.filePath,\n raw: parsedLine,\n toolInput,\n toolName,\n }),\n context,\n );\n return;\n }\n case 'tool.execution_complete': {\n if (getBoolean(eventData, 'success') !== false) {\n return;\n }\n\n await this.emitStateChange(\n 'agent.error',\n buildCopilotEventData(metadata, {\n errorMessage:\n extractLooseString(getRecord(eventData?.result), ['content']) ??\n 'Tool execution failed',\n errorType: 'tool_failure',\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.task_complete': {\n await this.emitStateChange(\n 'task.complete',\n buildCopilotEventData(metadata, {\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.error': {\n const errorMessage = getString(eventData, 'message');\n\n await this.emitStateChange(\n 'agent.error',\n buildCopilotEventData(metadata, {\n errorMessage,\n errorType: inferCopilotErrorType(errorMessage),\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.warning': {\n await this.emitStateChange(\n 'agent.asking_user',\n buildCopilotEventData(metadata, {\n errorMessage: getString(eventData, 'message'),\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'abort': {\n await this.emitStateChange(\n 'agent.error',\n buildCopilotEventData(metadata, {\n errorMessage: 'Session aborted',\n errorType: 'api_error',\n raw: parsedLine,\n }),\n context,\n );\n return;\n }\n case 'session.model_change': {\n const model = getString(eventData, 'newModel');\n\n this.sessionMetadata.set(rawSessionId, {\n ...metadata,\n model: model ?? metadata.model,\n });\n return;\n }\n default:\n return;\n }\n }\n\n private async processAssistantMessage(\n payload: Record<string, unknown>,\n metadata: CopilotSessionMetadata,\n context: AdapterPublishContext,\n ): Promise<void> {\n const data = getRecord(payload.data);\n\n if (!data) {\n return;\n }\n\n const reasoningText = getString(data, 'reasoningText');\n const content = getString(data, 'content');\n\n if (reasoningText) {\n await this.emitStateChange(\n 'agent.thinking',\n buildCopilotEventData(metadata, {\n raw: {\n message: {\n content: [\n {\n thinking: reasoningText,\n type: 'thinking',\n },\n ],\n role: 'assistant',\n },\n source: payload,\n },\n }),\n context,\n );\n }\n\n if (content) {\n await this.emitStateChange(\n 'agent.streaming',\n buildCopilotEventData(metadata, {\n raw: {\n content,\n message: {\n content: [\n {\n text: content,\n type: 'text',\n },\n ],\n role: 'assistant',\n },\n source: payload,\n },\n }),\n context,\n );\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n const files = await collectFilesRecursively(\n this.sessionStateDirectory,\n '.jsonl',\n );\n\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollCopilotProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollCopilotProcesses();\n }\n\n private async pollCopilotProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `copilot-cli-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/copilot-cli/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/copilot-cli/process-detect',\n },\n );\n }\n }\n\n private resolveRawSessionId(payload: Record<string, unknown>): string | undefined {\n return (\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(getRecord(payload.data), 'sessionId') ??\n getString(getRecord(payload.data), 'session_id')\n );\n }\n\n private async resolveSessionMetadata(\n rawSessionId: string,\n payload?: Record<string, unknown>,\n filePath?: string,\n ): Promise<CopilotSessionMetadata> {\n const cachedMetadata = this.sessionMetadata.get(rawSessionId);\n const payloadMetadata = extractCopilotSessionMetadata(payload);\n\n if (payloadMetadata.cwd) {\n const mergedMetadata = {\n ...cachedMetadata,\n ...payloadMetadata,\n sessionId: rawSessionId,\n } satisfies CopilotSessionMetadata;\n\n this.sessionMetadata.set(rawSessionId, mergedMetadata);\n return mergedMetadata;\n }\n\n const fileMetadata = await readCopilotWorkspaceMetadata(\n this.sessionStateDirectory,\n rawSessionId,\n filePath,\n );\n const mergedMetadata = {\n ...cachedMetadata,\n ...fileMetadata,\n sessionId: rawSessionId,\n } satisfies CopilotSessionMetadata;\n\n this.sessionMetadata.set(rawSessionId, mergedMetadata);\n return mergedMetadata;\n }\n}\n\nfunction buildCopilotEventData(\n metadata: CopilotSessionMetadata,\n overrides: Partial<Omit<EventData, 'state'>> = {},\n): Omit<EventData, 'state'> {\n return {\n cwd: overrides.cwd ?? metadata.cwd,\n model: overrides.model ?? metadata.model,\n project: overrides.project ?? metadata.repository,\n projectPath: overrides.projectPath ?? metadata.gitRoot ?? metadata.cwd,\n raw: overrides.raw,\n ...overrides,\n };\n}\n\nfunction extractCopilotHookToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolArgsValue =\n getString(payload, 'toolArgs') ?? getString(payload, 'tool_args');\n const directArguments =\n getRecord(payload.arguments) ?? getRecord(payload.toolArgs);\n const parsedArguments =\n directArguments ?? parseJsonRecord(toolArgsValue);\n\n return extractCopilotToolInput(parsedArguments);\n}\n\nfunction extractCopilotToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const filePath = extractFirstString(payload, [\n 'file',\n 'file_path',\n 'filePath',\n 'path',\n 'target',\n 'target_path',\n 'targetPath',\n ]);\n const command = extractFirstString(payload, [\n 'cmd',\n 'command',\n 'script',\n ]);\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction isCopilotCodingTool(\n toolName: string | undefined,\n toolInput: ToolInput | undefined,\n): boolean {\n if (toolName && COPILOT_CODING_TOOL_HINT.test(toolName)) {\n return true;\n }\n\n const filePath = toolInput?.filePath;\n\n if (!filePath) {\n return false;\n }\n\n return !/glob|grep|list|read|search|view/iu.test(toolName ?? '');\n}\n\nfunction inferCopilotErrorType(\n errorMessage: string | undefined,\n): ErrorType | undefined {\n if (!errorMessage) {\n return undefined;\n }\n\n if (/quota|credit|rate limit|too many requests/iu.test(errorMessage)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|too long/iu.test(errorMessage)) {\n return 'context_overflow';\n }\n\n if (/tool/iu.test(errorMessage)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nfunction extractCopilotSessionMetadata(\n payload: Record<string, unknown> | undefined,\n): Partial<CopilotSessionMetadata> {\n const data = getRecord(payload?.data);\n const context = getRecord(data?.context);\n\n return {\n branch:\n getString(context, 'branch') ??\n getString(payload, 'branch'),\n cwd:\n getString(context, 'cwd') ??\n getString(payload, 'cwd'),\n gitRoot:\n getString(context, 'gitRoot') ??\n getString(payload, 'gitRoot'),\n repository:\n getString(context, 'repository') ??\n getString(payload, 'repository'),\n };\n}\n\nasync function readCopilotWorkspaceMetadata(\n sessionStateDirectory: string,\n rawSessionId: string,\n filePath?: string,\n): Promise<Partial<CopilotSessionMetadata>> {\n const sessionDirectory = inferSessionDirectory(\n sessionStateDirectory,\n rawSessionId,\n filePath,\n );\n const workspacePath = join(sessionDirectory, 'workspace.yaml');\n\n try {\n const fileContent = await readFile(workspacePath, 'utf8');\n\n return parseCopilotWorkspaceYaml(fileContent);\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return {};\n }\n\n logger.debug({ error, rawSessionId }, 'Copilot workspace metadata read skipped');\n return {};\n }\n}\n\nfunction parseCopilotWorkspaceYaml(\n fileContent: string,\n): Partial<CopilotSessionMetadata> {\n const metadata: {\n branch?: string;\n cwd?: string;\n gitRoot?: string;\n repository?: string;\n } = {};\n\n for (const line of fileContent.split(/\\r?\\n/u)) {\n const match = line.match(/^([a-z_]+):\\s*(.+)$/u);\n\n if (!match) {\n continue;\n }\n\n const key = match[1];\n const value = match[2]?.trim();\n\n if (!value) {\n continue;\n }\n\n switch (key) {\n case 'branch':\n metadata.branch = value;\n break;\n case 'cwd':\n metadata.cwd = value;\n break;\n case 'git_root':\n metadata.gitRoot = value;\n break;\n case 'repository':\n metadata.repository = value;\n break;\n default:\n break;\n }\n }\n\n return metadata;\n}\n\nfunction inferSessionDirectory(\n sessionStateDirectory: string,\n rawSessionId: string,\n filePath?: string,\n): string {\n if (filePath && basename(filePath) === 'events.jsonl') {\n return dirname(filePath);\n }\n\n return join(sessionStateDirectory, rawSessionId);\n}\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, {\n withFileTypes: true,\n });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nasync function listProcesses(\n processListCommand: () => Promise<string>,\n): Promise<CopilotProcessInfo[]> {\n try {\n const commandOutput = await processListCommand();\n\n return commandOutput\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const [pidPart, ...commandParts] = line.split(/\\s+/u);\n const pid = pidPart ? Number.parseInt(pidPart, 10) : Number.NaN;\n\n return {\n command: commandParts.join(' '),\n pid,\n } satisfies CopilotProcessInfo;\n })\n .filter((processInfo) => Number.isInteger(processInfo.pid));\n } catch (error) {\n logger.debug({ error }, 'Copilot process listing skipped');\n return [];\n }\n}\n\nfunction inferSessionIdFromPath(filePath: string): string | undefined {\n const fileName = basename(filePath);\n\n if (fileName === 'events.jsonl') {\n return basename(dirname(filePath));\n }\n\n return fileName.endsWith('.jsonl') ? basename(fileName, '.jsonl') : undefined;\n}\n\nfunction parseJsonRecord(\n value: string | undefined,\n): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n\n try {\n const parsedValue = JSON.parse(value) as unknown;\n\n return getRecord(parsedValue);\n } catch {\n return undefined;\n }\n}\n\nfunction extractLooseString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n\n const nestedValue = getString(getRecord(payload[key]), 'content');\n\n if (nestedValue) {\n return nestedValue;\n }\n }\n\n return undefined;\n}\n\nfunction extractFirstString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n }\n\n return undefined;\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction getBoolean(\n payload: Record<string, unknown> | undefined,\n key: string,\n): boolean | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { EventData } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/codex.ts\n * @description Codex adapter based on passive `codex-tui.log` parsing plus process fallback detection.\n * @functions\n * โ†’ none\n * @exports CodexAdapter, CodexAdapterOptions\n * @see ./base.ts\n * @see ../../tasks/06-adapters-secondary/01_adapters-secondary_gemini-codex.md\n */\n\nconst execFile = promisify(execFileCallback);\n\n/**\n * Codex documents `codex exec --json` for machine-readable automation, but the\n * passive observer path for AISnitch today is still the local TUI log file.\n */\nexport interface CodexAdapterOptions extends AdapterRuntimeOptions {\n readonly logPath?: string;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface CodexProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– The Codex log watcher deliberately parses only high-signal lines:\n * command executions, patch targets, model selection, and shutdown markers.\n * Anything more ambitious would be fake precision over an unstable text log.\n */\nexport class CodexAdapter extends BaseAdapter {\n public override readonly displayName = 'Codex';\n\n public override readonly name = 'codex' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'log-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private lastKnownCwd: string | undefined;\n\n private lastKnownModel: string | undefined;\n\n private readonly logPath: string;\n\n private logOffset = 0;\n\n private logRemainder = '';\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: CodexAdapterOptions) {\n super(options);\n this.logPath =\n options.logPath ??\n join(this.getUserHomeDirectory(), '.codex', 'log', 'codex-tui.log');\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'codex']).then((result) => result.stdout));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedLogOffset();\n\n this.watcher = this.watcherFactory(this.logPath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processLogUpdate(filePath, true);\n });\n this.watcher.on('change', (filePath) => {\n void this.processLogUpdate(filePath, false);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Codex log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.lastKnownCwd = undefined;\n this.lastKnownModel = undefined;\n this.logOffset = 0;\n this.logRemainder = '';\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload === null) {\n logger.debug({ payload }, 'Codex ignores non-normalized hook payloads');\n return;\n }\n\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n }\n\n private async processLogUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Codex log read skipped');\n return;\n }\n\n const previousOffset = readFromStart ? 0 : this.logOffset;\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.logRemainder) +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.logOffset = fileContent.byteLength;\n this.logRemainder = remainder;\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processLogLine(trimmedLine);\n }\n }\n\n private async processLogLine(line: string): Promise<void> {\n const modelMatch = line.match(/model:\\s*([^,]+),\\s*.*effort:\\s*([^\\s]+)$/u);\n\n if (modelMatch) {\n const parsedModel = modelMatch[1]?.trim();\n\n if (parsedModel) {\n this.lastKnownModel = parsedModel;\n\n const sessionId = this.resolveLogSessionId(this.lastKnownCwd);\n const context = this.createLogContext(sessionId, this.lastKnownCwd, line);\n\n await this.ensureObservedSession(\n sessionId,\n {\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n context,\n );\n }\n\n return;\n }\n\n const parsedCommand = parseCodexCommandLine(line);\n\n if (parsedCommand !== null) {\n this.lastKnownCwd = parsedCommand.workdir ?? this.lastKnownCwd;\n\n const sessionId = this.resolveLogSessionId(parsedCommand.workdir);\n const context = this.createLogContext(sessionId, parsedCommand.workdir, line);\n\n await this.ensureObservedSession(\n sessionId,\n {\n cwd: parsedCommand.workdir,\n model: this.lastKnownModel,\n raw: {\n command: parsedCommand,\n logLine: line,\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.tool_call',\n {\n cwd: parsedCommand.workdir,\n model: this.lastKnownModel,\n raw: {\n command: parsedCommand,\n logLine: line,\n },\n toolInput: {\n command: parsedCommand.command,\n },\n toolName: 'shell',\n },\n context,\n );\n return;\n }\n\n const patchFileMatch = line.match(/^\\*\\*\\*\\s+(?:Update|Add|Delete)\\s+File:\\s+(.+)$/u);\n\n if (patchFileMatch?.[1]) {\n const activeFile = patchFileMatch[1].trim();\n const sessionId = this.resolveLogSessionId(this.lastKnownCwd);\n const context = this.createLogContext(sessionId, this.lastKnownCwd, line);\n\n await this.ensureObservedSession(\n sessionId,\n {\n activeFile,\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.coding',\n {\n activeFile,\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n context,\n );\n return;\n }\n\n if (/Shutting down Codex/iu.test(line) && this.currentSessionId !== null) {\n await this.emitStateChange(\n 'session.end',\n {\n cwd: this.lastKnownCwd,\n model: this.lastKnownModel,\n raw: {\n logLine: line,\n },\n },\n this.createLogContext(this.currentSessionId, this.lastKnownCwd, line),\n );\n }\n }\n\n private createLogContext(\n sessionId: string,\n cwd: string | undefined,\n line: string,\n ): AdapterPublishContext {\n return {\n cwd,\n hookPayload: {\n logLine: line,\n },\n sessionId,\n source: 'aisnitch://adapters/codex/log-watch',\n };\n }\n\n private resolveLogSessionId(cwd: string | undefined): string {\n return resolveSessionId({\n cwd,\n projectPath: cwd,\n sessionId: `${this.name}:session`,\n tool: this.name,\n });\n }\n\n private async ensureObservedSession(\n sessionId: string,\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n if (this.currentSessionId === sessionId) {\n return;\n }\n\n await this.emitStateChange('session.start', data, context);\n await this.emitStateChange('agent.idle', data, context);\n }\n\n private async seedLogOffset(): Promise<void> {\n try {\n const fileStats = await stat(this.logPath);\n\n this.logOffset = fileStats.size;\n } catch {\n this.logOffset = 0;\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollCodexProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollCodexProcesses();\n }\n\n private async pollCodexProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `codex-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/codex/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/codex/process-detect',\n },\n );\n }\n }\n}\n\ninterface ParsedCodexCommand {\n readonly command: string;\n readonly workdir?: string;\n}\n\nfunction parseCodexCommandLine(line: string): ParsedCodexCommand | null {\n const jsonStart = line.indexOf('{');\n const jsonEnd = line.lastIndexOf('}');\n\n if (jsonStart < 0 || jsonEnd <= jsonStart) {\n return null;\n }\n\n try {\n const parsedJson = JSON.parse(line.slice(jsonStart, jsonEnd + 1)) as unknown;\n\n if (!isRecord(parsedJson)) {\n return null;\n }\n\n const command = getString(parsedJson, 'command');\n\n if (!command) {\n return null;\n }\n\n return {\n command,\n workdir: getString(parsedJson, 'workdir'),\n };\n } catch {\n return null;\n }\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<CodexProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map(parseProcessLine)\n .filter((processInfo): processInfo is CodexProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode = isErrnoException(error) ? String(error.code) : '';\n\n if (isErrnoException(error) && (errorCode === 'ENOENT' || errorCode === '1')) {\n return [];\n }\n\n logger.debug({ error }, 'Codex process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): CodexProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException & { code?: string | number } {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/cursor.ts\n * @description Cursor CLI adapter covering process detection, JSON output interception,\n * and log file watching for the Cursor agent terminal.\n * @functions\n * โ†’ none\n * @exports CursorAdapter, CursorAdapterOptions\n * @see ./base.ts\n * @see ../../docs/priority-adapters.md\n *\n * ๐Ÿ“– Cursor CLI is the command-line interface to Cursor's AI agent. It supports\n * structured JSON output (`--output-format json`), process detection for running\n * instances, and writes session logs to Library/Application Support/Cursor/.\n * Interception strategy: process-detect primary, JSON line watching as fallback.\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst CURSOR_CODING_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'NotebookEdit',\n 'CreateFile',\n 'DeleteFile',\n 'MoveFile',\n]);\n\nexport interface CursorAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly logDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface CursorProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– Cursor CLI lacks a formal hook system but emits structured logs via its\n * background process and supports JSON output mode. The adapter uses process\n * polling as the primary detection mechanism and log watching as secondary.\n */\nexport class CursorAdapter extends BaseAdapter {\n public override readonly displayName = 'Cursor CLI';\n\n public override readonly name = 'cursor' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'jsonl-watch',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly logDirectory: string;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: CursorAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () => {\n const results = await Promise.all([\n execFile('pgrep', ['-lf', 'cursor-agent']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'cursor']).catch(() => ({ stdout: '' })),\n ]);\n return results.map((r) => r.stdout).join('\\n');\n });\n this.logDirectory =\n options.logDirectory ??\n join(this.getUserHomeDirectory(), 'Library', 'Application Support', 'Cursor');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n // Watch for Cursor log files in various locations\n const logPatterns = [\n join(this.logDirectory, 'logs', '**', '*.jsonl'),\n join(this.logDirectory, 'agent', '**', '*.jsonl'),\n ];\n\n this.watcher = this.watcherFactory(logPatterns[0]!, {\n awaitWriteFinish: { stabilityThreshold: 200 },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => void this.processTranscriptUpdate(filePath, true));\n this.watcher.on('change', (filePath) => void this.processTranscriptUpdate(filePath, false));\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Cursor log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Cursor hook payload must be an object');\n return;\n }\n\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath: getString(payload, 'projectPath'),\n sessionId: getString(payload, 'sessionId') ?? getString(payload, 'session_id'),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/cursor',\n };\n const eventType = getString(payload, 'event') ?? getString(payload, 'type');\n const toolName = getString(payload, 'tool') ?? getString(payload, 'toolName');\n const toolInput = extractToolInput(payload);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: getString(payload, 'model'),\n projectPath: getString(payload, 'projectPath'),\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session_start':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session_end':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task_start':\n case 'TaskStart':\n case 'UserPromptSubmit': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task_complete':\n case 'TaskComplete':\n case 'TaskCompleted': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'tool_call':\n case 'PreToolUse': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'tool_result':\n case 'PostToolUse': {\n const emittedType = isCursorCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'streaming':\n case 'Streaming':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(payload, 'error') ?? getString(payload, 'message') ?? 'Cursor error',\n errorType: inferCursorErrorType(payload),\n }, context);\n return;\n }\n case 'asking_user':\n case 'PermissionRequest':\n case 'Notification': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n logger.debug({ eventType }, 'Cursor hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Cursor transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ?? (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') + newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Cursor transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n const sessionId = resolveSessionId({\n sessionId:\n getString(parsedLine, 'sessionId') ??\n getString(parsedLine, 'session_id') ??\n basename(transcriptPath, '.jsonl'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n env: process.env,\n hookPayload: parsedLine,\n sessionId,\n source: 'aisnitch://adapters/cursor/log',\n transcriptPath,\n };\n const eventType = getString(parsedLine, 'type') ?? getString(parsedLine, 'event');\n const data = getRecord(parsedLine.data) ?? parsedLine;\n const toolName = getString(data, 'toolName') ?? getString(data, 'tool');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n model: getString(data, 'model'),\n raw: parsedLine,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n // Map Cursor log types to AISnitch event types\n switch (eventType) {\n case 'session.start':\n case 'session_start': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'session_end': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'task_start': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'task_complete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'agent.thinking':\n case 'thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'agent.streaming':\n case 'streaming':\n case 'assistant.message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'agent.tool_call':\n case 'tool_use': {\n const emittedType = isCursorCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'agent.error':\n case 'error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(data, 'message'),\n errorType: inferCursorErrorType(data),\n }, context);\n return;\n }\n case 'agent.asking_user':\n case 'permission_required': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n return;\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n try {\n const files = await collectFilesRecursively(\n join(this.logDirectory, 'logs'),\n '.jsonl',\n );\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n } catch {\n // Logs directory may not exist yet on first run.\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollCursorProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollCursorProcesses();\n }\n\n private async pollCursorProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `cursor-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n { raw: { process: processInfo, source: 'process-detect' } },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/cursor/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n { raw: { reason: 'process-exit', source: 'process-detect' } },\n {\n sessionId,\n source: 'aisnitch://adapters/cursor/process-detect',\n },\n );\n }\n }\n}\n\n// โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput) ?? getRecord(payload.arguments);\n const filePath =\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'path');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return { command, filePath };\n}\n\nfunction isCursorCodingTool(toolName?: string): boolean {\n return toolName !== undefined && CURSOR_CODING_TOOLS.has(toolName);\n}\n\nfunction inferCursorErrorType(\n payload: Record<string, unknown> | undefined,\n): ErrorType {\n const message =\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n '';\n\n if (/rate.?limit|quota|credit/i.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token.?limit|too.?long/i.test(message)) {\n return 'context_overflow';\n }\n\n if (/tool|permission|denied/i.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<CursorProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && line.includes('cursor'))\n .map(parseProcessLine)\n .filter((processInfo): processInfo is CursorProcessInfo => processInfo !== null);\n } catch (error) {\n logger.debug({ error }, 'Cursor process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): CursorProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/devin.ts\n * @description Devin CLI adapter covering the cloud-connected AI software engineer agent.\n * @functions\n * โ†’ none\n * @exports DevinAdapter, DevinAdapterOptions\n * @see ./base.ts\n * @see ../../docs/priority-adapters.md\n *\n * ๐Ÿ“– Devin is Cognition Labs' AI software engineer CLI. It operates as a cloud-connected\n * agent with local session management. The adapter uses process detection to track when\n * the Devin CLI is running, and can receive webhook-style events if configured via the\n * Devin dashboard. Session data is stored locally in ~/.devin/.\n * Interception: process-detect primary, webhook hooks when available.\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst DEVIN_CODING_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'Create',\n 'Delete',\n 'Move',\n 'Read',\n 'Grep',\n 'Bash',\n 'WebSearch',\n]);\n\nexport interface DevinAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly sessionDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface DevinProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface DevinSessionMetadata {\n readonly cwd?: string;\n readonly model?: string;\n readonly sessionId: string;\n}\n\n/**\n * ๐Ÿ“– Devin CLI runs as a cloud-connected agent. It communicates with Cognition's\n * backend but also maintains local session state in ~/.devin/sessions/. The adapter\n * tracks process lifecycle and watches for local session data files.\n */\nexport class DevinAdapter extends BaseAdapter {\n public override readonly displayName = 'Devin CLI';\n\n public override readonly name = 'devin' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'hooks',\n 'jsonl-watch',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionDirectory: string;\n\n private readonly sessionMetadata = new Map<string, DevinSessionMetadata>();\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: DevinAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () => {\n // Devin CLI binary name varies โ€” try common patterns\n const results = await Promise.all([\n execFile('pgrep', ['-lf', 'devin']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'cognition']).catch(() => ({ stdout: '' })),\n ]);\n return results.map((r) => r.stdout).join('\\n');\n });\n this.sessionDirectory =\n options.sessionDirectory ?? join(this.getUserHomeDirectory(), '.devin');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n // Watch for Devin session logs\n this.watcher = this.watcherFactory(\n join(this.sessionDirectory, '**', '*.jsonl'),\n {\n awaitWriteFinish: { stabilityThreshold: 200 },\n ignoreInitial: true,\n },\n );\n\n this.watcher.on('add', (filePath) => void this.processTranscriptUpdate(filePath, true));\n this.watcher.on('change', (filePath) => void this.processTranscriptUpdate(filePath, false));\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Devin log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.sessionMetadata.clear();\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Devin hook payload must be an object');\n return;\n }\n\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath: getString(payload, 'projectPath'),\n sessionId:\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(payload, 'id') ??\n getString(getRecord(payload.data), 'sessionId'),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/devin',\n };\n const eventType = getString(payload, 'event') ?? getString(payload, 'type') ?? getString(payload, 'action');\n const data = getRecord(payload.data) ?? payload;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName') ?? getString(data, 'name');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: getString(data, 'model') ?? getString(payload, 'model'),\n projectPath: getString(data, 'projectPath') ?? getString(payload, 'projectPath'),\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.start':\n case 'sessionStart':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'sessionEnd':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'taskStart':\n case 'task_create':\n case 'TaskCreate': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'taskComplete':\n case 'TaskComplete':\n case 'task_done': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'tool.call':\n case 'toolCall':\n case 'ToolCall': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'tool.result':\n case 'toolResult':\n case 'ToolResult': {\n const emittedType = isDevinCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking':\n case 'reasoning': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'output':\n case 'streaming':\n case 'Output': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'error':\n case 'Error':\n case 'ErrorOccurred': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(payload, 'error') ?? 'Devin error',\n errorType: inferDevinErrorType(data),\n }, context);\n return;\n }\n case 'asking_user':\n case 'PermissionRequest':\n case 'user_input_required':\n case 'InputRequired': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n logger.debug({ eventType }, 'Devin hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Devin transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ?? (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') + newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Devin transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n const eventType = getString(parsedLine, 'type') ?? getString(parsedLine, 'event');\n const sessionId = resolveSessionId({\n sessionId:\n getString(parsedLine, 'sessionId') ??\n getString(parsedLine, 'session_id') ??\n getString(parsedLine, 'id') ??\n basename(transcriptPath, '.jsonl'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n env: process.env,\n hookPayload: parsedLine,\n sessionId,\n source: 'aisnitch://adapters/devin/log',\n transcriptPath,\n };\n const data = getRecord(parsedLine.data) ?? parsedLine;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: getString(data, 'cwd'),\n model: getString(data, 'model'),\n raw: parsedLine,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.start':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'TaskStart': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'TaskComplete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'output':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'tool_use':\n case 'ToolUse': {\n const emittedType = isDevinCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(data, 'message'),\n errorType: inferDevinErrorType(data),\n }, context);\n return;\n }\n case 'permission_request':\n case 'asking_user': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n return;\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n try {\n const files = await collectFilesRecursively(this.sessionDirectory, '.jsonl');\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n } catch {\n // Session directory may not exist yet on first run.\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollDevinProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollDevinProcesses();\n }\n\n private async pollDevinProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `devin-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n { raw: { process: processInfo, source: 'process-detect' } },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/devin/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n { raw: { reason: 'process-exit', source: 'process-detect' } },\n {\n sessionId,\n source: 'aisnitch://adapters/devin/process-detect',\n },\n );\n }\n }\n}\n\n// โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const toolInput =\n getRecord(payload.tool_input) ??\n getRecord(payload.toolInput) ??\n getRecord(payload.arguments) ??\n getRecord(payload.params);\n const filePath =\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'path') ??\n getString(toolInput, 'target');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd') ??\n getString(toolInput, 'script');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return { command, filePath };\n}\n\nfunction isDevinCodingTool(toolName?: string): boolean {\n return toolName !== undefined && DEVIN_CODING_TOOLS.has(toolName);\n}\n\nfunction inferDevinErrorType(\n payload: Record<string, unknown> | undefined,\n): ErrorType {\n const message =\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n '';\n\n if (/rate.?limit|quota|credit|api.?key/i.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token.?limit|too.?long|exceeded/i.test(message)) {\n return 'context_overflow';\n }\n\n if (/tool|permission|denied|access/i.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<DevinProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .filter(\n (line) =>\n line.includes('devin') || line.includes('cognition') || line.includes('swe'),\n )\n .map(parseProcessLine)\n .filter((processInfo): processInfo is DevinProcessInfo => processInfo !== null);\n } catch (error) {\n logger.debug({ error }, 'Devin process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): DevinProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/gemini-cli.ts\n * @description Gemini CLI adapter covering command hooks, best-effort local `logs.json` watching, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports GeminiCLIAdapter, GeminiCLIAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/01_adapters-secondary_gemini-codex.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst GEMINI_CODING_TOOLS = new Set([\n 'edit',\n 'replace',\n 'write',\n 'write_file',\n]);\n\n/**\n * Gemini CLI now documents synchronous lifecycle hooks in settings.json. The\n * passive fallback here reads the per-session `logs.json` files under\n * `~/.gemini/tmp/`, which appear to contain prompt history even when hooks\n * were never installed.\n */\nexport interface GeminiCLIAdapterOptions extends AdapterRuntimeOptions {\n readonly logsDirectory?: string;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface GeminiProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– Gemini gets the same three-layer treatment as Claude/OpenCode, but the\n * file fallback is intentionally narrower: it only emits what local logs can\n * prove, instead of pretending those logs expose the full agent loop.\n */\nexport class GeminiCLIAdapter extends BaseAdapter {\n public override readonly displayName = 'Gemini CLI';\n\n public override readonly name = 'gemini-cli' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'log-watch',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly logsDirectory: string;\n\n private readonly observedLogMessageIds = new Map<string, Set<string>>();\n\n private readonly projectRootCache = new Map<string, string | undefined>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: GeminiCLIAdapterOptions) {\n super(options);\n this.logsDirectory =\n options.logsDirectory ??\n join(this.getUserHomeDirectory(), '.gemini', 'tmp');\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'gemini']).then((result) => result.stdout));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedObservedLogState();\n\n const logsGlob = join(this.logsDirectory, '**', 'logs.json');\n this.watcher = this.watcherFactory(logsGlob, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => {\n void this.processLogsFile(filePath);\n });\n this.watcher.on('change', (filePath) => {\n void this.processLogsFile(filePath);\n });\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Gemini logs watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.observedLogMessageIds.clear();\n this.projectRootCache.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Gemini hook payload must be an object');\n return;\n }\n\n const hookEventName =\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hookEventName');\n\n if (!hookEventName) {\n logger.warn({ payload }, 'Gemini hook payload is missing its event name');\n return;\n }\n\n const cwd = getString(payload, 'cwd');\n const transcriptPath =\n getString(payload, 'transcript_path') ??\n getString(payload, 'transcriptPath');\n const sessionId = resolveSessionId({\n activeFile: extractGeminiActiveFile(payload),\n cwd,\n projectPath: cwd,\n sessionId:\n getString(payload, 'session_id') ??\n getString(payload, 'sessionId'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n cwd,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/gemini-cli',\n transcriptPath,\n };\n const sharedData = {\n activeFile: extractGeminiActiveFile(payload),\n cwd,\n errorMessage: extractGeminiErrorMessage(payload),\n errorType: extractGeminiErrorType(payload),\n model: extractGeminiModel(payload),\n projectPath: cwd,\n raw: payload,\n tokensUsed: extractGeminiTokens(payload),\n toolInput: extractGeminiToolInput(payload),\n toolName: extractGeminiToolName(payload),\n } satisfies Omit<EventData, 'state'>;\n\n switch (hookEventName) {\n case 'SessionStart': {\n this.fallbackProcessSessionId = null;\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'BeforeAgent': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'AfterAgent': {\n if (sharedData.errorMessage) {\n await this.emitStateChange('agent.error', sharedData, context);\n return;\n }\n\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'BeforeTool': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'AfterTool': {\n if (sharedData.errorMessage) {\n await this.emitStateChange('agent.error', sharedData, context);\n return;\n }\n\n const emittedType = isGeminiCodingTool(sharedData.toolName)\n ? 'agent.coding'\n : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'AfterModel': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'Notification': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n case 'PreCompress': {\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n default: {\n logger.debug({ hookEventName }, 'Gemini hook event ignored by adapter');\n }\n }\n }\n\n private async processLogsFile(filePath: string): Promise<void> {\n let fileContent: string;\n\n try {\n fileContent = await readFile(filePath, 'utf8');\n } catch (error) {\n logger.debug({ error, filePath }, 'Gemini logs read skipped');\n return;\n }\n\n let parsedContent: unknown;\n\n try {\n parsedContent = JSON.parse(fileContent) as unknown;\n } catch (error) {\n logger.warn({ error, filePath }, 'Gemini logs file is not valid JSON');\n return;\n }\n\n if (!Array.isArray(parsedContent)) {\n logger.warn({ filePath }, 'Gemini logs file does not contain an array');\n return;\n }\n\n const knownMessageIds = this.observedLogMessageIds.get(filePath) ?? new Set<string>();\n this.observedLogMessageIds.set(filePath, knownMessageIds);\n\n for (const entry of parsedContent) {\n if (!isRecord(entry)) {\n continue;\n }\n\n const messageId =\n getString(entry, 'messageId') ??\n getString(entry, 'message_id');\n\n if (!messageId || knownMessageIds.has(messageId)) {\n continue;\n }\n\n knownMessageIds.add(messageId);\n await this.processLogEntry(entry, filePath);\n }\n }\n\n private async processLogEntry(\n entry: Record<string, unknown>,\n filePath: string,\n ): Promise<void> {\n const messageType = getString(entry, 'type');\n const sessionId = resolveSessionId({\n cwd: await this.readProjectRoot(filePath),\n projectPath: await this.readProjectRoot(filePath),\n sessionId: getString(entry, 'sessionId') ?? `${this.name}:session`,\n tool: this.name,\n });\n const projectPath = await this.readProjectRoot(filePath);\n const context: AdapterPublishContext = {\n cwd: projectPath,\n hookPayload: entry,\n sessionId,\n source: 'aisnitch://adapters/gemini-cli/log-watch',\n };\n const sharedData = {\n cwd: projectPath,\n projectPath,\n raw: entry,\n } satisfies Omit<EventData, 'state'>;\n\n await this.ensureObservedSession(sessionId, sharedData, context);\n\n switch (messageType) {\n case 'user': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'model':\n case 'assistant': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'thinking': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n default: {\n logger.debug({ filePath, messageType }, 'Gemini log entry ignored by adapter');\n }\n }\n }\n\n private async ensureObservedSession(\n sessionId: string,\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n if (this.currentSessionId === sessionId) {\n return;\n }\n\n await this.emitStateChange('session.start', data, context);\n await this.emitStateChange('agent.idle', data, context);\n }\n\n private async readProjectRoot(filePath: string): Promise<string | undefined> {\n if (this.projectRootCache.has(filePath)) {\n return this.projectRootCache.get(filePath);\n }\n\n const rootPath = join(dirname(filePath), '.project_root');\n\n try {\n const projectRoot = (await readFile(rootPath, 'utf8')).trim();\n const normalizedRoot = projectRoot.length > 0 ? projectRoot : undefined;\n\n this.projectRootCache.set(filePath, normalizedRoot);\n return normalizedRoot;\n } catch {\n this.projectRootCache.set(filePath, undefined);\n return undefined;\n }\n }\n\n private async seedObservedLogState(): Promise<void> {\n const files = await collectFilesRecursively(this.logsDirectory, 'logs.json');\n\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n\n if (!fileStats.isFile()) {\n return;\n }\n\n const fileContent = await readFile(filePath, 'utf8');\n const parsedContent = JSON.parse(fileContent) as unknown;\n const messageIds = new Set<string>();\n\n if (Array.isArray(parsedContent)) {\n for (const entry of parsedContent) {\n if (!isRecord(entry)) {\n continue;\n }\n\n const messageId =\n getString(entry, 'messageId') ??\n getString(entry, 'message_id');\n\n if (messageId) {\n messageIds.add(messageId);\n }\n }\n }\n\n this.observedLogMessageIds.set(filePath, messageIds);\n } catch {\n // Ignore files that disappear or fail while seeding.\n }\n }),\n );\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollGeminiProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollGeminiProcesses();\n }\n\n private async pollGeminiProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `gemini-cli-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/gemini-cli/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/gemini-cli/process-detect',\n },\n );\n }\n }\n}\n\nasync function collectFilesRecursively(\n directoryPath: string,\n fileName: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, {\n withFileTypes: true,\n });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, fileName);\n }\n\n return entry.name === fileName ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractGeminiToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'tool_name') ??\n getString(payload, 'toolName')\n );\n}\n\nfunction extractGeminiToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput);\n\n if (!toolInput) {\n return undefined;\n }\n\n const filePath =\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'path');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction extractGeminiActiveFile(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolInput = extractGeminiToolInput(payload);\n\n if (toolInput?.filePath) {\n return toolInput.filePath;\n }\n\n return (\n getString(payload, 'active_file') ??\n getString(payload, 'activeFile') ??\n getString(payload, 'file_path')\n );\n}\n\nfunction extractGeminiErrorMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolResponse = getRecord(payload.tool_response) ?? getRecord(payload.toolResponse);\n const llmResponse = getRecord(payload.llm_response) ?? getRecord(payload.llmResponse);\n\n return (\n getString(getRecord(toolResponse?.error), 'message') ??\n getString(payload, 'reason') ??\n getString(payload, 'message') ??\n getString(llmResponse, 'error')\n );\n}\n\nfunction extractGeminiErrorType(\n payload: Record<string, unknown>,\n): ErrorType | undefined {\n const rawType =\n getString(payload, 'error_type') ??\n getString(payload, 'errorType') ??\n getString(payload, 'stopReason');\n\n switch (rawType) {\n case 'rate_limit':\n return 'rate_limit';\n case 'max_output_tokens':\n case 'context_overflow':\n return 'context_overflow';\n case 'api_error':\n case 'provider_error':\n case 'invalid_request':\n return 'api_error';\n case 'tool_failure':\n return 'tool_failure';\n default:\n return undefined;\n }\n}\n\nfunction extractGeminiModel(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(getRecord(payload.llm_request), 'model') ??\n getString(payload, 'model')\n );\n}\n\nfunction extractGeminiTokens(\n payload: Record<string, unknown>,\n): number | undefined {\n const llmResponse = getRecord(payload.llm_response) ?? getRecord(payload.llmResponse);\n const usageMetadata = getRecord(llmResponse?.usageMetadata);\n const totalTokens =\n getNumber(usageMetadata, 'totalTokenCount') ??\n getNumber(usageMetadata, 'total_tokens');\n\n return totalTokens;\n}\n\nfunction isGeminiCodingTool(toolName?: string): boolean {\n return toolName !== undefined && GEMINI_CODING_TOOLS.has(toolName);\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<GeminiProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map(parseProcessLine)\n .filter((processInfo): processInfo is GeminiProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode = isErrnoException(error) ? String(error.code) : '';\n\n if (isErrnoException(error) && (errorCode === 'ENOENT' || errorCode === '1')) {\n return [];\n }\n\n logger.debug({ error }, 'Gemini process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): GeminiProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException & { code?: string | number } {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { ErrorType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/goose.ts\n * @description Goose adapter combining goosed session discovery, SSE event streaming, SQLite session watching, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports GooseAdapter, GooseAdapterOptions\n * @see ./base.ts\n * @see ../../tasks/06-adapters-secondary/02_adapters-secondary_goose-copilot_DONE.md\n */\n\nconst execFile = promisify(execFileCallback);\nconst DEFAULT_GOOSED_BASE_URL = 'http://127.0.0.1:8080';\nconst DEFAULT_SQLITE_QUERY = [\n 'SELECT',\n ' id,',\n ' name,',\n ' working_dir,',\n ' updated_at,',\n ' message_count,',\n ' provider_name,',\n ' accumulated_total_tokens,',\n ' total_tokens,',\n ' model_config',\n 'FROM sessions',\n 'ORDER BY updated_at DESC',\n 'LIMIT 24;',\n].join('\\n');\nconst MAX_STREAMED_SESSIONS = 6;\nconst GOOSE_CODING_TOOL_HINT = /apply|create|delete|edit|move|patch|rename|replace|write/iu;\nconst GOOSE_RATE_LIMIT_HINT = /credit|quota|rate limit|exhausted/iu;\n\nexport interface GooseAdapterOptions extends AdapterRuntimeOptions {\n readonly apiBaseUrl?: string;\n readonly apiKey?: string;\n readonly databasePath?: string;\n readonly fetchImplementation?: typeof fetch;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly sqliteQueryCommand?: (\n databasePath: string,\n query: string,\n ) => Promise<string>;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface GooseProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface GooseSessionSnapshot {\n readonly gooseSessionId: string;\n readonly sessionId: string;\n readonly messageCount?: number;\n readonly model?: string;\n readonly name?: string;\n readonly providerName?: string;\n readonly totalTokens?: number;\n readonly updatedAt?: string;\n readonly workingDir?: string;\n}\n\ninterface GooseStreamHandle {\n readonly abortController: AbortController;\n readonly promise: Promise<void>;\n}\n\ninterface GooseSessionsResponse {\n readonly sessions?: unknown;\n}\n\n/**\n * ๐Ÿ“– Goose is the first adapter that mixes three genuinely different sources:\n * HTTP session discovery, SSE streaming, and a coarse SQLite fallback. Each\n * layer is best-effort and intentionally conservative about what it claims.\n */\nexport class GooseAdapter extends BaseAdapter {\n public override readonly displayName = 'Goose';\n\n public override readonly name = 'goose' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'api-client',\n 'sqlite-watch',\n 'process-detect',\n ];\n\n private apiPoller: NodeJS.Timeout | null = null;\n\n private readonly apiBaseUrl: string;\n\n private readonly apiKey: string | undefined;\n\n private readonly databasePath: string;\n\n private databaseWatcher: FSWatcher | null = null;\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly fetchImplementation: typeof fetch;\n\n private apiDiscoverySeeded = false;\n\n private readonly observedSessions = new Set<string>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionEventFingerprints = new Map<string, Set<string>>();\n\n private readonly sessionSnapshots = new Map<string, GooseSessionSnapshot>();\n\n private readonly sessionStreams = new Map<string, GooseStreamHandle>();\n\n private readonly sqliteQueryCommand: (\n databasePath: string,\n query: string,\n ) => Promise<string>;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: GooseAdapterOptions) {\n super(options);\n this.apiBaseUrl =\n options.apiBaseUrl ??\n options.env?.AISNITCH_GOOSE_API_BASE_URL ??\n DEFAULT_GOOSED_BASE_URL;\n this.apiKey =\n options.apiKey ??\n options.env?.AISNITCH_GOOSE_API_KEY ??\n options.env?.GOOSE_API_KEY;\n this.databasePath =\n options.databasePath ??\n join(this.getUserHomeDirectory(), '.config', 'goose', 'sessions.db');\n this.fetchImplementation = options.fetchImplementation ?? fetch;\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-lf', 'goose|goosed']).then(\n (result) => result.stdout,\n ));\n this.sqliteQueryCommand =\n options.sqliteQueryCommand ??\n (async (databasePath, query) =>\n await execFile('sqlite3', ['-json', databasePath, query]).then(\n (result) => result.stdout,\n ));\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedSqliteSessions();\n\n this.databaseWatcher = this.watcherFactory(this.databasePath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n\n this.databaseWatcher.on('add', () => {\n void this.pollSqliteSessions(true);\n });\n this.databaseWatcher.on('change', () => {\n void this.pollSqliteSessions(true);\n });\n this.databaseWatcher.on('error', (error) => {\n logger.warn({ error }, 'Goose SQLite watcher error');\n });\n\n this.startApiPolling();\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.databaseWatcher !== null) {\n await this.databaseWatcher.close();\n this.databaseWatcher = null;\n }\n\n if (this.apiPoller !== null) {\n clearInterval(this.apiPoller);\n this.apiPoller = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n for (const streamHandle of this.sessionStreams.values()) {\n streamHandle.abortController.abort();\n void streamHandle.promise.catch(() => undefined);\n }\n\n this.apiDiscoverySeeded = false;\n this.fallbackProcessSessionId = null;\n this.observedSessions.clear();\n this.sessionEventFingerprints.clear();\n this.sessionSnapshots.clear();\n this.sessionStreams.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload === null) {\n logger.debug({ payload }, 'Goose ignores non-normalized hook payloads');\n return;\n }\n\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n }\n\n private startApiPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.apiPoller = setInterval(() => {\n void this.pollGooseApi(true);\n }, this.pollIntervalMs);\n this.apiPoller.unref();\n\n void this.pollGooseApi(false);\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollGooseProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollGooseProcesses();\n }\n\n private async seedSqliteSessions(): Promise<void> {\n try {\n await stat(this.databasePath);\n } catch {\n return;\n }\n\n const sessions = await this.readSqliteSessions();\n\n this.syncSessionSnapshots(sessions, false, 'sqlite-seed');\n }\n\n private async pollSqliteSessions(emitChanges: boolean): Promise<void> {\n const sessions = await this.readSqliteSessions();\n\n this.syncSessionSnapshots(sessions, emitChanges, 'sqlite');\n }\n\n private async readSqliteSessions(): Promise<GooseSessionSnapshot[]> {\n let rawOutput: string;\n\n try {\n rawOutput = await this.sqliteQueryCommand(\n this.databasePath,\n DEFAULT_SQLITE_QUERY,\n );\n } catch (error) {\n logger.debug({ error }, 'Goose SQLite session query skipped');\n return [];\n }\n\n let parsedOutput: unknown;\n\n try {\n parsedOutput = JSON.parse(rawOutput) as unknown;\n } catch (error) {\n logger.warn({ error }, 'Goose SQLite JSON output is invalid');\n return [];\n }\n\n if (!Array.isArray(parsedOutput)) {\n return [];\n }\n\n return parsedOutput\n .map((entry) => normalizeGooseSession(entry))\n .filter((entry): entry is GooseSessionSnapshot => entry !== null);\n }\n\n private async pollGooseApi(emitChanges: boolean): Promise<void> {\n let statusResponse: Response;\n\n try {\n statusResponse = await this.fetchImplementation(\n new URL('/status', this.apiBaseUrl),\n );\n } catch (error) {\n logger.debug({ error }, 'Goosed status endpoint is unavailable');\n return;\n }\n\n if (!statusResponse.ok) {\n return;\n }\n\n let sessionsResponse: Response;\n\n try {\n sessionsResponse = await this.fetchImplementation(\n new URL('/sessions', this.apiBaseUrl),\n {\n headers: this.createApiHeaders(),\n },\n );\n } catch (error) {\n logger.debug({ error }, 'Goosed sessions endpoint request failed');\n return;\n }\n\n if (!sessionsResponse.ok) {\n logger.debug(\n { status: sessionsResponse.status },\n 'Goosed sessions endpoint rejected the request',\n );\n return;\n }\n\n let parsedPayload: unknown;\n\n try {\n parsedPayload = await sessionsResponse.json();\n } catch (error) {\n logger.warn({ error }, 'Goosed sessions payload is not valid JSON');\n return;\n }\n\n const responsePayload = parsedPayload as GooseSessionsResponse;\n const rawSessions = Array.isArray(responsePayload.sessions)\n ? responsePayload.sessions\n : [];\n const sessions = rawSessions\n .map((entry) => normalizeGooseSession(entry))\n .filter((entry): entry is GooseSessionSnapshot => entry !== null);\n\n this.syncSessionSnapshots(\n sessions,\n emitChanges && this.apiDiscoverySeeded,\n 'api',\n );\n this.apiDiscoverySeeded = true;\n }\n\n private syncSessionSnapshots(\n nextSnapshots: readonly GooseSessionSnapshot[],\n emitChanges: boolean,\n source: string,\n ): void {\n for (const snapshot of nextSnapshots) {\n const previousSnapshot = this.sessionSnapshots.get(snapshot.sessionId);\n\n this.sessionSnapshots.set(snapshot.sessionId, snapshot);\n this.ensureTrackedSessionStream(snapshot);\n\n if (!emitChanges) {\n continue;\n }\n\n if (previousSnapshot === undefined) {\n void this.ensureObservedSession(snapshot, source);\n continue;\n }\n\n if (!didGooseSessionAdvance(previousSnapshot, snapshot)) {\n continue;\n }\n\n void this.ensureObservedSession(snapshot, source).then(async () => {\n await this.emitStateChange(\n 'agent.streaming',\n buildGooseSessionData(snapshot, {\n raw: {\n snapshot,\n source,\n },\n }),\n this.createSessionContext(snapshot, `aisnitch://adapters/goose/${source}`),\n );\n });\n }\n\n this.trimTrackedSessionStreams(nextSnapshots);\n }\n\n private ensureTrackedSessionStream(snapshot: GooseSessionSnapshot): void {\n if (this.sessionStreams.has(snapshot.sessionId)) {\n return;\n }\n\n const abortController = new AbortController();\n const streamPromise = this.consumeSessionEvents(snapshot, abortController).finally(\n () => {\n const activeStream = this.sessionStreams.get(snapshot.sessionId);\n\n if (activeStream?.abortController === abortController) {\n this.sessionStreams.delete(snapshot.sessionId);\n }\n },\n );\n\n this.sessionStreams.set(snapshot.sessionId, {\n abortController,\n promise: streamPromise,\n });\n }\n\n private trimTrackedSessionStreams(\n nextSnapshots: readonly GooseSessionSnapshot[],\n ): void {\n const keepSessionIds = new Set(\n [...nextSnapshots]\n .sort(compareGooseSessionsByRecency)\n .slice(0, MAX_STREAMED_SESSIONS)\n .map((snapshot) => snapshot.sessionId),\n );\n\n for (const [sessionId, streamHandle] of this.sessionStreams) {\n if (keepSessionIds.has(sessionId)) {\n continue;\n }\n\n streamHandle.abortController.abort();\n this.sessionStreams.delete(sessionId);\n }\n }\n\n private async consumeSessionEvents(\n snapshot: GooseSessionSnapshot,\n abortController: AbortController,\n ): Promise<void> {\n let response: Response;\n\n try {\n response = await this.fetchImplementation(\n new URL(\n `/sessions/${encodeURIComponent(snapshot.gooseSessionId)}/events`,\n this.apiBaseUrl,\n ),\n {\n headers: {\n ...this.createApiHeaders(),\n Accept: 'text/event-stream',\n },\n signal: abortController.signal,\n },\n );\n } catch (error) {\n if (abortController.signal.aborted) {\n return;\n }\n\n logger.debug({ error, sessionId: snapshot.sessionId }, 'Goose SSE request failed');\n return;\n }\n\n if (!response.ok || response.body === null) {\n logger.debug(\n { sessionId: snapshot.sessionId, status: response.status },\n 'Goose SSE stream is unavailable',\n );\n return;\n }\n\n const reader: ReadableStreamDefaultReader<Uint8Array> =\n response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const readResult = await reader.read();\n\n if (readResult.done) {\n break;\n }\n\n buffer += decoder.decode(readResult.value, { stream: true });\n\n while (true) {\n const delimiterIndex = buffer.indexOf('\\n\\n');\n\n if (delimiterIndex === -1) {\n break;\n }\n\n const frame = buffer.slice(0, delimiterIndex);\n\n buffer = buffer.slice(delimiterIndex + 2);\n await this.processSSEFrame(snapshot, frame);\n }\n }\n } catch (error) {\n if (!abortController.signal.aborted) {\n logger.debug(\n { error, sessionId: snapshot.sessionId },\n 'Goose SSE stream closed unexpectedly',\n );\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n private async processSSEFrame(\n snapshot: GooseSessionSnapshot,\n frame: string,\n ): Promise<void> {\n const payloadText = frame\n .split(/\\r?\\n/u)\n .filter((line) => line.startsWith('data:'))\n .map((line) => line.slice(5).trimStart())\n .join('\\n');\n\n if (payloadText.length === 0) {\n return;\n }\n\n let parsedPayload: unknown;\n\n try {\n parsedPayload = JSON.parse(payloadText) as unknown;\n } catch (error) {\n logger.warn({ error }, 'Goose SSE frame is not valid JSON');\n return;\n }\n\n await this.processSessionEvent(snapshot, parsedPayload);\n }\n\n private async processSessionEvent(\n snapshot: GooseSessionSnapshot,\n payload: unknown,\n ): Promise<void> {\n if (!isRecord(payload)) {\n return;\n }\n\n const fingerprint = createGooseFingerprint(payload);\n\n if (fingerprint && !this.markSessionEventSeen(snapshot.sessionId, fingerprint)) {\n return;\n }\n\n const eventType = getString(payload, 'type');\n\n switch (eventType) {\n case 'Message': {\n await this.processGooseMessage(snapshot, payload);\n return;\n }\n case 'Finish': {\n await this.ensureObservedSession(snapshot, 'sse');\n await this.emitStateChange(\n 'task.complete',\n buildGooseSessionData(snapshot, {\n raw: payload,\n tokensUsed: extractGooseTokenCount(getRecord(payload.token_state)),\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n return;\n }\n case 'Error': {\n const errorMessage = getString(payload, 'error');\n\n await this.ensureObservedSession(snapshot, 'sse');\n await this.emitStateChange(\n 'agent.error',\n buildGooseSessionData(snapshot, {\n errorMessage,\n errorType: inferGooseErrorType(errorMessage),\n raw: payload,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n return;\n }\n case 'Notification': {\n await this.ensureObservedSession(snapshot, 'sse');\n await this.emitStateChange(\n 'agent.asking_user',\n buildGooseSessionData(snapshot, {\n errorMessage: extractLooseString(payload, ['message']),\n raw: payload,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n return;\n }\n default:\n return;\n }\n }\n\n private async processGooseMessage(\n snapshot: GooseSessionSnapshot,\n payload: Record<string, unknown>,\n ): Promise<void> {\n const message = getRecord(payload.message);\n\n if (!message) {\n return;\n }\n\n const role = getString(message, 'role');\n const content = getRecordArray(message.content);\n const tokenState = getRecord(payload.token_state);\n const tokensUsed = extractGooseTokenCount(tokenState);\n\n await this.ensureObservedSession(snapshot, 'sse');\n\n if (role === 'user') {\n const promptText = content\n .filter((part) => getString(part, 'type') === 'text')\n .map((part) => getString(part, 'text'))\n .filter((part): part is string => typeof part === 'string')\n .join('\\n')\n .trim();\n\n await this.emitStateChange(\n 'task.start',\n buildGooseSessionData(snapshot, {\n raw: {\n message,\n prompt: promptText,\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n\n return;\n }\n\n if (role !== 'assistant') {\n return;\n }\n\n for (const part of content) {\n const partType = getString(part, 'type');\n\n switch (partType) {\n case 'thinking': {\n await this.emitStateChange(\n 'agent.thinking',\n buildGooseSessionData(snapshot, {\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'redactedThinking': {\n await this.emitStateChange(\n 'agent.thinking',\n buildGooseSessionData(snapshot, {\n raw: {\n message: {\n content: [\n {\n thinking: getString(part, 'data'),\n type: 'thinking',\n },\n ],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'text': {\n await this.emitStateChange(\n 'agent.streaming',\n buildGooseSessionData(snapshot, {\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'toolRequest': {\n const toolName = extractGooseToolName(part);\n const toolInput = extractGooseToolInput(part);\n const activeFile = toolInput?.filePath;\n const emittedType = isGooseCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call';\n\n await this.emitStateChange(\n emittedType,\n buildGooseSessionData(snapshot, {\n activeFile,\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n toolInput,\n toolName,\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'toolConfirmationRequest':\n case 'actionRequired': {\n await this.emitStateChange(\n 'agent.asking_user',\n buildGooseSessionData(snapshot, {\n errorMessage:\n getString(part, 'prompt') ??\n extractLooseString(getRecord(part.data), ['message']),\n raw: {\n message: {\n content: [part],\n role,\n },\n tokenState,\n },\n toolInput: extractGooseToolInput(part),\n toolName: extractGooseToolName(part),\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n case 'systemNotification': {\n const notificationType = getString(part, 'notificationType');\n const eventTypeToEmit =\n notificationType === 'thinkingMessage'\n ? 'agent.thinking'\n : 'agent.asking_user';\n\n await this.emitStateChange(\n eventTypeToEmit,\n buildGooseSessionData(snapshot, {\n errorMessage: getString(part, 'msg'),\n errorType:\n notificationType === 'creditsExhausted'\n ? 'rate_limit'\n : undefined,\n raw: {\n message:\n notificationType === 'thinkingMessage'\n ? {\n content: [\n {\n thinking: getString(part, 'msg'),\n type: 'thinking',\n },\n ],\n role,\n }\n : {\n content: [part],\n role,\n },\n tokenState,\n },\n tokensUsed,\n }),\n this.createSessionContext(snapshot, 'aisnitch://adapters/goose/sse'),\n );\n break;\n }\n default:\n break;\n }\n }\n }\n\n private async ensureObservedSession(\n snapshot: GooseSessionSnapshot,\n source: string,\n ): Promise<void> {\n if (this.observedSessions.has(snapshot.sessionId)) {\n return;\n }\n\n this.observedSessions.add(snapshot.sessionId);\n\n const context = this.createSessionContext(\n snapshot,\n `aisnitch://adapters/goose/${source}`,\n );\n const eventData = buildGooseSessionData(snapshot, {\n raw: {\n snapshot,\n source,\n },\n });\n\n await this.emitStateChange('session.start', eventData, context);\n await this.emitStateChange('agent.idle', eventData, context);\n }\n\n private createSessionContext(\n snapshot: GooseSessionSnapshot,\n source: string,\n ): AdapterPublishContext {\n return {\n cwd: snapshot.workingDir,\n sessionId: snapshot.sessionId,\n source,\n };\n }\n\n private markSessionEventSeen(sessionId: string, fingerprint: string): boolean {\n const knownFingerprints =\n this.sessionEventFingerprints.get(sessionId) ?? new Set<string>();\n\n if (knownFingerprints.has(fingerprint)) {\n return false;\n }\n\n if (knownFingerprints.size >= 256) {\n knownFingerprints.clear();\n }\n\n knownFingerprints.add(fingerprint);\n this.sessionEventFingerprints.set(sessionId, knownFingerprints);\n\n return true;\n }\n\n private createApiHeaders(): Record<string, string> | undefined {\n if (!this.apiKey) {\n return undefined;\n }\n\n return {\n Authorization: `Bearer ${this.apiKey}`,\n };\n }\n\n private async pollGooseProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `goose-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/goose/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/goose/process-detect',\n },\n );\n }\n }\n}\n\nfunction normalizeGooseSession(payload: unknown): GooseSessionSnapshot | null {\n if (!isRecord(payload)) {\n return null;\n }\n\n const gooseSessionId = getString(payload, 'id');\n\n if (!gooseSessionId) {\n return null;\n }\n\n const workingDir =\n getString(payload, 'working_dir') ?? getString(payload, 'workingDir');\n const name = getString(payload, 'name');\n const providerName =\n getString(payload, 'provider_name') ?? getString(payload, 'providerName');\n const updatedAt =\n getString(payload, 'updated_at') ?? getString(payload, 'updatedAt');\n const messageCount =\n getNumber(payload, 'message_count') ?? getNumber(payload, 'messageCount');\n const totalTokens =\n getNumber(payload, 'accumulated_total_tokens') ??\n getNumber(payload, 'total_tokens') ??\n getNumber(payload, 'accumulatedTotalTokens') ??\n getNumber(payload, 'totalTokens');\n const modelConfig = getRecord(payload.model_config) ?? getRecord(payload.modelConfig);\n const rawModelConfig = getString(payload, 'model_config');\n const parsedModelConfig =\n modelConfig ?? parseJsonRecord(rawModelConfig);\n const model = getString(parsedModelConfig, 'model_name') ?? getString(parsedModelConfig, 'modelName');\n const sessionId = resolveSessionId({\n cwd: workingDir,\n projectPath: workingDir,\n sessionId: gooseSessionId,\n tool: 'goose',\n });\n\n return {\n gooseSessionId,\n messageCount,\n model,\n name,\n providerName,\n sessionId,\n totalTokens,\n updatedAt,\n workingDir,\n };\n}\n\nfunction buildGooseSessionData(\n snapshot: GooseSessionSnapshot,\n overrides: Partial<Omit<EventData, 'state'>> = {},\n): Omit<EventData, 'state'> {\n return {\n cwd: overrides.cwd ?? snapshot.workingDir,\n model: overrides.model ?? snapshot.model,\n project: overrides.project ?? snapshot.name,\n projectPath: overrides.projectPath ?? snapshot.workingDir,\n raw: overrides.raw,\n tokensUsed: overrides.tokensUsed ?? snapshot.totalTokens,\n ...overrides,\n };\n}\n\nfunction compareGooseSessionsByRecency(\n left: GooseSessionSnapshot,\n right: GooseSessionSnapshot,\n): number {\n return Date.parse(right.updatedAt ?? '') - Date.parse(left.updatedAt ?? '');\n}\n\nfunction didGooseSessionAdvance(\n previousSnapshot: GooseSessionSnapshot,\n nextSnapshot: GooseSessionSnapshot,\n): boolean {\n return (\n previousSnapshot.updatedAt !== nextSnapshot.updatedAt ||\n previousSnapshot.messageCount !== nextSnapshot.messageCount ||\n previousSnapshot.totalTokens !== nextSnapshot.totalTokens\n );\n}\n\nfunction createGooseFingerprint(payload: Record<string, unknown>): string | null {\n const eventType = getString(payload, 'type');\n\n if (!eventType) {\n return null;\n }\n\n if (eventType === 'Message') {\n const message = getRecord(payload.message);\n const messageId = getString(message, 'id');\n const created = getNumber(message, 'created');\n const role = getString(message, 'role');\n\n return [eventType, messageId, created, role]\n .filter((value): value is string | number => value !== undefined)\n .join(':');\n }\n\n if (eventType === 'Finish') {\n return `${eventType}:${getString(payload, 'reason') ?? 'unknown'}`;\n }\n\n if (eventType === 'Error') {\n return `${eventType}:${getString(payload, 'error') ?? 'unknown'}`;\n }\n\n return eventType;\n}\n\nfunction extractGooseTokenCount(\n tokenState: Record<string, unknown> | undefined,\n): number | undefined {\n return (\n getNumber(tokenState, 'accumulatedTotalTokens') ??\n getNumber(tokenState, 'totalTokens')\n );\n}\n\nfunction extractGooseToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolCall = getRecord(payload.toolCall);\n\n return (\n getString(toolCall, 'name') ??\n getString(toolCall, 'toolName') ??\n getString(payload, 'toolName')\n );\n}\n\nfunction extractGooseToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const toolCall = getRecord(payload.toolCall);\n const argumentsRecord =\n getRecord(toolCall?.arguments) ??\n getRecord(toolCall?.args) ??\n getRecord(toolCall?.input) ??\n getRecord(payload.arguments);\n const filePath = extractFirstString(argumentsRecord, [\n 'file',\n 'file_path',\n 'filePath',\n 'path',\n 'target',\n 'target_path',\n 'targetPath',\n ]);\n const command = extractFirstString(argumentsRecord, [\n 'cmd',\n 'command',\n 'script',\n ]);\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction isGooseCodingTool(\n toolName: string | undefined,\n toolInput: ToolInput | undefined,\n): boolean {\n if (toolName && GOOSE_CODING_TOOL_HINT.test(toolName)) {\n return true;\n }\n\n const filePath = toolInput?.filePath;\n\n if (!filePath) {\n return false;\n }\n\n return !/read|view|glob|grep|list|search/iu.test(toolName ?? '');\n}\n\nfunction inferGooseErrorType(\n errorMessage: string | undefined,\n): ErrorType | undefined {\n if (!errorMessage) {\n return undefined;\n }\n\n if (GOOSE_RATE_LIMIT_HINT.test(errorMessage)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|too long/iu.test(errorMessage)) {\n return 'context_overflow';\n }\n\n if (/tool/iu.test(errorMessage)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n processListCommand: () => Promise<string>,\n): Promise<GooseProcessInfo[]> {\n try {\n const commandOutput = await processListCommand();\n\n return commandOutput\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const [pidPart, ...commandParts] = line.split(/\\s+/u);\n const pid = pidPart ? Number.parseInt(pidPart, 10) : Number.NaN;\n\n return {\n command: commandParts.join(' '),\n pid,\n } satisfies GooseProcessInfo;\n })\n .filter((processInfo) => Number.isInteger(processInfo.pid));\n } catch (error) {\n logger.debug({ error }, 'Goose process listing skipped');\n return [];\n }\n}\n\nfunction parseJsonRecord(\n value: string | undefined,\n): Record<string, unknown> | undefined {\n if (!value) {\n return undefined;\n }\n\n try {\n const parsedValue = JSON.parse(value) as unknown;\n\n return getRecord(parsedValue);\n } catch {\n return undefined;\n }\n}\n\nfunction extractFirstString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n }\n\n return undefined;\n}\n\nfunction extractLooseString(\n payload: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(payload, key);\n\n if (directValue) {\n return directValue;\n }\n\n const nestedValue = getString(getRecord(payload[key]), 'message');\n\n if (nestedValue) {\n return nestedValue;\n }\n }\n\n return undefined;\n}\n\nfunction getRecordArray(value: unknown): Record<string, unknown>[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.filter((entry): entry is Record<string, unknown> => isRecord(entry));\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/kilo.ts\n * @description Kilo CLI adapter covering process detection, ACP protocol integration,\n * and local data directory watching for the open-source Kilo Code agent.\n * @functions\n * โ†’ none\n * @exports KiloAdapter, KiloAdapterOptions\n * @see ./base.ts\n * @see ../../docs/priority-adapters.md\n *\n * ๐Ÿ“– Kilo is an open-source AI coding agent (10k+ stars on GitHub) that works with\n * VS Code, JetBrains, and as a standalone CLI. It ships an ACP (Agent Communication\n * Protocol) similar to OpenCode's, plus writes logs to ~/.config/kilo/ and\n * ~/.local/share/kilo/. Interception: process-detect primary, ACP plugin fallback.\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst KILO_CODING_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'Create',\n 'Delete',\n 'Move',\n 'ApplyDiff',\n]);\n\nexport interface KiloAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly configDirectory?: string;\n readonly dataDirectory?: string;\n readonly watcherFactory?: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface KiloProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface KiloSessionMetadata {\n readonly cwd?: string;\n readonly model?: string;\n readonly sessionId: string;\n}\n\n/**\n * ๐Ÿ“– Kilo uses an ACP protocol with JSON-RPC messages over stdin/stdout. The adapter\n * detects running processes and watches for session data files. When hooks are\n * available via the Kilo config, they are parsed as structured events.\n */\nexport class KiloAdapter extends BaseAdapter {\n public override readonly displayName = 'Kilo CLI';\n\n public override readonly name = 'kilo' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'jsonl-watch',\n 'hooks',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly configDirectory: string;\n\n private readonly dataDirectory: string;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionMetadata = new Map<string, KiloSessionMetadata>();\n\n private readonly transcriptOffsets = new Map<string, number>();\n\n private readonly transcriptRemainders = new Map<string, string>();\n\n private watcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: string,\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n public constructor(options: KiloAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () => {\n const results = await Promise.all([\n execFile('pgrep', ['-lf', 'kilo']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'kilocode']).catch(() => ({ stdout: '' })),\n execFile('pgrep', ['-lf', 'kilocode']).catch(() => ({ stdout: '' })),\n ]);\n return results.map((r) => r.stdout).join('\\n');\n });\n this.configDirectory =\n options.configDirectory ?? join(this.getUserHomeDirectory(), '.config', 'kilo');\n this.dataDirectory =\n options.dataDirectory ?? join(this.getUserHomeDirectory(), '.local', 'share', 'kilo');\n this.watcherFactory = options.watcherFactory ?? watch;\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await this.seedTranscriptOffsets();\n\n // Watch for Kilo session logs (additional patterns available for future expansion)\n const _logPatterns = [\n join(this.dataDirectory, '**', '*.jsonl'),\n join(this.configDirectory, 'logs', '**', '*.jsonl'),\n ];\n\n // Watch primary log directory\n this.watcher = this.watcherFactory(join(this.dataDirectory, '**', '*.jsonl'), {\n awaitWriteFinish: { stabilityThreshold: 200 },\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (filePath) => void this.processTranscriptUpdate(filePath, true));\n this.watcher.on('change', (filePath) => void this.processTranscriptUpdate(filePath, false));\n this.watcher.on('error', (error) => {\n logger.warn({ error }, 'Kilo log watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.watcher !== null) {\n await this.watcher.close();\n this.watcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.sessionMetadata.clear();\n this.transcriptOffsets.clear();\n this.transcriptRemainders.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'Kilo hook payload must be an object');\n return;\n }\n\n const sessionId = resolveSessionId({\n cwd: getString(payload, 'cwd'),\n pid: getNumber(payload, 'pid'),\n projectPath: getString(payload, 'projectPath'),\n sessionId:\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(getRecord(payload.data), 'sessionId'),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: getString(payload, 'cwd'),\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/kilo',\n };\n const eventType = getString(payload, 'event') ?? getString(payload, 'type') ?? getString(payload, 'method');\n const data = getRecord(payload.data) ?? payload;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName') ?? getString(data, 'name');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: context.cwd,\n model: getString(data, 'model') ?? getString(payload, 'model'),\n projectPath: getString(data, 'projectPath') ?? getString(payload, 'projectPath'),\n raw: payload,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.start':\n case 'sessionStart':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'sessionEnd':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'taskStart':\n case 'UserPrompt':\n case 'user_message': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'taskComplete':\n case 'TaskComplete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'tool.call':\n case 'toolCall':\n case 'PreToolUse': {\n await this.emitStateChange('agent.tool_call', sharedData, context);\n return;\n }\n case 'tool.result':\n case 'toolResult':\n case 'PostToolUse': {\n const emittedType = isKiloCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking':\n case 'reasoning': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'streaming':\n case 'Streaming':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(payload, 'error') ?? 'Kilo error',\n errorType: inferKiloErrorType(data),\n }, context);\n return;\n }\n case 'asking_user':\n case 'PermissionRequest':\n case 'input_required': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n logger.debug({ eventType }, 'Kilo hook event ignored by adapter');\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'Kilo transcript read skipped');\n return;\n }\n\n const knownOffset = this.transcriptOffsets.get(filePath);\n const previousOffset =\n knownOffset ?? (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.transcriptRemainders.get(filePath) ?? '') + newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.transcriptOffsets.set(filePath, fileContent.byteLength);\n this.transcriptRemainders.set(filePath, remainder);\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n if (trimmedLine.length === 0) {\n continue;\n }\n\n await this.processTranscriptLine(trimmedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: string,\n transcriptPath: string,\n ): Promise<void> {\n let parsedLine: unknown;\n\n try {\n parsedLine = JSON.parse(line) as unknown;\n } catch (error) {\n logger.warn({ error, transcriptPath }, 'Kilo transcript line is not valid JSON');\n return;\n }\n\n if (!isRecord(parsedLine)) {\n return;\n }\n\n // ACP protocol format: messages have type, id, session, data fields\n const acpType = getString(parsedLine, 'type') ?? getString(parsedLine, 'method');\n const sessionId = resolveSessionId({\n sessionId:\n getString(parsedLine, 'sessionId') ??\n getString(parsedLine, 'session_id') ??\n getString(parsedLine, 'id') ??\n basename(transcriptPath, '.jsonl'),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n env: process.env,\n hookPayload: parsedLine,\n sessionId,\n source: 'aisnitch://adapters/kilo/log',\n transcriptPath,\n };\n const data = getRecord(parsedLine.data) ?? parsedLine;\n const toolName = getString(data, 'tool') ?? getString(data, 'toolName');\n const toolInput = extractToolInput(data);\n const sharedData = {\n activeFile: toolInput?.filePath,\n cwd: getString(data, 'cwd'),\n model: getString(data, 'model'),\n raw: parsedLine,\n toolInput,\n toolName,\n } satisfies Omit<EventData, 'state'>;\n\n // Map Kilo/ACP message types to AISnitch events\n switch (acpType) {\n case 'session.start':\n case 'SessionStart': {\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.end':\n case 'SessionEnd': {\n await this.emitStateChange('session.end', sharedData, context);\n return;\n }\n case 'task.start':\n case 'TaskStart':\n case 'user_message': {\n await this.emitStateChange('task.start', sharedData, context);\n return;\n }\n case 'task.complete':\n case 'TaskComplete': {\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'thinking':\n case 'Thinking':\n case 'reasoning': {\n await this.emitStateChange('agent.thinking', sharedData, context);\n return;\n }\n case 'streaming':\n case 'assistant_message': {\n await this.emitStateChange('agent.streaming', sharedData, context);\n return;\n }\n case 'tool_call':\n case 'tool_use': {\n const emittedType = isKiloCodingTool(toolName) ? 'agent.coding' : 'agent.tool_call';\n await this.emitStateChange(emittedType, sharedData, context);\n return;\n }\n case 'error':\n case 'Error': {\n await this.emitStateChange('agent.error', {\n ...sharedData,\n errorMessage: getString(data, 'error') ?? getString(data, 'message'),\n errorType: inferKiloErrorType(data),\n }, context);\n return;\n }\n case 'permission_request':\n case 'asking_user': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n default:\n // ACP also sends heartbeat/ping messages โ€” ignore gracefully\n if (acpType === 'ping' || acpType === 'pong' || acpType === 'heartbeat') {\n return;\n }\n return;\n }\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n try {\n const files = await collectFilesRecursively(this.dataDirectory, '.jsonl');\n await Promise.all(\n files.map(async (filePath) => {\n try {\n const fileStats = await stat(filePath);\n this.transcriptOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore files that disappear between discovery and stat.\n }\n }),\n );\n } catch {\n // Data directory may not exist yet on first run.\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollKiloProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollKiloProcesses();\n }\n\n private async pollKiloProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `kilo-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n { raw: { process: processInfo, source: 'process-detect' } },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/kilo/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n { raw: { reason: 'process-exit', source: 'process-detect' } },\n {\n sessionId,\n source: 'aisnitch://adapters/kilo/process-detect',\n },\n );\n }\n }\n}\n\n// โ”€โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\nasync function collectFilesRecursively(\n directoryPath: string,\n extension: string,\n): Promise<string[]> {\n try {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const nestedResults = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = join(directoryPath, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return entry.name.endsWith(extension) ? [entryPath] : [];\n }),\n );\n\n return nestedResults.flat();\n } catch (error) {\n if (isErrnoException(error) && error.code === 'ENOENT') {\n return [];\n }\n\n throw error;\n }\n}\n\nfunction extractToolInput(\n payload: Record<string, unknown> | undefined,\n): ToolInput | undefined {\n if (!payload) {\n return undefined;\n }\n\n const toolInput = getRecord(payload.tool_input) ?? getRecord(payload.toolInput) ?? getRecord(payload.arguments) ?? getRecord(payload.params);\n const filePath =\n getString(toolInput, 'filePath') ??\n getString(toolInput, 'file_path') ??\n getString(toolInput, 'path') ??\n getString(toolInput, 'target');\n const command =\n getString(toolInput, 'command') ??\n getString(toolInput, 'cmd') ??\n getString(toolInput, 'script');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return { command, filePath };\n}\n\nfunction isKiloCodingTool(toolName?: string): boolean {\n return toolName !== undefined && KILO_CODING_TOOLS.has(toolName);\n}\n\nfunction inferKiloErrorType(\n payload: Record<string, unknown> | undefined,\n): ErrorType {\n const message =\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n '';\n\n if (/rate.?limit|quota|credit/i.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token.?limit|too.?long/i.test(message)) {\n return 'context_overflow';\n }\n\n if (/tool|permission|denied/i.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<KiloProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .filter((line) => line.includes('kilo') || line.includes('kilocode'))\n .map(parseProcessLine)\n .filter((processInfo): processInfo is KiloProcessInfo => processInfo !== null);\n } catch (error) {\n logger.debug({ error }, 'Kilo process detection failed');\n return [];\n }\n}\n\nfunction parseProcessLine(line: string): KiloProcessInfo | null {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n };\n}\n\nfunction isErrnoException(\n error: unknown,\n): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}","import { execFile as execFileCallback } from 'node:child_process';\nimport { readFile, readdir, stat } from 'node:fs/promises';\nimport { basename, dirname, extname, join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { watch, type FSWatcher } from 'chokidar';\nimport pidCwd from 'pid-cwd';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type {\n AISnitchEventType,\n ErrorType,\n EventData,\n ToolInput,\n} from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/openclaw.ts\n * @description OpenClaw adapter combining managed hook ingestion, bundled command logs, transcript watching, workspace-memory watching, and process fallback detection.\n * @functions\n * โ†’ none\n * @exports OpenClawAdapter, OpenClawAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/06-adapters-secondary/04_adapters-secondary_openclaw.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst COMMAND_START_THINKING_DELAY_MS = 2_000;\nconst POST_TOOL_THINKING_DELAY_MS = 500;\nconst OPENCLAW_CODING_TOOL_HINT =\n /apply|bash|create|delete|edit|exec|file|patch|replace|shell|write/iu;\nconst OPENCLAW_ERROR_HINT =\n /denied|error|exception|failed|quota|rate limit|refused|timeout/iu;\n\nexport interface OpenClawAdapterOptions extends AdapterRuntimeOptions {\n readonly agentsDirectory?: string;\n readonly commandsLogPath?: string;\n readonly cwdResolver?: (pid: number) => Promise<string | undefined>;\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n readonly watcherFactory?: (\n paths: Parameters<typeof watch>[0],\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n}\n\ninterface OpenClawProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\ninterface OpenClawSessionSnapshot {\n readonly cwd?: string;\n readonly project?: string;\n readonly sessionId: string;\n readonly sessionKey?: string;\n readonly transcriptPath?: string;\n}\n\ninterface PendingThinkingState {\n readonly context: AdapterPublishContext;\n readonly data: Omit<EventData, 'state'>;\n}\n\n/**\n * ๐Ÿ“– OpenClaw has several passive surfaces, but none of them is perfect alone.\n * AISnitch therefore merges the real managed hook path with filesystem and\n * process fallbacks so operators still get signal when setup is partial.\n */\nexport class OpenClawAdapter extends BaseAdapter {\n public override readonly displayName = 'OpenClaw';\n\n public override readonly name = 'openclaw' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'log-watch',\n 'jsonl-watch',\n 'process-detect',\n ];\n\n private readonly agentsDirectory: string;\n\n private readonly commandsLogPath: string;\n\n private commandsLogWatcher: FSWatcher | null = null;\n\n private readonly cwdResolver: (pid: number) => Promise<string | undefined>;\n\n private readonly fallbackProcessSessions = new Map<number, string>();\n\n private readonly observedTranscriptEntries = new Set<string>();\n\n private readonly pendingThinking = new Map<string, NodeJS.Timeout>();\n\n private readonly pendingThinkingState = new Map<string, PendingThinkingState>();\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n private readonly sessionSnapshots = new Map<string, OpenClawSessionSnapshot>();\n\n private readonly startedSessions = new Set<string>();\n\n private transcriptWatcher: FSWatcher | null = null;\n\n private readonly watcherFactory: (\n paths: Parameters<typeof watch>[0],\n options: Parameters<typeof watch>[1],\n ) => FSWatcher;\n\n private readonly memoryRootGlobs: readonly string[];\n\n private memoryWatcher: FSWatcher | null = null;\n\n private readonly fileOffsets = new Map<string, number>();\n\n private readonly fileRemainders = new Map<string, string>();\n\n public constructor(options: OpenClawAdapterOptions) {\n super(options);\n\n const openclawHome = join(this.getUserHomeDirectory(), '.openclaw');\n\n this.agentsDirectory = options.agentsDirectory ?? join(openclawHome, 'agents');\n this.commandsLogPath =\n options.commandsLogPath ?? join(openclawHome, 'logs', 'commands.log');\n this.cwdResolver =\n options.cwdResolver ??\n (async (pid) => {\n return await pidCwd(pid);\n });\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ??\n (async () =>\n await execFile('pgrep', ['-ifl', 'openclaw']).then(\n (result) => result.stdout,\n ));\n this.watcherFactory = options.watcherFactory ?? watch;\n this.memoryRootGlobs = [\n join(openclawHome, 'workspace', 'MEMORY.md'),\n join(openclawHome, 'workspace', 'memory', '*.md'),\n join(openclawHome, 'workspace-*', 'MEMORY.md'),\n join(openclawHome, 'workspace-*', 'memory', '*.md'),\n ];\n }\n\n public override async start(): Promise<void> {\n if (this.getStatus().running) {\n return;\n }\n\n this.setRunning(true);\n await Promise.all([\n this.seedCommandsLogOffset(),\n this.seedMemoryOffsets(),\n this.seedTranscriptOffsets(),\n ]);\n\n this.commandsLogWatcher = this.watcherFactory(this.commandsLogPath, {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n });\n this.commandsLogWatcher.on('add', (filePath) => {\n void this.processCommandsLogUpdate(filePath, true);\n });\n this.commandsLogWatcher.on('change', (filePath) => {\n void this.processCommandsLogUpdate(filePath, false);\n });\n this.commandsLogWatcher.on('error', (error) => {\n logger.warn({ error }, 'OpenClaw commands.log watcher error');\n });\n\n this.transcriptWatcher = this.watcherFactory(\n join(this.agentsDirectory, '*', 'sessions', '*.jsonl'),\n {\n awaitWriteFinish: {\n stabilityThreshold: 200,\n },\n ignoreInitial: true,\n },\n );\n this.transcriptWatcher.on('add', (filePath) => {\n void this.processTranscriptUpdate(filePath, true);\n });\n this.transcriptWatcher.on('change', (filePath) => {\n void this.processTranscriptUpdate(filePath, false);\n });\n this.transcriptWatcher.on('error', (error) => {\n logger.warn({ error }, 'OpenClaw transcript watcher error');\n });\n\n this.memoryWatcher = this.watcherFactory([...this.memoryRootGlobs], {\n awaitWriteFinish: {\n stabilityThreshold: 300,\n },\n ignoreInitial: true,\n });\n this.memoryWatcher.on('add', (filePath) => {\n void this.processMemoryUpdate(filePath, true);\n });\n this.memoryWatcher.on('change', (filePath) => {\n void this.processMemoryUpdate(filePath, false);\n });\n this.memoryWatcher.on('error', (error) => {\n logger.warn({ error }, 'OpenClaw memory watcher error');\n });\n\n this.startProcessPolling();\n }\n\n public override async stop(): Promise<void> {\n if (this.commandsLogWatcher !== null) {\n await this.commandsLogWatcher.close();\n this.commandsLogWatcher = null;\n }\n\n if (this.transcriptWatcher !== null) {\n await this.transcriptWatcher.close();\n this.transcriptWatcher = null;\n }\n\n if (this.memoryWatcher !== null) {\n await this.memoryWatcher.close();\n this.memoryWatcher = null;\n }\n\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n for (const timer of this.pendingThinking.values()) {\n clearTimeout(timer);\n }\n\n this.fileOffsets.clear();\n this.fileRemainders.clear();\n this.fallbackProcessSessions.clear();\n this.observedTranscriptEntries.clear();\n this.pendingThinking.clear();\n this.pendingThinkingState.clear();\n this.sessionSnapshots.clear();\n this.startedSessions.clear();\n this.setRunning(false);\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n transcriptPath: normalizedPayload.transcriptPath,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'OpenClaw payload must be an object');\n return;\n }\n\n await this.processNativePayload(\n payload,\n 'aisnitch://adapters/openclaw/hooks',\n extractOpenClawEventName(payload),\n );\n }\n\n private async processNativePayload(\n payload: Record<string, unknown>,\n source: string,\n eventName: string | undefined,\n transcriptPath?: string,\n ): Promise<void> {\n if (!eventName) {\n logger.debug({ payload, source }, 'OpenClaw payload missing event name');\n return;\n }\n\n const sessionId = resolveSessionId({\n activeFile: extractOpenClawActiveFile(payload),\n cwd: extractOpenClawCwd(payload),\n pid: getNumber(payload, 'pid'),\n project: extractOpenClawProject(payload),\n projectPath: extractOpenClawCwd(payload),\n sessionId: extractOpenClawSessionKey(payload),\n tool: this.name,\n transcriptPath,\n });\n const context: AdapterPublishContext = {\n cwd: extractOpenClawCwd(payload),\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source,\n transcriptPath,\n };\n const sharedData = buildOpenClawEventData(payload);\n\n this.sessionSnapshots.set(sessionId, {\n cwd: sharedData.cwd,\n project: sharedData.project,\n sessionId,\n sessionKey: extractOpenClawSessionKey(payload),\n transcriptPath,\n });\n\n switch (eventName) {\n case 'gateway:startup':\n case 'agent:bootstrap': {\n await this.emitOpenClawSessionStart(sharedData, context);\n return;\n }\n case 'command:new':\n case '/new': {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange('task.start', sharedData, context);\n this.scheduleThinking(sessionId, sharedData, context, COMMAND_START_THINKING_DELAY_MS);\n return;\n }\n case 'command:stop':\n case '/stop': {\n this.clearThinking(sessionId);\n await this.emitStateChange('task.complete', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'command:reset':\n case '/reset':\n case 'gateway:shutdown': {\n await this.emitOpenClawSessionEnd(sharedData, context);\n return;\n }\n case 'session:compact:before':\n case 'before_compaction': {\n await this.ensureSessionStarted(sharedData, context);\n this.clearThinking(sessionId);\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n case 'tool_result_persist': {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange(\n isOpenClawCodingTool(sharedData.toolName, sharedData.toolInput)\n ? 'agent.coding'\n : 'agent.tool_call',\n sharedData,\n context,\n );\n this.scheduleThinking(sessionId, sharedData, context, POST_TOOL_THINKING_DELAY_MS);\n return;\n }\n case 'message:received':\n case 'message:preprocessed':\n case 'session:compact:after':\n case 'after_compaction': {\n logger.debug({ eventName }, 'OpenClaw event intentionally ignored');\n return;\n }\n default: {\n logger.debug({ eventName }, 'OpenClaw event ignored by adapter');\n }\n }\n }\n\n private async emitOpenClawSessionStart(\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n const sessionId = context.sessionId;\n\n if (!sessionId) {\n return;\n }\n\n if (this.startedSessions.has(sessionId)) {\n await this.emitStateChange('agent.idle', data, context);\n return;\n }\n\n this.startedSessions.add(sessionId);\n await this.emitStateChange('session.start', data, context);\n await this.emitStateChange('agent.idle', data, context);\n }\n\n private async emitOpenClawSessionEnd(\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n const sessionId = context.sessionId;\n\n if (sessionId) {\n this.clearThinking(sessionId);\n this.startedSessions.delete(sessionId);\n this.sessionSnapshots.delete(sessionId);\n }\n\n await this.emitStateChange('session.end', data, context);\n }\n\n private async ensureSessionStarted(\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n ): Promise<void> {\n const sessionId = context.sessionId;\n\n if (!sessionId || this.startedSessions.has(sessionId)) {\n return;\n }\n\n await this.emitOpenClawSessionStart(\n {\n ...data,\n raw: {\n reason: 'implicit-start',\n source: context.source,\n ...(data.raw ?? {}),\n },\n },\n context,\n );\n }\n\n private scheduleThinking(\n sessionId: string,\n data: Omit<EventData, 'state'>,\n context: AdapterPublishContext,\n delayMs: number,\n ): void {\n this.clearThinking(sessionId);\n this.pendingThinkingState.set(sessionId, { context, data });\n\n const timer = setTimeout(() => {\n const thinkingState = this.pendingThinkingState.get(sessionId);\n\n if (!thinkingState) {\n return;\n }\n\n this.pendingThinking.delete(sessionId);\n this.pendingThinkingState.delete(sessionId);\n void this.emitStateChange(\n 'agent.thinking',\n thinkingState.data,\n thinkingState.context,\n );\n }, delayMs);\n timer.unref();\n\n this.pendingThinking.set(sessionId, timer);\n }\n\n private clearThinking(sessionId: string): void {\n const timer = this.pendingThinking.get(sessionId);\n\n if (timer) {\n clearTimeout(timer);\n }\n\n this.pendingThinking.delete(sessionId);\n this.pendingThinkingState.delete(sessionId);\n }\n\n private async seedCommandsLogOffset(): Promise<void> {\n await this.seedFileOffset(this.commandsLogPath);\n }\n\n private async seedTranscriptOffsets(): Promise<void> {\n const files = await collectFilesRecursively(this.agentsDirectory, '.jsonl');\n\n await Promise.all(files.map(async (filePath) => await this.seedFileOffset(filePath)));\n }\n\n private async seedMemoryOffsets(): Promise<void> {\n for (const root of [join(this.getUserHomeDirectory(), '.openclaw', 'workspace')]) {\n await Promise.all([\n this.seedDirectoryFileOffsets(join(root, 'memory'), '.md'),\n this.seedFileOffset(join(root, 'MEMORY.md')),\n ]);\n }\n }\n\n private async seedDirectoryFileOffsets(\n directory: string,\n extension: string,\n ): Promise<void> {\n const files = await collectFilesRecursively(directory, extension);\n\n await Promise.all(files.map(async (filePath) => await this.seedFileOffset(filePath)));\n }\n\n private async seedFileOffset(filePath: string): Promise<void> {\n try {\n const fileStats = await stat(filePath);\n\n this.fileOffsets.set(filePath, fileStats.size);\n } catch {\n // Ignore missing files while the source is still dormant.\n }\n }\n\n private async processCommandsLogUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n const lines = await this.readIncrementalLines(filePath, readFromStart);\n\n for (const line of lines) {\n const payload = parseJsonRecord(line);\n\n if (!payload) {\n logger.debug({ filePath, line }, 'OpenClaw commands.log line ignored');\n continue;\n }\n\n await this.processNativePayload(\n payload,\n 'aisnitch://adapters/openclaw/commands-log',\n extractOpenClawEventName(payload),\n );\n }\n }\n\n private async processTranscriptUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n const lines = await this.readIncrementalLines(filePath, readFromStart);\n\n for (const line of lines) {\n const parsedLine = parseJsonRecord(line);\n\n if (!parsedLine) {\n continue;\n }\n\n await this.processTranscriptLine(parsedLine, filePath);\n }\n }\n\n private async processTranscriptLine(\n line: Record<string, unknown>,\n filePath: string,\n ): Promise<void> {\n const rawSessionId =\n extractOpenClawSessionKey(line) ??\n inferOpenClawSessionIdFromTranscriptPath(filePath);\n const cwd = extractOpenClawCwd(line) ?? dirname(dirname(filePath));\n const sessionId = resolveSessionId({\n cwd,\n projectPath: cwd,\n sessionId: rawSessionId,\n tool: this.name,\n transcriptPath: filePath,\n });\n const eventFingerprint =\n getString(line, 'id') ??\n `${filePath}:${getString(line, 'timestamp') ?? JSON.stringify(line).slice(0, 120)}`;\n const dedupeKey = `${sessionId}:${eventFingerprint}`;\n\n if (this.observedTranscriptEntries.has(dedupeKey)) {\n return;\n }\n\n if (this.observedTranscriptEntries.size >= 4096) {\n this.observedTranscriptEntries.clear();\n }\n\n this.observedTranscriptEntries.add(dedupeKey);\n\n const context: AdapterPublishContext = {\n cwd,\n sessionId,\n source: 'aisnitch://adapters/openclaw/transcript',\n transcriptPath: filePath,\n };\n const sharedData: Omit<EventData, 'state'> = {\n cwd,\n project: basename(cwd) || cwd,\n projectPath: cwd,\n raw: line,\n };\n\n this.sessionSnapshots.set(sessionId, {\n cwd,\n project: sharedData.project,\n sessionId,\n transcriptPath: filePath,\n });\n\n if (getString(line, 'type') === 'session') {\n await this.emitOpenClawSessionStart(sharedData, context);\n return;\n }\n\n if (getString(line, 'type') === 'compaction') {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n\n const transcriptToolObservation = extractOpenClawTranscriptToolObservation(line);\n\n if (transcriptToolObservation) {\n const toolData: Omit<EventData, 'state'> = {\n ...sharedData,\n activeFile: transcriptToolObservation.activeFile,\n toolInput: transcriptToolObservation.toolInput,\n toolName: transcriptToolObservation.toolName,\n };\n\n await this.ensureSessionStarted(toolData, context);\n await this.emitStateChange(\n transcriptToolObservation.type,\n toolData,\n context,\n );\n this.scheduleThinking(sessionId, toolData, context, POST_TOOL_THINKING_DELAY_MS);\n return;\n }\n\n const thinkingText = extractOpenClawTranscriptThinkingText(line);\n\n if (thinkingText) {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange(\n 'agent.thinking',\n {\n ...sharedData,\n raw: {\n source: line,\n thinking: thinkingText,\n },\n },\n context,\n );\n return;\n }\n\n const streamingText = extractOpenClawTranscriptStreamingText(line);\n\n if (streamingText) {\n await this.ensureSessionStarted(sharedData, context);\n await this.emitStateChange(\n 'agent.streaming',\n {\n ...sharedData,\n raw: {\n content: streamingText,\n source: line,\n },\n },\n context,\n );\n }\n }\n\n private async processMemoryUpdate(\n filePath: string,\n readFromStart: boolean,\n ): Promise<void> {\n const baseName = basename(filePath);\n const resolvedSession = this.resolveMemorySession(filePath);\n\n if (!resolvedSession) {\n return;\n }\n\n const context: AdapterPublishContext = {\n cwd: resolvedSession.cwd,\n sessionId: resolvedSession.sessionId,\n source: 'aisnitch://adapters/openclaw/memory',\n };\n\n if (baseName === 'MEMORY.md') {\n await this.ensureSessionStarted(\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n source: 'memory-file',\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.compact',\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n source: 'memory-file',\n },\n },\n context,\n );\n return;\n }\n\n const lines = await this.readIncrementalLines(filePath, readFromStart);\n const snippet = lines.at(-1)?.trim();\n\n if (!snippet) {\n return;\n }\n\n await this.ensureSessionStarted(\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n source: 'memory-log',\n },\n },\n context,\n );\n await this.emitStateChange(\n 'agent.thinking',\n {\n cwd: resolvedSession.cwd,\n project: resolvedSession.project,\n projectPath: resolvedSession.cwd,\n raw: {\n filePath,\n snippet,\n source: 'memory-log',\n },\n },\n context,\n );\n }\n\n private resolveMemorySession(\n filePath: string,\n ): OpenClawSessionSnapshot | undefined {\n const workspaceDirectory =\n basename(filePath) === 'MEMORY.md' ? dirname(filePath) : dirname(dirname(filePath));\n\n for (const snapshot of this.sessionSnapshots.values()) {\n if (snapshot.cwd === workspaceDirectory) {\n return snapshot;\n }\n }\n\n const sessionId = resolveSessionId({\n cwd: workspaceDirectory,\n projectPath: workspaceDirectory,\n sessionId: `openclaw:${basename(workspaceDirectory)}:memory`,\n tool: this.name,\n });\n\n return {\n cwd: workspaceDirectory,\n project: basename(workspaceDirectory) || workspaceDirectory,\n sessionId,\n };\n }\n\n private async readIncrementalLines(\n filePath: string,\n readFromStart: boolean,\n ): Promise<readonly string[]> {\n let fileContent: Buffer;\n\n try {\n fileContent = await readFile(filePath);\n } catch (error) {\n logger.debug({ error, filePath }, 'OpenClaw source read skipped');\n return [];\n }\n\n const knownOffset = this.fileOffsets.get(filePath);\n const previousOffset =\n knownOffset ??\n (readFromStart ? 0 : fileContent.byteLength);\n const safeOffset =\n previousOffset > fileContent.byteLength ? 0 : previousOffset;\n const newChunk = fileContent.subarray(safeOffset).toString('utf8');\n const bufferedChunk =\n (safeOffset === 0 ? '' : this.fileRemainders.get(filePath) ?? '') +\n newChunk;\n const lines = bufferedChunk.split(/\\r?\\n/u);\n const remainder =\n bufferedChunk.endsWith('\\n') || bufferedChunk.endsWith('\\r')\n ? ''\n : (lines.pop() ?? '');\n\n this.fileOffsets.set(filePath, fileContent.byteLength);\n this.fileRemainders.set(filePath, remainder);\n\n return lines\n .map((line) => line.trimEnd())\n .filter((line) => line.trim().length > 0);\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollOpenClawProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollOpenClawProcesses();\n }\n\n private async pollOpenClawProcesses(): Promise<void> {\n const processes = await listOpenClawProcesses(this.processListCommand);\n const observedPids = new Set<number>();\n\n for (const processInfo of processes) {\n observedPids.add(processInfo.pid);\n\n if (this.fallbackProcessSessions.has(processInfo.pid)) {\n continue;\n }\n\n const cwd = await this.cwdResolver(processInfo.pid);\n const sessionId = resolveSessionId({\n cwd,\n pid: processInfo.pid,\n projectPath: cwd,\n sessionId: `openclaw-process-${processInfo.pid}`,\n tool: this.name,\n });\n const data: Omit<EventData, 'state'> = {\n cwd,\n project: cwd ? basename(cwd) || cwd : undefined,\n projectPath: cwd,\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n };\n const context: AdapterPublishContext = {\n cwd,\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/openclaw/process-detect',\n };\n\n this.fallbackProcessSessions.set(processInfo.pid, sessionId);\n this.sessionSnapshots.set(sessionId, {\n cwd,\n project: data.project,\n sessionId,\n });\n await this.emitOpenClawSessionStart(data, context);\n }\n\n for (const [pid, sessionId] of this.fallbackProcessSessions) {\n if (observedPids.has(pid)) {\n continue;\n }\n\n this.fallbackProcessSessions.delete(pid);\n await this.emitOpenClawSessionEnd(\n {\n raw: {\n pid,\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/openclaw/process-detect',\n },\n );\n }\n }\n}\n\nasync function collectFilesRecursively(\n directory: string,\n extension: string,\n): Promise<string[]> {\n try {\n const directoryEntries = await readdir(directory, {\n withFileTypes: true,\n });\n const nestedFiles = await Promise.all(\n directoryEntries.map(async (entry) => {\n const entryPath = join(directory, entry.name);\n\n if (entry.isDirectory()) {\n return await collectFilesRecursively(entryPath, extension);\n }\n\n return extname(entry.name) === extension ? [entryPath] : [];\n }),\n );\n\n return nestedFiles.flat();\n } catch {\n return [];\n }\n}\n\nasync function listOpenClawProcesses(\n listCommand: () => Promise<string>,\n): Promise<OpenClawProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n } satisfies OpenClawProcessInfo;\n })\n .filter((value): value is OpenClawProcessInfo => value !== null);\n } catch (error) {\n const errorCode =\n error instanceof Error && 'code' in error ? String(error.code) : '';\n\n if (\n error instanceof Error &&\n 'code' in error &&\n (errorCode === 'ENOENT' || errorCode === '1')\n ) {\n return [];\n }\n\n logger.debug({ error }, 'OpenClaw process detection failed');\n return [];\n }\n}\n\nfunction buildOpenClawEventData(\n payload: Record<string, unknown>,\n): Omit<EventData, 'state'> {\n const cwd = extractOpenClawCwd(payload);\n const project = extractOpenClawProject(payload);\n const toolInput = extractOpenClawToolInput(payload);\n\n return {\n activeFile: extractOpenClawActiveFile(payload) ?? toolInput?.filePath,\n cwd,\n errorMessage: extractOpenClawErrorMessage(payload),\n errorType: inferOpenClawErrorType(payload),\n model: extractOpenClawModel(payload),\n project,\n projectPath: cwd,\n raw: payload,\n toolInput,\n toolName: extractOpenClawToolName(payload),\n tokensUsed: extractOpenClawTokens(payload),\n };\n}\n\nfunction extractOpenClawEventName(\n payload: Record<string, unknown>,\n): string | undefined {\n const explicitEvent =\n getString(payload, 'event') ??\n getString(payload, 'hook_event_name') ??\n getString(payload, 'hookEventName');\n\n if (explicitEvent) {\n return explicitEvent;\n }\n\n const type = getString(payload, 'type');\n const action = getString(payload, 'action');\n\n if (!type) {\n return undefined;\n }\n\n if (!action) {\n return type;\n }\n\n if (type === 'command' && !action.startsWith('/') && !action.includes(':')) {\n return `command:${action}`;\n }\n\n return `${type}:${action}`;\n}\n\nfunction extractOpenClawSessionKey(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'sessionKey') ??\n getString(payload, 'sessionId') ??\n getString(payload, 'session_id') ??\n getString(getRecord(payload.context), 'sessionKey') ??\n getString(getRecord(payload.context), 'sessionId') ??\n getString(getRecord(payload.context), 'session_id') ??\n getString(getRecord(payload.context), 'sessionEntry')\n );\n}\n\nfunction extractOpenClawCwd(\n payload: Record<string, unknown>,\n): string | undefined {\n const context = getRecord(payload.context);\n\n return (\n getString(payload, 'cwd') ??\n getString(payload, 'workspaceDir') ??\n getString(context, 'workspaceDir') ??\n getString(context, 'cwd')\n );\n}\n\nfunction extractOpenClawProject(\n payload: Record<string, unknown>,\n): string | undefined {\n const cwd = extractOpenClawCwd(payload);\n\n if (cwd) {\n return basename(cwd) || cwd;\n }\n\n return (\n getString(payload, 'project') ??\n getString(getRecord(payload.context), 'project')\n );\n}\n\nfunction extractOpenClawActiveFile(\n payload: Record<string, unknown>,\n): string | undefined {\n const toolInput = extractOpenClawToolInput(payload);\n\n return (\n getString(payload, 'activeFile') ??\n getString(payload, 'filePath') ??\n getString(getRecord(payload.context), 'filePath') ??\n toolInput?.filePath\n );\n}\n\nfunction extractOpenClawToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'toolName') ??\n getString(payload, 'tool_name') ??\n getString(getRecord(payload.tool), 'name') ??\n getString(getRecord(payload.data), 'toolName') ??\n getString(getRecord(payload.result), 'toolName')\n );\n}\n\nfunction extractOpenClawToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const context = getRecord(payload.context);\n const argsRecord =\n getRecord(payload.toolInput) ??\n getRecord(payload.tool_input) ??\n getRecord(payload.params) ??\n getRecord(payload.arguments) ??\n getRecord(getRecord(payload.tool)?.params) ??\n getRecord(getRecord(payload.tool)?.arguments) ??\n getRecord(context?.params) ??\n getRecord(context?.arguments);\n const filePath =\n getString(payload, 'filePath') ??\n getString(argsRecord, 'filePath') ??\n getString(argsRecord, 'path');\n const command =\n getString(payload, 'command') ??\n getString(argsRecord, 'command') ??\n getString(argsRecord, 'cmd');\n\n if (!filePath && !command) {\n return undefined;\n }\n\n return {\n ...(command ? { command } : {}),\n ...(filePath ? { filePath } : {}),\n };\n}\n\nfunction extractOpenClawErrorMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'error') ??\n getString(payload, 'message') ??\n getString(getRecord(payload.error), 'message') ??\n getString(getRecord(payload.result), 'error')\n );\n}\n\nfunction inferOpenClawErrorType(\n payload: Record<string, unknown>,\n): ErrorType | undefined {\n const errorMessage = extractOpenClawErrorMessage(payload);\n\n if (!errorMessage) {\n return undefined;\n }\n\n const normalizedMessage = errorMessage.toLowerCase();\n\n if (normalizedMessage.includes('rate limit') || normalizedMessage.includes('quota')) {\n return 'rate_limit';\n }\n\n if (\n normalizedMessage.includes('context window') ||\n normalizedMessage.includes('context length') ||\n normalizedMessage.includes('too many tokens')\n ) {\n return 'context_overflow';\n }\n\n return OPENCLAW_ERROR_HINT.test(errorMessage) ? 'tool_failure' : 'api_error';\n}\n\nfunction extractOpenClawModel(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'model') ??\n getString(getRecord(payload.context), 'model') ??\n getString(getRecord(payload.sessionEntry), 'model')\n );\n}\n\nfunction extractOpenClawTokens(\n payload: Record<string, unknown>,\n): number | undefined {\n const directTokens =\n getNumber(payload, 'totalTokens') ??\n getNumber(payload, 'tokensUsed') ??\n getNumber(getRecord(payload.sessionEntry), 'totalTokens') ??\n getNumber(getRecord(payload.stats), 'totalTokens');\n\n return directTokens === undefined ? undefined : Math.max(0, directTokens);\n}\n\nfunction isOpenClawCodingTool(\n toolName: string | undefined,\n toolInput: ToolInput | undefined,\n): boolean {\n return Boolean(\n toolInput?.filePath ||\n (toolName && OPENCLAW_CODING_TOOL_HINT.test(toolName)),\n );\n}\n\nfunction inferOpenClawSessionIdFromTranscriptPath(\n filePath: string,\n): string | undefined {\n const fileName = basename(filePath, extname(filePath));\n\n return fileName.length > 0 ? fileName : undefined;\n}\n\nfunction extractOpenClawTranscriptToolObservation(\n payload: Record<string, unknown>,\n):\n | {\n readonly activeFile?: string;\n readonly toolInput?: ToolInput;\n readonly toolName?: string;\n readonly type: AISnitchEventType;\n }\n | null {\n const nestedMessage = getRecord(payload.message) ?? getRecord(payload.data);\n const role =\n getString(payload, 'role') ??\n getString(nestedMessage, 'role') ??\n getString(getRecord(payload.entry), 'role');\n const toolName =\n extractOpenClawToolName(payload) ??\n getString(nestedMessage, 'name') ??\n getString(getRecord(payload.tool), 'name');\n const toolInput = extractOpenClawToolInput(payload);\n const activeFile =\n extractOpenClawActiveFile(payload) ??\n getString(nestedMessage, 'filePath') ??\n toolInput?.filePath;\n const content = getString(nestedMessage, 'content');\n const looksLikeToolPayload = Boolean(\n role === 'tool' ||\n role === 'tool_result' ||\n toolName ||\n getString(payload, 'type') === 'tool_result' ||\n content?.includes('tool') ||\n Array.isArray(getRecord(nestedMessage)?.content),\n );\n\n if (!looksLikeToolPayload) {\n return null;\n }\n\n return {\n activeFile,\n toolInput,\n toolName,\n type: isOpenClawCodingTool(toolName, toolInput)\n ? 'agent.coding'\n : 'agent.tool_call',\n };\n}\n\nfunction extractOpenClawTranscriptThinkingText(\n payload: Record<string, unknown>,\n): string | undefined {\n const directReasoning =\n getString(payload, 'reasoning') ??\n getString(getRecord(payload.message), 'reasoning') ??\n getString(getRecord(payload.data), 'reasoning');\n\n if (directReasoning) {\n return directReasoning;\n }\n\n const content = getRecord(payload.message)?.content;\n\n if (!Array.isArray(content)) {\n return undefined;\n }\n\n for (const item of content) {\n const itemRecord = getRecord(item);\n const itemType = getString(itemRecord, 'type');\n\n if (itemType === 'thinking' || itemType === 'reasoning') {\n return (\n getString(itemRecord, 'thinking') ??\n getString(itemRecord, 'text') ??\n getString(itemRecord, 'content')\n );\n }\n }\n\n return undefined;\n}\n\nfunction extractOpenClawTranscriptStreamingText(\n payload: Record<string, unknown>,\n): string | undefined {\n const directText =\n getString(payload, 'text') ??\n getString(getRecord(payload.message), 'text') ??\n getString(getRecord(payload.data), 'text');\n\n if (directText) {\n return directText;\n }\n\n const content = getRecord(payload.message)?.content;\n\n if (!Array.isArray(content)) {\n return undefined;\n }\n\n for (const item of content) {\n const itemRecord = getRecord(item);\n const itemType = getString(itemRecord, 'type');\n\n if (itemType === 'text' || itemType === 'output_text') {\n return getString(itemRecord, 'text') ?? getString(itemRecord, 'content');\n }\n }\n\n return undefined;\n}\n\nfunction parseJsonRecord(value: string): Record<string, unknown> | null {\n try {\n const parsedValue = JSON.parse(value) as unknown;\n\n return getRecord(parsedValue) ?? null;\n } catch {\n return null;\n }\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const value = payload?.[key];\n\n return typeof value === 'string' && value.trim().length > 0\n ? value\n : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown> | undefined,\n key: string,\n): number | undefined {\n const value = payload?.[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport { logger } from '../core/engine/logger.js';\nimport { resolveSessionId } from '../core/session-identity.js';\nimport type { ErrorType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * @file src/adapters/opencode.ts\n * @description OpenCode adapter centered on the official plugin system plus process fallback detection.\n * @functions\n * โ†’ none\n * @exports OpenCodeAdapter, OpenCodeAdapterOptions\n * @see ./base.ts\n * @see ../cli/commands/setup.ts\n * @see ../../tasks/04-adapters-priority/03_adapters-priority_opencode.md\n */\n\nconst execFile = promisify(execFileCallback);\n\nconst OPENCODE_CODING_TOOLS = new Set(['edit', 'multi_edit', 'write']);\n\n/**\n * OpenCode officially documents plugin hooks and ACP subprocess support.\n * The plugin path is the stable passive-observer option for AISnitch today;\n * ACP is interactive editor transport, not a passive tap into a running TUI.\n */\nexport interface OpenCodeAdapterOptions extends AdapterRuntimeOptions {\n readonly pollIntervalMs?: number;\n readonly processListCommand?: () => Promise<string>;\n}\n\ninterface ProcessInfo {\n readonly command: string;\n readonly pid: number;\n}\n\n/**\n * ๐Ÿ“– The setup command already installs an OpenCode plugin that forwards\n * events over HTTP, so this adapter mostly focuses on mapping that stream\n * cleanly and falling back to process detection when setup was skipped.\n */\nexport class OpenCodeAdapter extends BaseAdapter {\n public override readonly displayName = 'OpenCode';\n\n public override readonly name = 'opencode' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'hooks',\n 'process-detect',\n ];\n\n private fallbackProcessSessionId: string | null = null;\n\n private readonly pollIntervalMs: number;\n\n private processPoller: NodeJS.Timeout | null = null;\n\n private readonly processListCommand: () => Promise<string>;\n\n public constructor(options: OpenCodeAdapterOptions) {\n super(options);\n this.pollIntervalMs = options.pollIntervalMs ?? 5_000;\n this.processListCommand =\n options.processListCommand ?? (async () => await execFile('pgrep', ['-lf', 'opencode']).then((result) => result.stdout));\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startProcessPolling();\n\n return Promise.resolve();\n }\n\n public override stop(): Promise<void> {\n if (this.processPoller !== null) {\n clearInterval(this.processPoller);\n this.processPoller = null;\n }\n\n this.fallbackProcessSessionId = null;\n this.setRunning(false);\n\n return Promise.resolve();\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalizedPayload = this.parseNormalizedHookPayload(payload);\n\n if (normalizedPayload !== null) {\n await this.emitNormalizedPayload({\n ...normalizedPayload,\n sessionId: resolveSessionId({\n activeFile: normalizedPayload.data?.activeFile,\n cwd: normalizedPayload.data?.cwd ?? normalizedPayload.cwd,\n pid: normalizedPayload.pid,\n project: normalizedPayload.data?.project,\n projectPath: normalizedPayload.data?.projectPath,\n sessionId: normalizedPayload.sessionId,\n tool: this.name,\n }),\n });\n return;\n }\n\n if (!isRecord(payload)) {\n logger.warn({ payload }, 'OpenCode payload must be an object');\n return;\n }\n\n const eventType = getString(payload, 'type');\n\n if (!eventType) {\n logger.warn({ payload }, 'OpenCode payload is missing its event type');\n return;\n }\n\n const sessionId = resolveSessionId({\n activeFile: extractOpenCodeActiveFile(payload),\n cwd: extractOpenCodeCwd(payload),\n pid: getNumber(payload, 'pid'),\n project: extractOpenCodeProject(payload),\n sessionId: extractOpenCodeSessionId(payload),\n tool: this.name,\n });\n const context: AdapterPublishContext = {\n cwd: extractOpenCodeCwd(payload),\n // ๐Ÿ“– Pass process.env so the context detector can detect the terminal\n env: this.env ?? process.env,\n hookPayload: payload,\n pid: getNumber(payload, 'pid'),\n sessionId,\n source: 'aisnitch://adapters/opencode',\n };\n const sharedData = {\n activeFile: extractOpenCodeActiveFile(payload),\n cwd: context.cwd,\n errorMessage: extractOpenCodeErrorMessage(payload),\n errorType: extractOpenCodeErrorType(payload),\n // ๐Ÿ“– Extract model from payload โ€” OpenCode may send it as \"model\" or nested in properties\n model: getString(payload, 'model') ?? getString(getRecord(payload.properties), 'model'),\n project: extractOpenCodeProject(payload),\n raw: payload,\n toolInput: extractOpenCodeToolInput(payload),\n toolName: extractOpenCodeToolName(payload),\n // ๐Ÿ“– Extract token usage from payload (with input/output/cached breakdown)\n ...(() => {\n const tokens = extractOpenCodeTokens(payload);\n return {\n tokensUsed: tokens.total,\n inputTokens: tokens.inputTokens,\n outputTokens: tokens.outputTokens,\n cachedTokens: tokens.cachedTokens,\n };\n })(),\n } satisfies Omit<EventData, 'state'>;\n\n switch (eventType) {\n case 'session.created': {\n this.fallbackProcessSessionId = null;\n await this.emitStateChange('session.start', sharedData, context);\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.deleted': {\n const finalMessage = extractOpenCodeFinalMessage(payload);\n await this.emitStateChange('session.end', {\n ...sharedData,\n finalMessage,\n }, context);\n return;\n }\n case 'session.error': {\n await this.emitStateChange('agent.error', sharedData, context);\n return;\n }\n case 'session.idle': {\n await this.emitStateChange('agent.idle', sharedData, context);\n return;\n }\n case 'session.compacted': {\n await this.emitStateChange('agent.compact', sharedData, context);\n return;\n }\n case 'thinking': {\n const thinkingContent = extractOpenCodeThinkingContent(payload);\n await this.emitStateChange('agent.thinking', {\n ...sharedData,\n thinkingContent,\n }, context);\n return;\n }\n case 'message.updated':\n case 'message.part.updated': {\n const messageContent = extractOpenCodeMessageContent(payload);\n await this.emitStateChange('agent.streaming', {\n ...sharedData,\n messageContent,\n }, context);\n return;\n }\n case 'permission.asked': {\n await this.emitStateChange('agent.asking_user', sharedData, context);\n return;\n }\n case 'tool.execute.before': {\n const toolCallName = extractOpenCodeToolName(payload);\n await this.emitStateChange('agent.tool_call', {\n ...sharedData,\n toolCallName,\n }, context);\n return;\n }\n case 'tool.execute.after': {\n const toolCallName = extractOpenCodeToolName(payload);\n const toolResult = extractOpenCodeToolResult(payload);\n const emittedType = isOpenCodeCodingTool(sharedData.toolName)\n ? 'agent.coding'\n : 'agent.tool_call';\n await this.emitStateChange(emittedType, {\n ...sharedData,\n toolCallName,\n toolResult,\n }, context);\n return;\n }\n default: {\n logger.debug({ eventType }, 'OpenCode event ignored by adapter');\n }\n }\n }\n\n private startProcessPolling(): void {\n if (this.pollIntervalMs <= 0) {\n return;\n }\n\n this.processPoller = setInterval(() => {\n void this.pollOpenCodeProcesses();\n }, this.pollIntervalMs);\n this.processPoller.unref();\n\n void this.pollOpenCodeProcesses();\n }\n\n private async pollOpenCodeProcesses(): Promise<void> {\n const processes = await listProcesses(this.processListCommand);\n\n if (processes.length > 0 && this.getStatus().activeSessions === 0) {\n const processInfo = processes[0];\n\n if (!processInfo) {\n return;\n }\n\n const sessionId = `opencode-process-${processInfo.pid}`;\n\n this.fallbackProcessSessionId = sessionId;\n await this.emitStateChange(\n 'session.start',\n {\n raw: {\n process: processInfo,\n source: 'process-detect',\n },\n },\n {\n pid: processInfo.pid,\n sessionId,\n source: 'aisnitch://adapters/opencode/process-detect',\n },\n );\n return;\n }\n\n if (processes.length === 0 && this.fallbackProcessSessionId !== null) {\n const sessionId = this.fallbackProcessSessionId;\n\n this.fallbackProcessSessionId = null;\n await this.emitStateChange(\n 'session.end',\n {\n raw: {\n reason: 'process-exit',\n source: 'process-detect',\n },\n },\n {\n sessionId,\n source: 'aisnitch://adapters/opencode/process-detect',\n },\n );\n }\n }\n}\n\nasync function listProcesses(\n listCommand: () => Promise<string>,\n): Promise<ProcessInfo[]> {\n if (process.platform === 'win32') {\n return [];\n }\n\n try {\n const stdout = await listCommand();\n\n return stdout\n .split(/\\r?\\n/u)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => {\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return null;\n }\n\n const pidText = match[1];\n const command = match[2];\n\n if (!pidText || !command) {\n return null;\n }\n\n return {\n command,\n pid: Number.parseInt(pidText, 10),\n } satisfies ProcessInfo;\n })\n .filter((processInfo): processInfo is ProcessInfo => processInfo !== null);\n } catch (error) {\n const errorCode =\n error instanceof Error && 'code' in error ? String(error.code) : '';\n\n if (\n error instanceof Error &&\n 'code' in error &&\n (errorCode === 'ENOENT' || errorCode === '1')\n ) {\n return [];\n }\n\n logger.debug({ error }, 'OpenCode process detection failed');\n return [];\n }\n}\n\nfunction extractOpenCodeSessionId(\n payload: Record<string, unknown>,\n): string | undefined {\n const directSessionId =\n getString(payload, 'sessionID') ??\n getString(payload, 'sessionId');\n\n if (directSessionId) {\n return directSessionId;\n }\n\n const properties = getRecord(payload.properties);\n\n return getString(properties, 'sessionID') ?? getString(properties, 'sessionId');\n}\n\nfunction extractOpenCodeCwd(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'cwd') ??\n getString(getRecord(payload.properties), 'cwd')\n );\n}\n\nfunction extractOpenCodeProject(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'project') ??\n getString(getRecord(payload.properties), 'project')\n );\n}\n\nfunction extractOpenCodeToolName(\n payload: Record<string, unknown>,\n): string | undefined {\n const tool = getRecord(payload.tool);\n\n return getString(tool, 'name') ?? getString(payload, 'tool');\n}\n\nfunction extractOpenCodeActiveFile(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(payload, 'file') ??\n getString(getRecord(payload.properties), 'file') ??\n extractOpenCodeToolInput(payload)?.filePath\n );\n}\n\nfunction extractOpenCodeToolInput(\n payload: Record<string, unknown>,\n): ToolInput | undefined {\n const args =\n getRecord(payload.args) ??\n getRecord(getRecord(payload.output)?.args) ??\n getRecord(getRecord(payload.properties)?.args);\n\n if (!args) {\n return undefined;\n }\n\n const command =\n getString(args, 'command') ??\n getString(args, 'cmd');\n const filePath =\n getString(args, 'filePath') ??\n getString(args, 'file_path') ??\n getString(args, 'path');\n\n if (!command && !filePath) {\n return undefined;\n }\n\n return {\n command,\n filePath,\n };\n}\n\nfunction extractOpenCodeErrorMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n return (\n getString(getRecord(payload.error), 'message') ??\n getString(payload, 'message')\n );\n}\n\nfunction extractOpenCodeErrorType(\n payload: Record<string, unknown>,\n): ErrorType | undefined {\n const rawType =\n getString(payload, 'errorType') ??\n getString(getRecord(payload.error), 'type');\n\n switch (rawType) {\n case 'rate_limit':\n return 'rate_limit';\n case 'context_overflow':\n return 'context_overflow';\n case 'tool_failure':\n return 'tool_failure';\n case 'api_error':\n case 'provider_error':\n return 'api_error';\n default:\n return undefined;\n }\n}\n\nfunction isOpenCodeCodingTool(toolName?: string): boolean {\n return toolName !== undefined && OPENCODE_CODING_TOOLS.has(toolName);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getNumber(\n payload: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = payload[key];\n\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value : undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the final/completion message from OpenCode payload.\n * This is the summary text shown at the end of an AI run.\n */\nfunction extractOpenCodeFinalMessage(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct final message fields\n const directMessage =\n getString(payload, 'final_message') ??\n getString(payload, 'finalMessage') ??\n getString(payload, 'summary') ??\n getString(payload, 'completion_message');\n\n if (directMessage) {\n return directMessage;\n }\n\n // From result or output fields\n const result =\n getString(payload, 'result') ??\n getString(payload, 'output') ??\n getString(getRecord(payload.properties), 'result');\n\n if (result) {\n return result;\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts the tool execution result from OpenCode payload.\n * Contains success messages, error outputs, or short tool results.\n */\nfunction extractOpenCodeToolResult(\n payload: Record<string, unknown>,\n): string | undefined {\n // Direct result field\n const directResult =\n getString(payload, 'result') ??\n getString(payload, 'output') ??\n getString(payload, 'toolResult');\n\n if (directResult) {\n return directResult;\n }\n\n // From tool_result object\n const toolResult = getRecord(payload.tool_result) ?? getRecord(payload.toolResult);\n if (toolResult) {\n return getString(toolResult, 'content') ?? getString(toolResult, 'output');\n }\n\n // From properties.toolResult\n const props = getRecord(payload.properties);\n if (props) {\n const nestedResult = getRecord(props.tool_result) ?? getRecord(props.toolResult);\n if (nestedResult) {\n return getString(nestedResult, 'content') ?? getString(nestedResult, 'output');\n }\n }\n\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts message/chat content from OpenCode payload.\n */\nfunction extractOpenCodeMessageContent(\n payload: Record<string, unknown>,\n): string | undefined {\n const directMessage =\n getString(payload, 'text') ??\n getString(payload, 'message') ??\n getString(payload, 'content') ??\n getString(payload, 'output');\n if (directMessage) {\n return directMessage;\n }\n const part = getRecord(payload.part) ?? getRecord(getRecord(payload.properties)?.part);\n if (part) {\n return getString(part, 'text') ?? getString(part, 'content');\n }\n const props = getRecord(payload.properties);\n if (props) {\n const message = getRecord(props.message) ?? getRecord(props.info);\n if (message) {\n return getString(message, 'text') ?? getString(message, 'content');\n }\n return getString(props, 'text') ?? getString(props, 'message');\n }\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts thinking/reasoning content from OpenCode payload.\n */\nfunction extractOpenCodeThinkingContent(\n payload: Record<string, unknown>,\n): string | undefined {\n const directThinking =\n getString(payload, 'thinking') ??\n getString(payload, 'thinkingContent') ??\n getString(payload, 'reasoning') ??\n getString(payload, 'thought');\n if (directThinking) {\n return directThinking;\n }\n const props = getRecord(payload.properties);\n if (props) {\n return getString(props, 'thinking') ?? getString(props, 'reasoning') ?? getString(props, 'thought');\n }\n return undefined;\n}\n\n/**\n * ๐Ÿ“– Extracts token usage from OpenCode payload.\n * OpenCode sends token info in properties.info.tokens:\n * { input: number, output: number, reasoning: number }\n */\ninterface OpenCodeTokens {\n total?: number;\n inputTokens?: number;\n outputTokens?: number;\n cachedTokens?: number;\n}\n\nfunction extractOpenCodeTokens(\n payload: Record<string, unknown>,\n): OpenCodeTokens {\n // Direct tokens field\n const directTokens = getNumber(payload, 'tokensUsed') ?? getNumber(payload, 'tokens');\n if (directTokens !== undefined) {\n return { total: directTokens };\n }\n\n // Nested in properties.info.tokens\n const props = getRecord(payload.properties);\n if (props) {\n const info = getRecord(props.info);\n if (info) {\n const tokens = getRecord(info.tokens);\n if (tokens) {\n const inputTokens = getNumber(tokens, 'input') ?? 0;\n const outputTokens = getNumber(tokens, 'output') ?? 0;\n const reasoningTokens = getNumber(tokens, 'reasoning') ?? 0;\n const total = inputTokens + outputTokens + reasoningTokens;\n return total > 0 ? {\n total,\n inputTokens,\n outputTokens,\n // reasoning tokens are often billed as cached on some providers\n cachedTokens: reasoningTokens,\n } : {};\n }\n }\n\n // Fallback: direct in properties\n const fallbackTokens = getNumber(props, 'tokensUsed') ?? getNumber(props, 'tokens');\n if (fallbackTokens !== undefined) {\n return { total: fallbackTokens };\n }\n }\n\n return {};\n}\n","/**\n * @file src/adapters/pi.ts\n * @description Pi AI Agent adapter using Pi's local API and log monitoring.\n * @functions\n * โ†’ detectPiInstance\n * @exports PiAdapter\n * @see ./base.ts\n * @see ../core/events/types.ts\n */\n\nimport { execFile } from 'node:child_process';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { logger } from '../core/engine/logger.js';\nimport type { AISnitchEventType, EventData } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\nconst execFileAsync = promisify(execFile);\n\ninterface PiActivity {\n sessionId: string;\n state: 'thinking' | 'tool' | 'idle' | 'output' | 'error';\n content?: string;\n toolName?: string;\n toolInput?: { filePath?: string; command?: string };\n model?: string;\n}\n\n/**\n * ๐Ÿ“– Pi is a coding agent by MiniMax. This adapter detects Pi activity through:\n * 1. Process detection (pgrep for pi processes)\n * 2. MiniMax API / local socket detection\n * 3. Log file monitoring\n */\nexport class PiAdapter extends BaseAdapter {\n public override readonly displayName = 'Pi (MiniMax)';\n\n public override readonly name = 'pi' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'api-client',\n 'log-watch',\n ];\n\n private readonly apiPort = 7890;\n\n private readonly logPath: string;\n\n private poller: NodeJS.Timeout | null = null;\n\n private activePiSessions: Map<string, PiActivity> = new Map();\n\n private lastCheckedTime: number = 0;\n\n public constructor(options: AdapterRuntimeOptions) {\n super(options);\n\n this.logPath = join(\n options.homeDirectory ?? process.env.HOME ?? '',\n '.pi',\n 'agent.log',\n );\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startPolling();\n\n logger.info({ adapter: this.name }, 'Pi adapter started');\n\n return Promise.resolve();\n }\n\n public override stop(): Promise<void> {\n if (this.poller !== null) {\n clearInterval(this.poller);\n this.poller = null;\n }\n\n this.setRunning(false);\n logger.info({ adapter: this.name }, 'Pi adapter stopped');\n\n return Promise.resolve();\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalized = this.parseNormalizedHookPayload(payload);\n\n if (normalized === null) {\n return;\n }\n\n const context: AdapterPublishContext = {\n cwd: normalized.cwd,\n pid: normalized.pid,\n sessionId: normalized.sessionId,\n source: 'pi-hook',\n };\n\n const eventType = this.mapEventType(normalized.type ?? '');\n const eventData = this.buildEventData(eventType, normalized);\n\n await this.emit(eventType, eventData, context);\n }\n\n private startPolling(): void {\n this.poller = setInterval(() => {\n void this.pollPiActivity();\n }, 2_000);\n }\n\n private async pollPiActivity(): Promise<void> {\n // Check for Pi processes\n const running = await this.detectPiInstance();\n\n if (!running) {\n // Pi not running, mark sessions as idle\n for (const [sessionId, activity] of this.activePiSessions) {\n if (activity.state !== 'idle') {\n activity.state = 'idle';\n await this.emitIdle(sessionId);\n }\n }\n return;\n }\n\n // Try Pi's local API\n try {\n const response = await fetch(\n `http://127.0.0.1:${this.apiPort}/api/status`,\n {\n signal: AbortSignal.timeout(500),\n },\n );\n\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n await this.processPiApiResponse(data);\n }\n } catch {\n // API not available, try MiniMax API\n await this.checkMiniMaxApi();\n }\n }\n\n private async detectPiInstance(): Promise<boolean> {\n try {\n // Check for Pi/MiniMax process\n const result = await execFileAsync('pgrep', ['-l', 'pi|minimax']);\n\n if (result.stdout.includes('pi') || result.stdout.includes('minimax')) {\n return true;\n }\n } catch {\n // No Pi process found\n }\n\n // Check for Pi socket or port\n try {\n const response = await fetch(\n `http://127.0.0.1:${this.apiPort}/health`,\n {\n signal: AbortSignal.timeout(200),\n },\n );\n\n if (response.ok) {\n return true;\n }\n } catch {\n // Pi not listening\n }\n\n return false;\n }\n\n private async checkMiniMaxApi(): Promise<void> {\n try {\n // Check MiniMax API for running sessions\n const response = await fetch('http://127.0.0.1:3000/api/agent/status', {\n signal: AbortSignal.timeout(500),\n });\n\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n await this.processPiApiResponse(data);\n }\n } catch {\n // MiniMax not running\n }\n }\n\n private async processPiApiResponse(\n data: Record<string, unknown>,\n ): Promise<void> {\n const rawSession = (data.sessionId ?? data.project ?? 'default') as string;\n const sessionId = `pi:${rawSession.replace(/[^a-zA-Z0-9-_]/g, '-')}`;\n\n let activity = this.activePiSessions.get(sessionId);\n\n if (!activity) {\n activity = { sessionId, state: 'idle' };\n this.activePiSessions.set(sessionId, activity);\n await this.emitSessionStart(sessionId, data);\n }\n\n const rawState = (data.state ?? 'idle') as string;\n const state = rawState as PiActivity['state'];\n\n if (state !== activity.state) {\n switch (state) {\n case 'thinking': {\n const rawThinking = data.thinking as string | undefined;\n if (rawThinking) {\n await this.emitThinking(sessionId, rawThinking);\n }\n break;\n }\n case 'tool': {\n const rawFilePath = data.filePath as string | undefined;\n const rawCommand = data.command as string | undefined;\n const rawToolName = (data.toolName as string | undefined) ?? 'unknown';\n await this.emitToolCall(\n sessionId,\n {\n filePath: rawFilePath ?? '',\n command: rawCommand ?? '',\n },\n rawToolName,\n );\n break;\n }\n case 'output': {\n const rawOutput = data.output as string | undefined;\n if (rawOutput) {\n await this.emitOutput(sessionId, rawOutput);\n }\n break;\n }\n case 'error': {\n const rawError = (data.error as string | undefined) ?? 'Unknown error';\n await this.emitError(sessionId, rawError);\n break;\n }\n case 'idle':\n await this.emitIdle(sessionId);\n break;\n }\n\n activity.state = state;\n }\n }\n\n private async emitSessionStart(\n sessionId: string,\n data: Record<string, unknown>,\n ): Promise<void> {\n const rawProject = (data.project as string | undefined) ?? 'pi-project';\n const rawModel = (data.model as string | undefined) ?? 'minimax/moonshot';\n const eventData: EventData = {\n state: 'session.start',\n project: rawProject,\n model: rawModel,\n raw: data,\n };\n\n await this.emit('session.start', eventData, { sessionId });\n }\n\n private async emitThinking(sessionId: string, content: string): Promise<void> {\n if (!content) return;\n\n const eventData: EventData = {\n state: 'agent.thinking',\n thinkingContent: content,\n };\n\n await this.emit('agent.thinking', eventData, { sessionId });\n }\n\n private async emitToolCall(\n sessionId: string,\n toolInput: { filePath?: string; command?: string },\n toolName: string,\n ): Promise<void> {\n const eventData: EventData = {\n state: 'agent.tool_call',\n toolCallName: toolName,\n toolInput,\n activeFile: toolInput.filePath,\n };\n\n await this.emit('agent.tool_call', eventData, { sessionId });\n }\n\n private async emitOutput(sessionId: string, content: string): Promise<void> {\n if (!content) return;\n\n const eventData: EventData = {\n state: 'agent.streaming',\n messageContent: content,\n };\n\n await this.emit('agent.streaming', eventData, { sessionId });\n }\n\n private async emitError(sessionId: string, errorMessage: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.error',\n errorMessage,\n errorType: 'api_error',\n };\n\n await this.emit('agent.error', eventData, { sessionId });\n }\n\n private async emitIdle(sessionId: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.idle',\n };\n\n await this.emit('agent.idle', eventData, { sessionId });\n }\n\n private mapEventType(type: string): AISnitchEventType {\n const mapping: Record<string, AISnitchEventType> = {\n 'session.start': 'session.start',\n 'session.end': 'session.end',\n 'task.start': 'task.start',\n 'task.complete': 'task.complete',\n thinking: 'agent.thinking',\n tool: 'agent.tool_call',\n coding: 'agent.coding',\n output: 'agent.streaming',\n message: 'agent.streaming',\n ask: 'agent.asking_user',\n error: 'agent.error',\n idle: 'agent.idle',\n compact: 'agent.compact',\n };\n\n return mapping[type] ?? 'agent.streaming';\n }\n\n private buildEventData(\n eventType: AISnitchEventType,\n payload: Record<string, unknown>,\n ): EventData {\n const data = (payload.data ?? {}) as Partial<EventData>;\n\n return {\n state: eventType,\n project: data.project,\n activeFile: data.activeFile,\n model: data.model,\n toolInput: data.toolInput,\n toolCallName: data.toolCallName,\n thinkingContent: data.thinkingContent,\n messageContent: data.messageContent,\n finalMessage: data.finalMessage,\n toolResult: data.toolResult,\n errorMessage: data.errorMessage,\n errorType: data.errorType,\n raw: data.raw,\n };\n }\n}\n","/**\n * @file src/adapters/zed.ts\n * @description Zed AI Agent adapter using log file monitoring and IPC detection.\n * @functions\n * โ†’ extractZedEventFromLog\n * @exports ZedAdapter\n * @see ./base.ts\n * @see ../core/events/types.ts\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\n\nimport { logger } from '../core/engine/logger.js';\nimport type { AISnitchEventType, EventData, ToolInput } from '../core/events/types.js';\nimport {\n type AdapterPublishContext,\n type AdapterRuntimeOptions,\n BaseAdapter,\n type InterceptionStrategy,\n} from './base.js';\n\n/**\n * ๐Ÿ“– Zed Agent (zed.dev) exposes a local HTTP API on port 9876 for its agent.\n * This adapter polls that endpoint and watches Zed's log file for activity.\n */\nexport class ZedAdapter extends BaseAdapter {\n public override readonly displayName = 'Zed AI';\n\n public override readonly name = 'zed' as const;\n\n public override readonly strategies: readonly InterceptionStrategy[] = [\n 'process-detect',\n 'api-client',\n ];\n\n private readonly logPaths: readonly string[];\n\n private readonly apiPort = 9876;\n\n private readonly pollIntervalMs: number;\n\n private poller: NodeJS.Timeout | null = null;\n\n private lastEventTime: number = 0;\n\n private activeZedSessions: Map<string, string> = new Map();\n\n public constructor(options: AdapterRuntimeOptions) {\n super(options);\n\n this.pollIntervalMs = 2_000;\n this.logPaths = [\n join(options.homeDirectory ?? process.env.HOME ?? '', '.config', 'zed', 'logs', 'agent.log'),\n '/tmp/zed-agent.log',\n ];\n }\n\n public override start(): Promise<void> {\n if (this.getStatus().running) {\n return Promise.resolve();\n }\n\n this.setRunning(true);\n this.startPolling();\n\n logger.info({ adapter: this.name }, 'Zed adapter started');\n\n return Promise.resolve();\n }\n\n public override stop(): Promise<void> {\n if (this.poller !== null) {\n clearInterval(this.poller);\n this.poller = null;\n }\n\n this.setRunning(false);\n logger.info({ adapter: this.name }, 'Zed adapter stopped');\n\n return Promise.resolve();\n }\n\n public override async handleHook(payload: unknown): Promise<void> {\n const normalized = this.parseNormalizedHookPayload(payload);\n\n if (normalized === null) {\n return;\n }\n\n const context: AdapterPublishContext = {\n cwd: normalized.cwd,\n pid: normalized.pid,\n sessionId: normalized.sessionId,\n source: 'zed-hook',\n };\n\n const eventType = this.mapEventType(normalized.type ?? '');\n const eventData = this.buildEventData(eventType, normalized);\n\n await this.emit(eventType, eventData, context);\n }\n\n private startPolling(): void {\n this.poller = setInterval(() => {\n void this.pollZedStatus();\n }, this.pollIntervalMs);\n }\n\n private async pollZedStatus(): Promise<void> {\n try {\n // Try Zed's agent API\n const response = await fetch(`http://127.0.0.1:${this.apiPort}/api/agent/status`, {\n signal: AbortSignal.timeout(1_000),\n });\n\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n\n if (data.sessionId && typeof data.sessionId === 'string') {\n const sessionId = `zed:${data.sessionId}`;\n\n if (!this.activeZedSessions.has(sessionId)) {\n this.activeZedSessions.set(sessionId, sessionId);\n await this.emitSessionStart(sessionId, data);\n }\n\n if (data.state === 'thinking' && this.lastEventTime < Date.now() - 5_000) {\n const rawThinking = data.thinking as string | undefined;\n if (rawThinking) {\n await this.emitThinking(sessionId, rawThinking);\n }\n } else if (data.state === 'tool' && data.toolName) {\n const rawFilePath = data.filePath as string | undefined;\n const rawCommand = data.command as string | undefined;\n const rawToolName = (data.toolName as string | undefined) ?? 'unknown';\n await this.emitToolCall(\n sessionId,\n {\n filePath: rawFilePath ?? '',\n command: rawCommand ?? '',\n },\n rawToolName,\n );\n } else if (data.state === 'idle') {\n await this.emitIdle(sessionId);\n }\n }\n }\n } catch {\n // Zed agent not running or API not available - fall through to log parsing\n await this.checkLogFiles();\n }\n }\n\n private async checkLogFiles(): Promise<void> {\n for (const logPath of this.logPaths) {\n try {\n const content = await readFile(logPath, 'utf8');\n await this.parseLogContent(content);\n } catch {\n // Log file doesn't exist yet\n }\n }\n }\n\n private async parseLogContent(content: string): Promise<void> {\n const lines = content.split('\\n').filter((line) => line.trim());\n\n for (const line of lines) {\n if (this.lastEventTime > 0 && this.lastEventTime >= Date.now() - 2_000) {\n continue;\n }\n\n const event = this.extractZedEventFromLog(line);\n if (event) {\n await this.handleHook(event);\n this.lastEventTime = Date.now();\n }\n }\n }\n\n private extractZedEventFromLog(\n line: string,\n ): Record<string, unknown> | null {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n\n if (!parsed.type || typeof parsed.type !== 'string') {\n return null;\n }\n\n const rawSessionId = parsed.sessionId as string | undefined;\n const rawWorkspace = parsed.workspace as string | undefined;\n const sessionId = rawSessionId\n ? rawSessionId\n : rawWorkspace\n ? `zed:${basename(rawWorkspace)}`\n : `zed:${Date.now()}`;\n\n const rawCwd = (parsed.cwd ?? rawWorkspace) as string | undefined;\n\n return {\n type: parsed.type,\n sessionId,\n cwd: rawCwd,\n data: {\n project: parsed.project ?? rawWorkspace ? basename(String(rawWorkspace)) : undefined,\n model: parsed.model,\n state: parsed.type,\n thinkingContent: parsed.thinking,\n toolCallName: parsed.toolName,\n toolInput: parsed.toolInput,\n messageContent: parsed.message ?? parsed.output,\n errorMessage: parsed.error,\n raw: parsed,\n },\n };\n } catch {\n // Not JSON - try pattern matching for plain text logs\n if (line.includes('[zed:agent]')) {\n const cleaned = line.replace(/^\\[.*?\\] \\[.*?\\] /, '');\n\n if (cleaned.includes('Thinking:')) {\n return { type: 'thinking', thinkingContent: cleaned.replace('Thinking:', '').trim() };\n }\n if (cleaned.includes('Executing tool:')) {\n return { type: 'tool', toolCallName: cleaned.replace('Executing tool:', '').trim() };\n }\n if (cleaned.includes('Error:')) {\n return { type: 'error', errorMessage: cleaned.replace('Error:', '').trim() };\n }\n }\n\n return null;\n }\n }\n\n private async emitSessionStart(sessionId: string, _data: Record<string, unknown>): Promise<void> {\n const eventData: EventData = {\n state: 'session.start',\n project: sessionId.split(':')[1] ?? 'unknown',\n };\n\n await this.emit('session.start', eventData, { sessionId });\n }\n\n private async emitThinking(sessionId: string, content: string): Promise<void> {\n if (!content) return;\n\n const eventData: EventData = {\n state: 'agent.thinking',\n thinkingContent: content,\n };\n\n await this.emit('agent.thinking', eventData, { sessionId });\n this.lastEventTime = Date.now();\n }\n\n private async emitToolCall(sessionId: string, toolInput: ToolInput, toolName: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.tool_call',\n toolCallName: toolName,\n toolInput,\n activeFile: toolInput.filePath,\n };\n\n await this.emit('agent.tool_call', eventData, { sessionId });\n this.lastEventTime = Date.now();\n }\n\n private async emitIdle(sessionId: string): Promise<void> {\n const eventData: EventData = {\n state: 'agent.idle',\n };\n\n await this.emit('agent.idle', eventData, { sessionId });\n }\n\n private mapEventType(type: string): AISnitchEventType {\n const mapping: Record<string, AISnitchEventType> = {\n 'session.start': 'session.start',\n 'session.end': 'session.end',\n 'task.start': 'task.start',\n 'task.complete': 'task.complete',\n thinking: 'agent.thinking',\n tool: 'agent.tool_call',\n coding: 'agent.coding',\n output: 'agent.streaming',\n message: 'agent.streaming',\n ask: 'agent.asking_user',\n error: 'agent.error',\n idle: 'agent.idle',\n compact: 'agent.compact',\n };\n\n return mapping[type] ?? 'agent.streaming';\n }\n\n private buildEventData(\n eventType: AISnitchEventType,\n payload: Record<string, unknown>,\n ): EventData {\n const data = (payload.data ?? {}) as Partial<EventData>;\n\n return {\n state: eventType,\n project: data.project,\n activeFile: data.activeFile,\n model: data.model,\n toolInput: data.toolInput,\n toolCallName: data.toolCallName,\n thinkingContent: data.thinkingContent,\n messageContent: data.messageContent,\n finalMessage: data.finalMessage,\n toolResult: data.toolResult,\n errorMessage: data.errorMessage,\n errorType: data.errorType,\n raw: data.raw,\n };\n }\n}\n","import type { AISnitchConfig } from '../core/config/schema.js';\nimport type { ToolName } from '../core/events/types.js';\nimport type { AdapterStatus, BaseAdapter } from './base.js';\n\nimport { logger } from '../core/engine/logger.js';\n\n/**\n * @file src/adapters/registry.ts\n * @description Adapter registry that owns built-in adapter instances and orchestrates their lifecycle.\n * @functions\n * โ†’ none\n * @exports AdapterRegistry\n * @see ./base.ts\n * @see ./index.ts\n */\n\n/**\n * ๐Ÿ“– The registry is intentionally tiny: one place to register adapters, one\n * place to start/stop them, and one place to ask what is alive right now.\n */\nexport class AdapterRegistry {\n private readonly adapters = new Map<ToolName, BaseAdapter>();\n\n /**\n * Registers one built-in or community adapter instance.\n */\n public register(adapter: BaseAdapter): void {\n if (this.adapters.has(adapter.name)) {\n throw new Error(`Adapter \"${adapter.name}\" is already registered.`);\n }\n\n this.adapters.set(adapter.name, adapter);\n }\n\n /**\n * Returns one adapter instance by its tool name.\n */\n public get(toolName: ToolName): BaseAdapter | undefined {\n return this.adapters.get(toolName);\n }\n\n /**\n * Lists every registered adapter.\n */\n public list(): BaseAdapter[] {\n return [...this.adapters.values()];\n }\n\n /**\n * Returns one status snapshot per registered adapter.\n */\n public getStatus(): AdapterStatus[] {\n return this.list().map((adapter) => adapter.getStatus());\n }\n\n /**\n * Starts every adapter enabled in the current AISnitch config.\n * ๐Ÿ“– Each adapter is started independently โ€” one failure does not prevent\n * the others from starting.\n */\n public async startAll(config: AISnitchConfig): Promise<void> {\n for (const adapter of this.list()) {\n if (config.adapters[adapter.name]?.enabled !== true) {\n continue;\n }\n\n try {\n await adapter.start();\n } catch (error: unknown) {\n logger.error(\n { error, adapter: adapter.name },\n `๐Ÿ“– Failed to start adapter \"${adapter.name}\" โ€” skipping`,\n );\n }\n }\n }\n\n /**\n * Stops every adapter in reverse registration order.\n * ๐Ÿ“– Each adapter is stopped independently โ€” one failure does not prevent\n * the others from being stopped.\n */\n public async stopAll(): Promise<void> {\n const adapters = this.list().reverse();\n\n for (const adapter of adapters) {\n try {\n await adapter.stop();\n } catch (error: unknown) {\n logger.warn(\n { error, adapter: adapter.name },\n `๐Ÿ“– Error stopping adapter \"${adapter.name}\" โ€” continuing`,\n );\n }\n }\n }\n}\n","import { basename } from 'node:path';\n\nimport { spawn as spawnPty, type IPty } from '@lydell/node-pty';\nimport stripAnsi from 'strip-ansi';\n\nimport { createEvent } from '../core/events/factory.js';\nimport type {\n AISnitchEvent,\n AISnitchEventType,\n ErrorType,\n EventData,\n ToolName,\n} from '../core/events/types.js';\nimport { ContextDetector } from '../core/engine/context-detector.js';\nimport { resolveSessionId } from '../core/session-identity.js';\n\n/**\n * @file src/adapters/generic-pty.ts\n * @description Generic PTY wrapper used by `aisnitch wrap` to observe interactive tools without first-class adapters.\n * @functions\n * โ†’ analyzeTerminalOutputChunk\n * @exports GenericPTYSession, GenericPTYSessionOptions, GenericPTYObservation, analyzeTerminalOutputChunk\n * @see ../cli/runtime.ts\n * @see ../../tasks/06-adapters-secondary/03_adapters-secondary_aider-pty_DONE.md\n */\n\nconst PTY_ERROR_HINT = /error|exception|failed|traceback|refused|denied/iu;\nconst PTY_ASKING_USER_HINT =\n /\\b\\(Y(?:es)?\\/N(?:o)?\\)|\\bPress Enter\\b|\\bcontinue\\?\\b|\\bselect\\b|\\bchoose\\b|\\bapprove\\b/iu;\nconst PTY_THINKING_HINT =\n /thinking|analyzing|planning|reasoning|reflecting|compacting|summarizing/iu;\nconst PTY_CODING_HINT =\n /apply_patch|creating|deleting|editing|patch|renaming|replacing|search\\/replace|updating|writing|<<<<<<<|>>>>>>>|diff --git/iu;\nconst PTY_SPINNER_FRAME_HINT = /[|/\\\\-]|[โ ‹โ ™โ นโ ธโ ผโ ดโ ฆโ งโ ‡โ ]/u;\n\nexport interface GenericPTYSessionOptions {\n readonly args: readonly string[];\n readonly command: string;\n readonly cwd: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly publishEvent: (\n event: AISnitchEvent,\n context?: {\n readonly cwd?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly pid?: number;\n },\n ) => Promise<boolean>;\n readonly rows?: number;\n readonly cols?: number;\n readonly stdin?: NodeJS.ReadStream;\n readonly stdout?: NodeJS.WriteStream;\n}\n\nexport interface GenericPTYObservation {\n readonly fingerprint: string;\n readonly type: AISnitchEventType;\n readonly data: Omit<EventData, 'state'>;\n}\n\n/**\n * ๐Ÿ“– The wrapper deliberately uses heuristics instead of pretending it has a\n * stable protocol. Its job is to recover useful live signals from messy ANSI.\n */\nexport class GenericPTYSession {\n private readonly args: readonly string[];\n\n private readonly cols: number;\n\n private readonly command: string;\n\n private readonly commandLine: string;\n\n private readonly contextDetector = new ContextDetector();\n\n private readonly cwd: string;\n\n private readonly env: NodeJS.ProcessEnv;\n\n private lastObservationFingerprint: string | null = null;\n\n private readonly publishEvent: GenericPTYSessionOptions['publishEvent'];\n\n private readonly rows: number;\n\n private sequenceNumber = 0;\n\n private readonly stdin: NodeJS.ReadStream;\n\n private readonly stdout: NodeJS.WriteStream;\n\n private readonly tool: ToolName;\n\n private userInputBuffer = '';\n\n public constructor(options: GenericPTYSessionOptions) {\n this.args = options.args;\n this.command = options.command;\n this.commandLine = [options.command, ...options.args].join(' ').trim();\n this.cols = options.cols ?? process.stdout.columns ?? 120;\n this.cwd = options.cwd;\n this.env = {\n ...process.env,\n ...options.env,\n };\n this.publishEvent = options.publishEvent;\n this.rows = options.rows ?? process.stdout.rows ?? 32;\n this.stdin = options.stdin ?? process.stdin;\n this.stdout = options.stdout ?? process.stdout;\n this.tool = inferWrappedToolName(options.command, options.args);\n }\n\n /**\n * Launches the wrapped PTY session and resolves with the wrapped exit code.\n */\n public async run(): Promise<number> {\n const pty = spawnPty(this.command, [...this.args], {\n cols: this.cols,\n cwd: this.cwd,\n env: normalizePtyEnvironment(this.env),\n rows: this.rows,\n });\n const sessionId = resolveSessionId({\n cwd: this.cwd,\n pid: pty.pid,\n tool: this.tool,\n });\n const terminal = this.contextDetector.detectTerminal(this.env);\n\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'session.start',\n {\n cwd: this.cwd,\n pid: pty.pid,\n project: basename(this.cwd) || this.cwd,\n projectPath: this.cwd,\n raw: {\n args: this.args,\n command: this.command,\n source: 'pty-wrap',\n },\n terminal,\n toolInput: {\n command: this.commandLine,\n },\n toolName: basename(this.command) || this.command,\n },\n );\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'task.start',\n {\n cwd: this.cwd,\n pid: pty.pid,\n project: basename(this.cwd) || this.cwd,\n projectPath: this.cwd,\n raw: {\n args: this.args,\n command: this.command,\n source: 'pty-wrap',\n },\n terminal,\n toolInput: {\n command: this.commandLine,\n },\n },\n );\n\n return await new Promise<number>((resolve) => {\n let settled = false;\n let exitPoller: NodeJS.Timeout | null = null;\n const finalize = (exitCode: number, signal?: number) => {\n if (settled) {\n return;\n }\n\n settled = true;\n if (exitPoller !== null) {\n clearInterval(exitPoller);\n }\n void this.handleExit(pty, sessionId, terminal, exitCode, signal).finally(() => {\n inputCleanup();\n resizeCleanup();\n signalCleanup();\n dataDisposable.dispose();\n exitDisposable.dispose();\n resolve(exitCode);\n });\n };\n const dataDisposable = pty.onData((chunk: string) => {\n this.stdout.write(chunk);\n void this.handleOutputChunk(pty, sessionId, terminal, chunk);\n });\n const exitDisposable = pty.onExit(\n ({ exitCode, signal }: { exitCode: number; signal?: number }) => {\n finalize(exitCode, signal);\n },\n );\n exitPoller = setInterval(() => {\n if (!isPidRunning(pty.pid)) {\n finalize(0);\n }\n }, 200);\n exitPoller.unref();\n const inputCleanup = this.attachStdin(pty, sessionId, terminal);\n const resizeCleanup = this.attachResize(pty);\n const signalCleanup = this.attachParentSignals(pty);\n });\n }\n\n private attachParentSignals(pty: IPty): () => void {\n const handleSigterm = () => {\n pty.kill('SIGTERM');\n };\n const handleSigint = () => {\n pty.kill('SIGINT');\n };\n\n process.on('SIGTERM', handleSigterm);\n process.on('SIGINT', handleSigint);\n\n return () => {\n process.off('SIGTERM', handleSigterm);\n process.off('SIGINT', handleSigint);\n };\n }\n\n private attachResize(pty: IPty): () => void {\n if (!this.stdout.isTTY) {\n return () => undefined;\n }\n\n const handleResize = () => {\n pty.resize(process.stdout.columns ?? this.cols, process.stdout.rows ?? this.rows);\n };\n\n this.stdout.on('resize', handleResize);\n\n return () => {\n this.stdout.off('resize', handleResize);\n };\n }\n\n private attachStdin(\n pty: IPty,\n sessionId: string,\n terminal: string,\n ): () => void {\n const input = this.stdin;\n\n if (!input.isTTY) {\n return () => undefined;\n }\n\n const handleInput = (chunk: Buffer) => {\n pty.write(chunk);\n void this.captureUserInput(pty, sessionId, terminal, chunk.toString('utf8'));\n };\n\n input.resume();\n input.setRawMode?.(true);\n input.on('data', handleInput);\n\n return () => {\n input.off('data', handleInput);\n input.setRawMode?.(false);\n void this.flushUserInput(sessionId, pty.pid, terminal);\n };\n }\n\n private async captureUserInput(\n pty: IPty,\n sessionId: string,\n terminal: string,\n chunk: string,\n ): Promise<void> {\n const sanitizedChunk = stripTerminalControlCharacters(chunk);\n\n if (sanitizedChunk.includes('\\r') || sanitizedChunk.includes('\\n')) {\n await this.flushUserInput(sessionId, pty.pid, terminal);\n return;\n }\n\n const printableChunk = sanitizedChunk.trim();\n\n if (printableChunk.length === 0) {\n return;\n }\n\n this.userInputBuffer = `${this.userInputBuffer}${printableChunk}`;\n\n if (this.userInputBuffer.length >= 120) {\n await this.flushUserInput(sessionId, pty.pid, terminal);\n }\n }\n\n private async flushUserInput(\n sessionId: string,\n pid: number,\n terminal: string,\n ): Promise<void> {\n const input = this.userInputBuffer.trim();\n\n if (input.length === 0) {\n this.userInputBuffer = '';\n return;\n }\n\n this.userInputBuffer = '';\n\n await this.emitEvent(\n pid,\n sessionId,\n 'agent.asking_user',\n {\n cwd: this.cwd,\n pid,\n raw: {\n input,\n source: 'pty-stdin',\n },\n terminal,\n },\n );\n }\n\n private async handleOutputChunk(\n pty: IPty,\n sessionId: string,\n terminal: string,\n chunk: string,\n ): Promise<void> {\n const observation = analyzeTerminalOutputChunk({\n chunk,\n commandLine: this.commandLine,\n tool: this.tool,\n });\n\n if (!observation) {\n return;\n }\n\n if (this.lastObservationFingerprint === observation.fingerprint) {\n return;\n }\n\n this.lastObservationFingerprint = observation.fingerprint;\n await this.emitEvent(pty.pid, sessionId, observation.type, {\n cwd: this.cwd,\n pid: pty.pid,\n project: basename(this.cwd) || this.cwd,\n projectPath: this.cwd,\n terminal,\n ...observation.data,\n });\n }\n\n private async handleExit(\n pty: IPty,\n sessionId: string,\n terminal: string,\n exitCode: number,\n signal: number | undefined,\n ): Promise<void> {\n await this.flushUserInput(sessionId, pty.pid, terminal);\n\n if (exitCode !== 0) {\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'agent.error',\n {\n cwd: this.cwd,\n errorMessage: `Wrapped process exited with code ${exitCode}.`,\n errorType: 'tool_failure',\n pid: pty.pid,\n raw: {\n exitCode,\n signal,\n source: 'pty-wrap',\n },\n terminal,\n },\n );\n }\n\n await this.emitEvent(\n pty.pid,\n sessionId,\n 'session.end',\n {\n cwd: this.cwd,\n pid: pty.pid,\n raw: {\n exitCode,\n signal,\n source: 'pty-wrap',\n },\n terminal,\n },\n );\n }\n\n private async emitEvent(\n pid: number,\n sessionId: string,\n type: AISnitchEventType,\n data: Omit<EventData, 'state'>,\n ): Promise<void> {\n this.sequenceNumber += 1;\n\n await this.publishEvent(\n createEvent({\n source: `aisnitch://adapters/${this.tool}/pty-wrap`,\n type,\n 'aisnitch.tool': this.tool,\n 'aisnitch.sessionid': sessionId,\n 'aisnitch.seqnum': this.sequenceNumber,\n data,\n }),\n {\n cwd: this.cwd,\n env: this.env,\n pid,\n },\n );\n }\n}\n\n/**\n * Interprets one PTY chunk into the best-effort AISnitch activity state.\n */\nexport function analyzeTerminalOutputChunk(input: {\n readonly chunk: string;\n readonly commandLine: string;\n readonly tool: ToolName;\n}): GenericPTYObservation | null {\n const strippedText = stripAnsi(input.chunk)\n .replaceAll('\\u0007', '');\n const normalizedText = stripTerminalControlCharacters(strippedText)\n .replaceAll('\\r', '\\n')\n .trim();\n\n if (normalizedText.length === 0) {\n return null;\n }\n\n const activeFile = extractPathReference(normalizedText);\n const raw = {\n chunk: input.chunk,\n output: normalizedText,\n source: 'pty-wrap',\n } satisfies Record<string, unknown>;\n\n if (containsRedAnsi(input.chunk) || PTY_ERROR_HINT.test(normalizedText)) {\n return {\n data: {\n activeFile,\n errorMessage: normalizedText,\n errorType: classifyPtyErrorType(normalizedText),\n raw,\n },\n fingerprint: createPtyFingerprint('agent.error', normalizedText, activeFile),\n type: 'agent.error',\n };\n }\n\n if (PTY_ASKING_USER_HINT.test(normalizedText)) {\n return {\n data: {\n activeFile,\n raw,\n },\n fingerprint: createPtyFingerprint(\n 'agent.asking_user',\n normalizedText,\n activeFile,\n ),\n type: 'agent.asking_user',\n };\n }\n\n if (\n PTY_CODING_HINT.test(normalizedText) ||\n (activeFile !== undefined && /\\.(?:[cm]?[jt]sx?|json|md|py|rb|rs|sh|ya?ml)$/u.test(activeFile))\n ) {\n return {\n data: {\n activeFile,\n raw,\n toolInput: activeFile\n ? {\n filePath: activeFile,\n }\n : {\n command: input.commandLine,\n },\n toolName: activeFile ? 'file-edit' : basename(input.commandLine) || 'shell',\n },\n fingerprint: createPtyFingerprint('agent.coding', normalizedText, activeFile),\n type: 'agent.coding',\n };\n }\n\n if (containsSpinnerHint(input.chunk) || PTY_THINKING_HINT.test(normalizedText)) {\n return {\n data: {\n raw,\n },\n fingerprint: createPtyFingerprint('agent.thinking', normalizedText, activeFile),\n type: 'agent.thinking',\n };\n }\n\n return {\n data: {\n activeFile,\n raw,\n },\n fingerprint: createPtyFingerprint('agent.streaming', normalizedText, activeFile),\n type: 'agent.streaming',\n };\n}\n\nfunction normalizePtyEnvironment(\n env: NodeJS.ProcessEnv,\n): Record<string, string | undefined> {\n return Object.fromEntries(\n Object.entries(env).map(([key, value]) => [key, value]),\n );\n}\n\nfunction inferWrappedToolName(\n command: string,\n args: readonly string[],\n): ToolName {\n const commandBaseName = basename(command).toLowerCase();\n const fullCommandLine = [commandBaseName, ...args].join(' ').toLowerCase();\n const toolMatchers: readonly [ToolName, RegExp][] = [\n ['aider', /\\baider\\b/u],\n ['amp', /\\bamp\\b/u],\n ['claude-code', /\\bclaude\\b/u],\n ['copilot-cli', /\\bcopilot\\b/u],\n ['codex', /\\bcodex\\b/u],\n ['continue', /\\bcontinue\\b/u],\n ['cursor', /\\bcursor\\b/u],\n ['gemini-cli', /\\bgemini\\b/u],\n ['goose', /\\bgoose\\b/u],\n ['kilo', /\\bkilo\\b/u],\n ['openclaw', /\\bopenclaw\\b/u],\n ['opencode', /\\bopencode\\b/u],\n ['openhands', /\\bopenhands\\b/u],\n ['qwen-code', /\\bqwen\\b/u],\n ['windsurf', /\\bwindsurf\\b/u],\n ];\n\n for (const [toolName, matcher] of toolMatchers) {\n if (matcher.test(fullCommandLine)) {\n return toolName;\n }\n }\n\n return 'unknown';\n}\n\nfunction extractPathReference(text: string): string | undefined {\n const pathMatch = text.match(\n /(?:^|[\\s'\"])((?:\\.{0,2}\\/|\\/)?[A-Za-z0-9._/-]+\\.[A-Za-z0-9._-]+)(?=$|[\\s'\":,)])/u,\n );\n\n return pathMatch?.[1];\n}\n\nfunction classifyPtyErrorType(message: string): ErrorType {\n if (/rate limit|quota|too many requests/iu.test(message)) {\n return 'rate_limit';\n }\n\n if (/context|token limit|context window/iu.test(message)) {\n return 'context_overflow';\n }\n\n if (/write|edit|patch|apply|command failed|exit code/iu.test(message)) {\n return 'tool_failure';\n }\n\n return 'api_error';\n}\n\nfunction createPtyFingerprint(\n type: AISnitchEventType,\n text: string,\n activeFile?: string,\n): string {\n return [type, activeFile ?? '', text.replace(/\\s+/gu, ' ').slice(0, 240)].join(\n '::',\n );\n}\n\nfunction stripTerminalControlCharacters(value: string): string {\n return [...value]\n .filter((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n\n return !(\n (codePoint >= 0x00 && codePoint <= 0x08) ||\n (codePoint >= 0x0b && codePoint <= 0x1a) ||\n (codePoint >= 0x1c && codePoint <= 0x1f) ||\n codePoint === 0x7f\n );\n })\n .join('');\n}\n\nfunction containsRedAnsi(value: string): boolean {\n return (\n value.includes('\\u001B[31m') ||\n value.includes('\\u001B[0;31m') ||\n value.includes('\\u001B[91m')\n );\n}\n\nfunction containsSpinnerHint(value: string): boolean {\n return (\n (value.includes('\\r') || value.includes('\\u0008')) &&\n PTY_SPINNER_FRAME_HINT.test(value)\n );\n}\n\nfunction isPidRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n (error.code === 'ESRCH' || error.code === 'ENOENT')\n ) {\n return false;\n }\n\n return true;\n }\n}\n","import { execFile as execFileCallback } from 'node:child_process';\nimport { basename } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport pidCwd from 'pid-cwd';\n\nimport type { AISnitchEvent, ToolName } from '../events/types.js';\nimport { logger } from './logger.js';\n\nconst execFile = promisify(execFileCallback);\n\n/**\n * @file src/core/engine/context-detector.ts\n * @description Best-effort runtime context enrichment for terminal, cwd, pid, and instance metadata.\n * @functions\n * โ†’ none\n * @exports ProcessInfo, ProcessContext, EnrichedContextFields, ContextDetector\n * @see ../events/schema.ts\n */\n\n/**\n * Lightweight process metadata used during instance enumeration.\n */\nexport interface ProcessInfo {\n readonly pid: number;\n readonly cwd?: string;\n}\n\n/**\n * Context captured from a tool process, transcript path, or hook payload.\n */\nexport interface ProcessContext {\n readonly pid?: number;\n readonly env?: NodeJS.ProcessEnv;\n readonly sessionId?: string;\n readonly transcriptPath?: string;\n readonly hookPayload?: Record<string, unknown>;\n}\n\n/**\n * Context fields that AISnitch attaches into `event.data`.\n */\nexport interface EnrichedContextFields {\n readonly terminal?: string;\n readonly cwd?: string;\n readonly pid?: number;\n readonly instanceId?: string;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n}\n\ninterface CachedProcessContext {\n readonly terminal?: string;\n readonly cwd?: string;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n readonly expiresAt: number;\n}\n\ninterface CommandExecutionOptions {\n readonly timeoutMs?: number;\n}\n\ninterface ContextDetectorOptions {\n readonly cacheTtlMs?: number;\n readonly commandTimeoutMs?: number;\n readonly cwdResolver?: (pid: number) => Promise<string | undefined>;\n readonly execCommand?: (\n command: string,\n args: readonly string[],\n options?: CommandExecutionOptions,\n ) => Promise<string>;\n readonly now?: () => number;\n}\n\nconst TERM_PROGRAM_MAP: Record<string, string> = {\n Apple_Terminal: 'Terminal.app',\n Hyper: 'Hyper',\n 'iTerm.app': 'iTerm2',\n WezTerm: 'WezTerm',\n ghostty: 'Ghostty',\n tmux: 'tmux',\n vscode: 'VS Code',\n zed: 'Zed',\n};\n\nconst PROCESS_NAME_MAP: Record<string, string> = {\n Alacritty: 'Alacritty',\n Hyper: 'Hyper',\n Terminal: 'Terminal.app',\n Warp: 'Warp',\n WezTerm: 'WezTerm',\n ghostty: 'Ghostty',\n iTerm2: 'iTerm2',\n kitty: 'kitty',\n screen: 'screen',\n tmux: 'tmux',\n 'tmux: server': 'tmux',\n};\n\nconst TOOL_BINARY_MAP: Record<ToolName, string> = {\n 'aider': 'aider',\n 'amp': 'amp',\n 'augment-code': 'auggie',\n 'claude-code': 'claude',\n 'cline': 'cline',\n 'codex': 'codex',\n 'continue': 'continue',\n 'copilot-cli': 'copilot',\n 'cursor': 'cursor',\n 'devin': 'devin',\n 'gemini-cli': 'gemini',\n 'goose': 'goose',\n 'kilo': 'kilo',\n 'kiro': 'kiro',\n 'mistral': 'mistral',\n 'openhands': 'openhands',\n 'openclaw': 'openclaw',\n 'opencode': 'opencode',\n 'pi': 'pi',\n 'qwen-code': 'qwen',\n 'unknown': 'unknown',\n 'windsurf': 'windsurf',\n 'zed': 'zed',\n};\n\n/**\n * ๐Ÿ“– Context enrichment is always best-effort. Failing to detect a terminal or\n * cwd must never break the event stream itself.\n */\nexport class ContextDetector {\n private readonly cache = new Map<number, CachedProcessContext>();\n\n private readonly cacheTtlMs: number;\n\n private readonly commandTimeoutMs: number;\n\n private readonly cwdResolver: (pid: number) => Promise<string | undefined>;\n\n private readonly execCommand: (\n command: string,\n args: readonly string[],\n options?: CommandExecutionOptions,\n ) => Promise<string>;\n\n private readonly now: () => number;\n\n public constructor(options: ContextDetectorOptions = {}) {\n this.cacheTtlMs = options.cacheTtlMs ?? 30_000;\n this.commandTimeoutMs = options.commandTimeoutMs ?? 500;\n this.cwdResolver =\n options.cwdResolver ?? ((pid) => this.resolveCwdWithPidCwd(pid));\n this.execCommand =\n options.execCommand ??\n ((command, args, commandOptions) =>\n this.defaultExecCommand(command, args, commandOptions));\n this.now = options.now ?? Date.now;\n }\n\n /**\n * Detects the terminal display name from environment variables.\n */\n public detectTerminal(env: NodeJS.ProcessEnv = {}): string {\n if (env.ITERM_SESSION_ID) {\n return 'iTerm2';\n }\n\n if (env.KITTY_WINDOW_ID) {\n return 'kitty';\n }\n\n if (env.WEZTERM_EXECUTABLE) {\n return 'WezTerm';\n }\n\n if (env.TERM_PROGRAM) {\n return TERM_PROGRAM_MAP[env.TERM_PROGRAM] ?? env.TERM_PROGRAM;\n }\n\n if (env.TERM === 'alacritty' || env.TERM?.includes('alacritty')) {\n return 'Alacritty';\n }\n\n if (env.TERM?.includes('ghostty')) {\n return 'Ghostty';\n }\n\n if (env.TMUX) {\n return 'tmux';\n }\n\n return 'unknown';\n }\n\n /**\n * Walks the parent-process chain looking for a known terminal emulator.\n */\n public async getTerminalFromPPIDChain(pid: number): Promise<string> {\n let currentPid = pid;\n\n for (let depth = 0; depth < 4 && currentPid > 0; depth += 1) {\n try {\n const stdout = await this.execCommand(\n 'ps',\n ['-p', String(currentPid), '-o', 'ppid=,comm='],\n { timeoutMs: this.commandTimeoutMs },\n );\n const line = stdout.trim();\n const match = line.match(/^(\\d+)\\s+(.+)$/u);\n\n if (!match) {\n return 'unknown';\n }\n\n const parentPidToken = match[1];\n const commandText = match[2];\n\n if (!parentPidToken || !commandText) {\n return 'unknown';\n }\n\n const nextPid = Number.parseInt(parentPidToken, 10);\n const normalizedProcessName = basename(commandText).replace(/\\.app$/u, '');\n const mappedTerminal =\n PROCESS_NAME_MAP[normalizedProcessName] ??\n PROCESS_NAME_MAP[commandText.trim()];\n\n if (mappedTerminal) {\n return mappedTerminal;\n }\n\n currentPid = nextPid;\n } catch (error: unknown) {\n logger.debug({ error, pid }, 'Terminal PPID chain lookup failed');\n return 'unknown';\n }\n }\n\n return 'unknown';\n }\n\n /**\n * Resolves the working directory for a running process with a fast timeout.\n */\n public async getCWDForPID(pid: number): Promise<string | undefined> {\n try {\n return await this.withTimeout(this.cwdResolver(pid));\n } catch (error: unknown) {\n logger.warn({ error, pid }, 'Primary PID cwd lookup failed');\n }\n\n if (process.platform !== 'darwin') {\n return undefined;\n }\n\n try {\n const stdout = await this.execCommand(\n 'lsof',\n ['-a', '-p', String(pid), '-d', 'cwd', '-Fn'],\n { timeoutMs: this.commandTimeoutMs },\n );\n const cwdLine = stdout\n .split('\\n')\n .find((line) => line.startsWith('n') && line.length > 1);\n\n return cwdLine?.slice(1) || undefined;\n } catch (error: unknown) {\n logger.warn({ error, pid }, 'Fallback PID cwd lookup failed');\n return undefined;\n }\n }\n\n /**\n * Decodes a Claude transcript path into its original project cwd when possible.\n */\n public decodeCWDFromTranscriptPath(\n transcriptPath: string,\n ): string | undefined {\n const match = transcriptPath.match(/\\.claude\\/projects\\/([^/]+)\\//u);\n\n if (!match?.[1] || !match[1].startsWith('-')) {\n return undefined;\n }\n\n return match[1].replace(/-/gu, '/');\n }\n\n /**\n * Enumerates active instances for a given tool binary using `pgrep`.\n */\n public async enumerateInstances(toolBinary: string): Promise<ProcessInfo[]> {\n if (process.platform === 'win32' || toolBinary === 'unknown') {\n return [];\n }\n\n try {\n const stdout = await this.execCommand(\n 'pgrep',\n ['-fl', toolBinary],\n { timeoutMs: this.commandTimeoutMs },\n );\n const lines = stdout\n .trim()\n .split('\\n')\n .filter((line) => line.trim().length > 0);\n\n const processRows: ProcessInfo[] = [];\n\n for (const line of lines) {\n const [pidToken] = line.trim().split(/\\s+/u, 1);\n const parsedPid = Number.parseInt(pidToken ?? '', 10);\n\n if (!Number.isFinite(parsedPid)) {\n continue;\n }\n\n processRows.push({\n pid: parsedPid,\n cwd: await this.getCWDForPID(parsedPid),\n });\n }\n\n return processRows.sort((left, right) => left.pid - right.pid);\n } catch (error: unknown) {\n logger.debug({ error, toolBinary }, 'Instance enumeration failed');\n return [];\n }\n }\n\n /**\n * Returns the 1-based position of the PID among active tool instances.\n */\n public async getInstanceIndex(\n pid: number,\n toolBinary: string,\n ): Promise<{ readonly index: number; readonly total: number }> {\n const instances = await this.enumerateInstances(toolBinary);\n const index = instances.findIndex((instance) => instance.pid === pid);\n\n return {\n index: index >= 0 ? index + 1 : 1,\n total: Math.max(instances.length, 1),\n };\n }\n\n /**\n * Builds a stable identifier for one tool instance.\n */\n public buildInstanceId(\n toolName: ToolName,\n pid: number,\n sessionId?: string,\n ): string {\n return `${toolName}:${sessionId ?? pid}`;\n }\n\n /**\n * Enriches an AISnitch event with best-effort runtime context.\n */\n public async enrich(\n event: AISnitchEvent,\n context: ProcessContext = {},\n ): Promise<AISnitchEvent> {\n const pid = context.pid ?? event.data.pid;\n const toolName = event['aisnitch.tool'];\n const toolBinary = TOOL_BINARY_MAP[toolName];\n const hookPayloadCwd = this.getHookPayloadCwd(context.hookPayload);\n const explicitTerminal =\n event.data.terminal ??\n (context.env ? this.detectTerminal(context.env) : 'unknown');\n const explicitCwd =\n event.data.cwd ??\n hookPayloadCwd ??\n (context.transcriptPath\n ? this.decodeCWDFromTranscriptPath(context.transcriptPath)\n : undefined);\n\n if (!pid || pid <= 0) {\n return {\n ...event,\n data: {\n ...event.data,\n terminal:\n explicitTerminal !== 'unknown' ? explicitTerminal : event.data.terminal,\n cwd: explicitCwd ?? event.data.cwd,\n instanceId: context.sessionId\n ? this.buildInstanceId(toolName, 0, context.sessionId)\n : event.data.instanceId,\n },\n };\n }\n\n const cachedContext = this.getCachedContext(pid);\n const detectedContext =\n cachedContext ?? (await this.detectContext(pid, toolBinary, explicitTerminal));\n\n if (!cachedContext) {\n this.cache.set(pid, {\n ...detectedContext,\n expiresAt: this.now() + this.cacheTtlMs,\n });\n }\n\n const instanceId = this.buildInstanceId(\n toolName,\n pid,\n context.sessionId ?? event['aisnitch.sessionid'],\n );\n\n return {\n ...event,\n data: {\n ...event.data,\n terminal:\n explicitTerminal !== 'unknown'\n ? explicitTerminal\n : detectedContext.terminal ?? event.data.terminal,\n cwd:\n explicitCwd ??\n detectedContext.cwd ??\n event.data.cwd,\n pid,\n instanceId,\n instanceIndex:\n event.data.instanceIndex ?? detectedContext.instanceIndex,\n instanceTotal:\n event.data.instanceTotal ?? detectedContext.instanceTotal,\n },\n };\n }\n\n private async detectContext(\n pid: number,\n toolBinary: string,\n explicitTerminal: string,\n ): Promise<Omit<CachedProcessContext, 'expiresAt'>> {\n const cwdPromise = this.getCWDForPID(pid);\n const instancePromise = this.getInstanceIndex(pid, toolBinary);\n const terminalPromise =\n explicitTerminal !== 'unknown'\n ? Promise.resolve(explicitTerminal)\n : this.getTerminalFromPPIDChain(pid);\n\n const [cwd, instanceInfo, terminal] = await Promise.all([\n cwdPromise.catch(() => undefined),\n instancePromise.catch(() => ({ index: 1, total: 1 })),\n terminalPromise.catch(() => 'unknown'),\n ]);\n\n return {\n cwd,\n terminal: terminal !== 'unknown' ? terminal : undefined,\n instanceIndex: instanceInfo.index,\n instanceTotal: instanceInfo.total,\n };\n }\n\n private getCachedContext(pid: number): Omit<CachedProcessContext, 'expiresAt'> | undefined {\n const cachedContext = this.cache.get(pid);\n\n if (!cachedContext) {\n return undefined;\n }\n\n if (cachedContext.expiresAt <= this.now()) {\n this.cache.delete(pid);\n return undefined;\n }\n\n const { expiresAt: _expiresAt, ...context } = cachedContext;\n return context;\n }\n\n private getHookPayloadCwd(\n hookPayload: Record<string, unknown> | undefined,\n ): string | undefined {\n if (!hookPayload) {\n return undefined;\n }\n\n const rawCwd = hookPayload.cwd;\n\n return typeof rawCwd === 'string' && rawCwd.length > 0 ? rawCwd : undefined;\n }\n\n private async resolveCwdWithPidCwd(pid: number): Promise<string | undefined> {\n const cwd = (await pidCwd(pid)) as string | null | undefined;\n\n return cwd ?? undefined;\n }\n\n private async defaultExecCommand(\n command: string,\n args: readonly string[],\n options: CommandExecutionOptions = {},\n ): Promise<string> {\n const result = await execFile(command, [...args], {\n encoding: 'utf8',\n timeout: options.timeoutMs ?? this.commandTimeoutMs,\n maxBuffer: 1024 * 1024,\n });\n\n return result.stdout;\n }\n\n private async withTimeout<T>(promise: Promise<T>): Promise<T> {\n return await Promise.race([\n promise,\n new Promise<never>((_resolve, reject) => {\n setTimeout(() => {\n reject(new Error('Context detection timed out.'));\n }, this.commandTimeoutMs).unref();\n }),\n ]);\n }\n}\n","/**\n * @file src/adapters/index.ts\n * @description Barrel exports for the built-in AISnitch adapter system and factory.\n * @functions\n * โ†’ createDefaultAdapters\n * @exports all adapter primitives plus createDefaultAdapters\n * @see ./base.ts\n * @see ./registry.ts\n * @see ./aider.ts\n * @see ./claude-code.ts\n * @see ./copilot-cli.ts\n * @see ./cursor.ts\n * @see ./devin.ts\n * @see ./gemini-cli.ts\n * @see ./generic-pty.ts\n * @see ./goose.ts\n * @see ./kilo.ts\n * @see ./codex.ts\n * @see ./openclaw.ts\n * @see ./opencode.ts\n * @see ./pi.ts\n * @see ./zed.ts\n */\n\nimport type { AdapterRuntimeOptions } from './base.js';\nimport { AiderAdapter } from './aider.js';\nimport { ClaudeCodeAdapter } from './claude-code.js';\nimport { CopilotCLIAdapter } from './copilot-cli.js';\nimport { CodexAdapter } from './codex.js';\nimport { CursorAdapter } from './cursor.js';\nimport { DevinAdapter } from './devin.js';\nimport { GeminiCLIAdapter } from './gemini-cli.js';\nimport { GooseAdapter } from './goose.js';\nimport { KiloAdapter } from './kilo.js';\nimport { OpenClawAdapter } from './openclaw.js';\nimport { OpenCodeAdapter } from './opencode.js';\nimport { PiAdapter } from './pi.js';\nimport { ZedAdapter } from './zed.js';\n\nexport * from './base.js';\nexport * from './registry.js';\nexport * from './aider.js';\nexport * from './claude-code.js';\nexport * from './copilot-cli.js';\nexport * from './codex.js';\nexport * from './cursor.js';\nexport * from './devin.js';\nexport * from './gemini-cli.js';\nexport * from './generic-pty.js';\nexport * from './goose.js';\nexport * from './kilo.js';\nexport * from './openclaw.js';\nexport * from './opencode.js';\nexport * from './pi.js';\nexport * from './zed.js';\n\n/**\n * Instantiates the built-in adapters that ship with AISnitch.\n */\nexport function createDefaultAdapters(options: AdapterRuntimeOptions) {\n return [\n new AiderAdapter(options),\n new ClaudeCodeAdapter(options),\n new CopilotCLIAdapter(options),\n new CursorAdapter(options),\n new DevinAdapter(options),\n new GeminiCLIAdapter(options),\n new GooseAdapter(options),\n new KiloAdapter(options),\n new CodexAdapter(options),\n new OpenClawAdapter(options),\n new OpenCodeAdapter(options),\n new PiAdapter(options),\n new ZedAdapter(options),\n ] as const;\n}\n","import type { infer as ZodInfer } from 'zod';\nimport { z } from 'zod';\n\nimport { ToolNameSchema } from '../events/schema.js';\n\n/**\n * @file src/core/config/schema.ts\n * @description Zod schemas and inferred types for the persistent AISnitch configuration file.\n * @functions\n * โ†’ none\n * @exports LOG_LEVELS, AdapterConfigSchema, ConfigSchema, AISnitchConfig, AdapterConfig\n * @see ./loader.ts\n */\n\n/**\n * Supported log levels for the daemon runtime.\n */\nexport const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;\nexport const AUTO_UPDATE_MANAGERS = ['auto', 'npm', 'pnpm', 'bun', 'brew'] as const;\n\n/**\n * Per-adapter toggle stored inside the config file.\n */\nexport const AdapterConfigSchema = z.strictObject({\n enabled: z.boolean().default(true),\n});\n\n/**\n * Silent self-update behavior for globally installed AISnitch binaries.\n */\nexport const AutoUpdateConfigSchema = z.strictObject({\n enabled: z.boolean().default(true),\n intervalMs: z.number().int().min(0).default(0),\n manager: z.enum(AUTO_UPDATE_MANAGERS).default('auto'),\n});\n\n/**\n * Runtime schema for the full persisted configuration contract.\n */\nexport const ConfigSchema = z.strictObject({\n wsPort: z.number().int().min(1024).max(65535).default(4820),\n httpPort: z.number().int().min(1024).max(65535).default(4821),\n /**\n * ๐Ÿ“– This is intentionally a partial record because most users will only\n * override a couple of adapters instead of all supported tools at once.\n */\n adapters: z.partialRecord(ToolNameSchema, AdapterConfigSchema).default({}),\n autoUpdate: AutoUpdateConfigSchema.default({\n enabled: true,\n intervalMs: 0,\n manager: 'auto',\n }),\n idleTimeoutMs: z.number().int().min(10_000).default(120_000),\n logLevel: z.enum(LOG_LEVELS).default('info'),\n});\n\n/**\n * Inferred TypeScript view of a single adapter config entry.\n */\nexport type AdapterConfig = ZodInfer<typeof AdapterConfigSchema>;\nexport type AutoUpdateConfig = ZodInfer<typeof AutoUpdateConfigSchema>;\n\n/**\n * Inferred TypeScript view of the persisted AISnitch config.\n */\nexport type AISnitchConfig = ZodInfer<typeof ConfigSchema>;\n","import type { AISnitchConfig } from './schema.js';\n\n/**\n * @file src/core/config/defaults.ts\n * @description Central default values for the AISnitch runtime configuration.\n * @functions\n * โ†’ none\n * @exports DEFAULT_CONFIG\n * @see ./schema.ts\n */\n\n/**\n * ๐Ÿ“– Keeping defaults in plain data makes them reusable for docs, tests,\n * config bootstrapping, and eventual `aisnitch config` CLI commands.\n */\nexport const DEFAULT_CONFIG: AISnitchConfig = {\n wsPort: 4820,\n httpPort: 4821,\n adapters: {},\n autoUpdate: {\n enabled: true,\n intervalMs: 0,\n manager: 'auto',\n },\n idleTimeoutMs: 120_000,\n logLevel: 'info',\n};\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nimport { DEFAULT_CONFIG } from './defaults.js';\nimport { ConfigSchema } from './schema.js';\nimport type { AISnitchConfig } from './schema.js';\n\n/**\n * @file src/core/config/loader.ts\n * @description File-system backed helpers for reading, writing, and resolving AISnitch config paths and ports.\n * @functions\n * โ†’ getAISnitchHomePath\n * โ†’ getConfigPath\n * โ†’ ensureConfigDir\n * โ†’ loadConfig\n * โ†’ saveConfig\n * โ†’ resolveAvailablePort\n * @exports ConfigPathOptions, PortResolutionOptions, getAISnitchHomePath, getConfigPath, ensureConfigDir, loadConfig, saveConfig, resolveAvailablePort\n * @see ./schema.ts\n * @see ./defaults.ts\n */\n\n/**\n * Common options for redirecting config path resolution during tests.\n */\nexport interface ConfigPathOptions {\n readonly env?: NodeJS.ProcessEnv;\n readonly homeDirectory?: string;\n readonly configPath?: string;\n}\n\n/**\n * Options for port selection and lightweight logging during bootstrap.\n */\nexport interface PortResolutionOptions {\n readonly host?: string;\n readonly maxAttempts?: number;\n readonly logger?: (message: string) => void;\n}\n\n/**\n * Returns the root directory used by AISnitch to store config and daemon state.\n */\nexport function getAISnitchHomePath(options: ConfigPathOptions = {}): string {\n if (options.configPath && options.configPath.trim().length > 0) {\n return dirname(resolve(options.configPath));\n }\n\n const configuredHome = options.env?.AISNITCH_HOME;\n\n if (configuredHome && configuredHome.trim().length > 0) {\n return resolve(configuredHome);\n }\n\n return join(options.homeDirectory ?? homedir(), '.aisnitch');\n}\n\n/**\n * Resolves the absolute path of `config.json`, honoring `AISNITCH_HOME`.\n */\nexport function getConfigPath(options: ConfigPathOptions = {}): string {\n if (options.configPath && options.configPath.trim().length > 0) {\n return resolve(options.configPath);\n }\n\n return join(getAISnitchHomePath(options), 'config.json');\n}\n\n/**\n * Ensures the AISnitch home directory exists before reading or writing config.\n */\nexport async function ensureConfigDir(\n options: ConfigPathOptions = {},\n): Promise<string> {\n const directoryPath = getAISnitchHomePath(options);\n\n await mkdir(directoryPath, { recursive: true });\n\n return directoryPath;\n}\n\n/**\n * Loads, validates, and default-fills the AISnitch config from disk.\n */\nexport async function loadConfig(\n options: ConfigPathOptions = {},\n): Promise<AISnitchConfig> {\n const configPath = getConfigPath(options);\n\n try {\n const rawConfig = await readFile(configPath, 'utf8');\n const parsedJson: unknown = JSON.parse(rawConfig);\n\n return ConfigSchema.parse(parsedJson);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return ConfigSchema.parse(DEFAULT_CONFIG);\n }\n\n if (error instanceof SyntaxError) {\n throw new Error(`Invalid JSON in AISnitch config at ${configPath}`, {\n cause: error,\n });\n }\n\n throw error;\n }\n}\n\n/**\n * Writes a validated AISnitch config back to disk using stable pretty JSON.\n */\nexport async function saveConfig(\n config: AISnitchConfig,\n options: ConfigPathOptions = {},\n): Promise<string> {\n const validatedConfig = ConfigSchema.parse(config);\n const configPath = getConfigPath(options);\n\n await ensureConfigDir(options);\n await writeFile(\n configPath,\n `${JSON.stringify(validatedConfig, null, 2)}\\n`,\n 'utf8',\n );\n\n return configPath;\n}\n\nasync function canBindPort(port: number, host: string): Promise<boolean> {\n return await new Promise<boolean>((resolveAvailability, reject) => {\n const server = createServer();\n\n server.once('error', (error: NodeJS.ErrnoException) => {\n server.close();\n\n if (error.code === 'EADDRINUSE') {\n resolveAvailability(false);\n return;\n }\n\n reject(error);\n });\n\n server.once('listening', () => {\n server.close((closeError) => {\n if (closeError) {\n reject(closeError);\n return;\n }\n\n resolveAvailability(true);\n });\n });\n\n server.listen(port, host);\n });\n}\n\n/**\n * Resolves a usable port by trying the requested port first and then the next\n * sequential ports up to a bounded retry count.\n */\nexport async function resolveAvailablePort(\n requestedPort: number,\n options: PortResolutionOptions = {},\n): Promise<number> {\n const host = options.host ?? '127.0.0.1';\n /**\n * ๐Ÿ“– AISnitch can spawn foreground demos, ephemeral wrap pipelines, and a\n * managed daemon on the same machine. Keeping the default search window too\n * narrow makes one stale process enough to brick startup, so we probe a\n * wider local range before giving up.\n */\n const maxAttempts = options.maxAttempts ?? 100;\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n const candidatePort = requestedPort + attempt;\n const available = await canBindPort(candidatePort, host);\n\n if (!available) {\n continue;\n }\n\n if (candidatePort === requestedPort) {\n options.logger?.(`AISnitch will use requested port ${candidatePort}.`);\n } else {\n options.logger?.(\n `AISnitch port ${requestedPort} is busy, using ${candidatePort} instead.`,\n );\n }\n\n return candidatePort;\n }\n\n throw new Error(\n `Unable to find an available port from ${requestedPort} to ${\n requestedPort + maxAttempts - 1\n }.`,\n );\n}\n","import { EventEmitter } from 'eventemitter3';\n\nimport { AISnitchEventSchema } from '../events/schema.js';\nimport type { AISnitchEvent, AISnitchEventType } from '../events/types.js';\nimport { logger } from './logger.js';\n\n/**\n * @file src/core/engine/event-bus.ts\n * @description Typed in-memory pub/sub bus used by the AISnitch runtime pipeline.\n * @functions\n * โ†’ none\n * @exports EventHandler, EventBusStats, EventBus\n * @see ./logger.ts\n * @see ../events/schema.ts\n */\n\n/**\n * Listener signature used by the EventBus.\n */\nexport type EventHandler = (event: AISnitchEvent) => void;\n\ntype EventBusChannels = {\n event: (event: AISnitchEvent) => void;\n} & {\n [K in AISnitchEventType as `event:${K}`]: (event: AISnitchEvent) => void;\n};\n\n/**\n * Metrics exposed by the in-memory event bus.\n */\nexport interface EventBusStats {\n readonly publishedEvents: number;\n readonly rejectedEvents: number;\n readonly subscriberCount: number;\n}\n\n/**\n * ๐Ÿ“– The EventBus is the single fan-out point inside the process. Adapters,\n * hook receivers, and IPC ingress all publish here before anything reaches WS.\n */\nexport class EventBus {\n private readonly emitter: EventEmitter<EventBusChannels> =\n new EventEmitter<EventBusChannels>();\n\n private readonly globalHandlers = new Set<EventHandler>();\n\n private readonly typedHandlers = new Map<AISnitchEventType, Set<EventHandler>>();\n\n private publishedEvents = 0;\n\n private rejectedEvents = 0;\n\n /**\n * Validates and publishes an event to all generic and type-specific listeners.\n */\n publish(event: unknown): event is AISnitchEvent {\n const parsedEvent = AISnitchEventSchema.safeParse(event);\n\n if (!parsedEvent.success) {\n this.rejectedEvents += 1;\n logger.warn(\n {\n issues: parsedEvent.error.issues,\n },\n 'Rejected invalid event',\n );\n return false;\n }\n\n this.publishedEvents += 1;\n\n logger.debug(\n {\n eventId: parsedEvent.data.id,\n instanceId: parsedEvent.data.data.instanceId,\n sessionId: parsedEvent.data['aisnitch.sessionid'],\n eventType: parsedEvent.data.type,\n tool: parsedEvent.data['aisnitch.tool'],\n },\n 'Published event',\n );\n\n // ๐Ÿ“– Wrap emits in try/catch โ€” one buggy subscriber must never crash the bus\n try {\n this.emitter.emit('event', parsedEvent.data);\n } catch (error: unknown) {\n logger.warn({ error, eventType: parsedEvent.data.type }, '๐Ÿ“– Error in EventBus global subscriber');\n }\n\n try {\n this.emitter.emit(`event:${parsedEvent.data.type}`, parsedEvent.data);\n } catch (error: unknown) {\n logger.warn({ error, eventType: parsedEvent.data.type }, '๐Ÿ“– Error in EventBus typed subscriber');\n }\n\n return true;\n }\n\n /**\n * Subscribes to all valid events emitted on the bus.\n */\n subscribe(handler: EventHandler): () => void {\n this.globalHandlers.add(handler);\n this.emitter.on('event', handler);\n\n return () => {\n this.unsubscribe(handler);\n };\n }\n\n /**\n * Subscribes to only one normalized event type.\n */\n subscribeType(type: AISnitchEventType, handler: EventHandler): () => void {\n const channel = `event:${type}` as const;\n const handlersForType = this.typedHandlers.get(type) ?? new Set<EventHandler>();\n\n handlersForType.add(handler);\n this.typedHandlers.set(type, handlersForType);\n this.emitter.on(channel, handler);\n\n return () => {\n this.unsubscribeType(type, handler);\n };\n }\n\n /**\n * Removes a previously subscribed catch-all handler.\n */\n unsubscribe(handler: EventHandler): void {\n this.globalHandlers.delete(handler);\n this.emitter.off('event', handler);\n }\n\n /**\n * Removes all listeners and clears internal handler tracking.\n */\n unsubscribeAll(): void {\n this.globalHandlers.clear();\n this.typedHandlers.clear();\n this.emitter.removeAllListeners();\n }\n\n /**\n * Returns current in-memory bus statistics.\n */\n getStats(): EventBusStats {\n const typedSubscriberCount = [...this.typedHandlers.values()].reduce(\n (count, handlers) => count + handlers.size,\n 0,\n );\n\n return {\n publishedEvents: this.publishedEvents,\n rejectedEvents: this.rejectedEvents,\n subscriberCount: this.globalHandlers.size + typedSubscriberCount,\n };\n }\n\n private unsubscribeType(type: AISnitchEventType, handler: EventHandler): void {\n const channel = `event:${type}` as const;\n const handlersForType = this.typedHandlers.get(type);\n\n if (!handlersForType) {\n return;\n }\n\n handlersForType.delete(handler);\n\n if (handlersForType.size === 0) {\n this.typedHandlers.delete(type);\n }\n\n this.emitter.off(channel, handler);\n }\n}\n","/**\n * @file src/core/engine/ring-buffer.ts\n * @description Fixed-size oldest-first ring buffer used to absorb temporary consumer backpressure.\n * @functions\n * โ†’ none\n * @exports RingBuffer\n */\n\n/**\n * ๐Ÿ“– This buffer intentionally drops the oldest item when full. For a live\n * stream UI that is exactly the right tradeoff: newest activity beats stale UI.\n */\nexport class RingBuffer<T> {\n private readonly items: Array<T | undefined>;\n\n private head = 0;\n\n private count = 0;\n\n public constructor(private readonly maxCapacity: number) {\n if (!Number.isInteger(maxCapacity) || maxCapacity <= 0) {\n throw new Error('RingBuffer capacity must be a positive integer.');\n }\n\n this.items = new Array<T | undefined>(maxCapacity);\n }\n\n /**\n * Pushes one item into the buffer and returns the dropped oldest item if full.\n */\n push(item: T): T | undefined {\n if (this.count < this.maxCapacity) {\n const insertIndex = (this.head + this.count) % this.maxCapacity;\n this.items[insertIndex] = item;\n this.count += 1;\n return undefined;\n }\n\n const droppedItem = this.items[this.head];\n\n this.items[this.head] = item;\n this.head = (this.head + 1) % this.maxCapacity;\n\n return droppedItem;\n }\n\n /**\n * Removes and returns the oldest item in the buffer.\n */\n shift(): T | undefined {\n if (this.count === 0) {\n return undefined;\n }\n\n const item = this.items[this.head];\n\n this.items[this.head] = undefined;\n this.head = (this.head + 1) % this.maxCapacity;\n this.count -= 1;\n\n return item;\n }\n\n /**\n * Drains and returns all items in oldest-first order.\n */\n drain(): T[] {\n const drainedItems: T[] = [];\n\n while (this.count > 0) {\n const item = this.shift();\n\n if (item !== undefined) {\n drainedItems.push(item);\n }\n }\n\n return drainedItems;\n }\n\n /**\n * Clears the buffer contents.\n */\n clear(): void {\n this.items.fill(undefined);\n this.head = 0;\n this.count = 0;\n }\n\n public get capacity(): number {\n return this.maxCapacity;\n }\n\n public get size(): number {\n return this.count;\n }\n\n public get isFull(): boolean {\n return this.count === this.maxCapacity;\n }\n}\n","import { once } from 'node:events';\nimport type { AddressInfo } from 'node:net';\n\nimport { WebSocket, WebSocketServer } from 'ws';\n\nimport { AISNITCH_VERSION } from '../../package-info.js';\nimport type { AISnitchEvent, ToolName } from '../events/types.js';\nimport type { EventBus } from './event-bus.js';\nimport { logger } from './logger.js';\nimport { RingBuffer } from './ring-buffer.js';\n\n/**\n * @file src/core/engine/ws-server.ts\n * @description Localhost-only WebSocket event stream server with per-consumer buffering and heartbeat handling.\n * @functions\n * โ†’ none\n * @exports WelcomeMessage, WSServerStartOptions, WSServerStats, WSServer\n * @see ./ring-buffer.ts\n * @see ./event-bus.ts\n */\n\n/**\n * Message sent immediately after a new consumer connects.\n */\nexport interface WelcomeMessage {\n readonly type: 'welcome';\n readonly version: string;\n readonly tools: readonly ToolName[];\n}\n\n/**\n * Startup configuration for the WebSocket server.\n */\nexport interface WSServerStartOptions {\n readonly port: number;\n readonly eventBus: EventBus;\n readonly activeTools?: readonly ToolName[];\n readonly host?: string;\n readonly bufferCapacity?: number;\n readonly backpressureThresholdBytes?: number;\n readonly heartbeatIntervalMs?: number;\n readonly pongTimeoutMs?: number;\n}\n\n/**\n * Observable runtime stats for the WebSocket server.\n */\nexport interface WSServerStats {\n readonly listening: boolean;\n readonly host: string;\n readonly port: number | null;\n readonly consumerCount: number;\n readonly eventsSent: number;\n readonly droppedEvents: number;\n}\n\ninterface ConsumerState {\n readonly buffer: RingBuffer<string>;\n lastPingAt: number;\n awaitingPongSince: number | null;\n}\n\n/**\n * ๐Ÿ“– Every consumer gets its own ring buffer so one slow UI cannot block the\n * others or force the daemon to keep unbounded queued output in memory.\n */\nexport class WSServer {\n private wss: WebSocketServer | undefined;\n\n private host = '127.0.0.1';\n\n private port: number | null = null;\n\n private readonly consumers = new Map<WebSocket, ConsumerState>();\n\n private unsubscribeFromBus: (() => void) | undefined;\n\n private maintenanceTimer: NodeJS.Timeout | undefined;\n\n private eventsSent = 0;\n\n private droppedEvents = 0;\n\n /**\n * Starts the localhost WebSocket server and subscribes it to the event bus.\n */\n public async start(options: WSServerStartOptions): Promise<number> {\n if (this.wss) {\n return this.port ?? options.port;\n }\n\n this.host = options.host ?? '127.0.0.1';\n\n const bufferCapacity = options.bufferCapacity ?? 1_000;\n const backpressureThresholdBytes =\n options.backpressureThresholdBytes ?? 64 * 1024;\n const heartbeatIntervalMs = options.heartbeatIntervalMs ?? 30_000;\n const pongTimeoutMs = options.pongTimeoutMs ?? 10_000;\n const activeTools = options.activeTools ?? [];\n\n this.wss = new WebSocketServer({\n host: this.host,\n port: options.port,\n });\n\n this.wss.on('connection', (socket) => {\n this.handleConnection(\n socket,\n {\n activeTools,\n bufferCapacity,\n backpressureThresholdBytes,\n },\n );\n });\n\n this.wss.on('error', (error) => {\n logger.error({ error }, 'WebSocket server error');\n });\n\n await once(this.wss, 'listening');\n\n const address = this.wss.address();\n\n if (!address || typeof address === 'string') {\n throw new Error('Unable to resolve WebSocket server address.');\n }\n\n this.port = (address as AddressInfo).port;\n\n this.unsubscribeFromBus = options.eventBus.subscribe((event) => {\n this.broadcastEvent(event, backpressureThresholdBytes);\n });\n\n this.maintenanceTimer = setInterval(() => {\n this.runMaintenance(backpressureThresholdBytes, heartbeatIntervalMs, pongTimeoutMs);\n }, 1_000);\n this.maintenanceTimer.unref();\n\n logger.info(\n {\n host: this.host,\n port: this.port,\n },\n 'WebSocket server started',\n );\n\n return this.port;\n }\n\n /**\n * Stops the server and closes all consumer connections.\n */\n public async stop(): Promise<void> {\n this.unsubscribeFromBus?.();\n this.unsubscribeFromBus = undefined;\n\n if (this.maintenanceTimer) {\n clearInterval(this.maintenanceTimer);\n this.maintenanceTimer = undefined;\n }\n\n for (const socket of this.consumers.keys()) {\n socket.terminate();\n }\n this.consumers.clear();\n\n if (!this.wss) {\n this.port = null;\n return;\n }\n\n const wss = this.wss;\n this.wss = undefined;\n\n await new Promise<void>((resolve, reject) => {\n wss.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n\n this.port = null;\n\n logger.info('WebSocket server stopped');\n }\n\n /**\n * Returns live server metrics used by health and status reporting.\n */\n public getStats(): WSServerStats {\n return {\n listening: this.wss !== undefined,\n host: this.host,\n port: this.port,\n consumerCount: this.consumers.size,\n eventsSent: this.eventsSent,\n droppedEvents: this.droppedEvents,\n };\n }\n\n private handleConnection(\n socket: WebSocket,\n options: {\n readonly activeTools: readonly ToolName[];\n readonly bufferCapacity: number;\n readonly backpressureThresholdBytes: number;\n },\n ): void {\n const state: ConsumerState = {\n buffer: new RingBuffer<string>(options.bufferCapacity),\n lastPingAt: Date.now(),\n awaitingPongSince: null,\n };\n\n this.consumers.set(socket, state);\n\n socket.on('pong', () => {\n state.awaitingPongSince = null;\n this.flushConsumer(socket, state, options.backpressureThresholdBytes);\n });\n\n socket.on('close', () => {\n this.consumers.delete(socket);\n });\n\n socket.on('error', (error) => {\n logger.warn({ error }, 'WebSocket consumer error');\n // ๐Ÿ“– Remove the consumer from the map so dead sockets don't accumulate\n this.consumers.delete(socket);\n });\n\n const welcomeMessage: WelcomeMessage = {\n type: 'welcome',\n version: AISNITCH_VERSION,\n tools: options.activeTools,\n };\n\n this.trySendOrQueue(\n socket,\n state,\n JSON.stringify(welcomeMessage),\n options.backpressureThresholdBytes,\n );\n }\n\n private broadcastEvent(\n event: AISnitchEvent,\n backpressureThresholdBytes: number,\n ): void {\n const serializedEvent = JSON.stringify(event);\n\n for (const [socket, state] of this.consumers) {\n this.trySendOrQueue(\n socket,\n state,\n serializedEvent,\n backpressureThresholdBytes,\n );\n }\n }\n\n private trySendOrQueue(\n socket: WebSocket,\n state: ConsumerState,\n serializedPayload: string,\n backpressureThresholdBytes: number,\n ): void {\n if (socket.readyState !== WebSocket.OPEN) {\n return;\n }\n\n if (state.buffer.size === 0 && socket.bufferedAmount < backpressureThresholdBytes) {\n socket.send(serializedPayload, (error) => {\n if (error) {\n logger.warn({ error }, 'Failed to send WebSocket payload');\n }\n });\n this.eventsSent += 1;\n return;\n }\n\n const droppedPayload = state.buffer.push(serializedPayload);\n\n if (droppedPayload !== undefined) {\n this.droppedEvents += 1;\n }\n }\n\n private flushConsumer(\n socket: WebSocket,\n state: ConsumerState,\n backpressureThresholdBytes: number,\n ): void {\n while (\n socket.readyState === WebSocket.OPEN &&\n state.buffer.size > 0 &&\n socket.bufferedAmount < backpressureThresholdBytes\n ) {\n const nextPayload = state.buffer.shift();\n\n if (nextPayload === undefined) {\n break;\n }\n\n socket.send(nextPayload, (error) => {\n if (error) {\n logger.warn({ error }, 'Failed to flush buffered WebSocket payload');\n }\n });\n\n this.eventsSent += 1;\n }\n }\n\n private runMaintenance(\n backpressureThresholdBytes: number,\n heartbeatIntervalMs: number,\n pongTimeoutMs: number,\n ): void {\n const now = Date.now();\n\n for (const [socket, state] of this.consumers) {\n this.flushConsumer(socket, state, backpressureThresholdBytes);\n\n if (state.awaitingPongSince !== null) {\n if (now - state.awaitingPongSince > pongTimeoutMs) {\n socket.terminate();\n }\n continue;\n }\n\n if (now - state.lastPingAt >= heartbeatIntervalMs) {\n state.lastPingAt = now;\n state.awaitingPongSince = now;\n\n if (socket.readyState === WebSocket.OPEN) {\n socket.ping();\n }\n }\n }\n }\n}\n","/**\n * @file src/package-info.ts\n * @description Shared package metadata constants consumed by the public index, CLI, and TUI without creating import cycles.\n * @functions\n * โ†’ getPackageScaffoldInfo\n * @exports AISNITCH_PACKAGE_NAME, AISNITCH_VERSION, AISNITCH_DESCRIPTION, AISnitchScaffoldInfo, getPackageScaffoldInfo\n * @see ./index.ts\n * @see ./cli/program.ts\n * @see ./tui/index.tsx\n */\n\n/**\n * ๐Ÿ“– This constant keeps the published package identity in one place so the\n * CLI and TUI can reuse a single source of truth without reaching through the\n * package root export barrel.\n */\nexport const AISNITCH_PACKAGE_NAME = 'aisnitch';\n\n/**\n * ๐Ÿ“– Injected at build time by tsup (and at test time by vitest) from package.json\n * via the __AISNITCH_VERSION__ define constant โ€” never edit this manually.\n * Bumping package.json is the only step required to update the displayed version.\n */\ndeclare const __AISNITCH_VERSION__: string;\nexport const AISNITCH_VERSION: string = __AISNITCH_VERSION__;\n\n/**\n * ๐Ÿ“– The shared description stays close to the package identity so commander\n * help output and future docs surfaces stay aligned.\n */\nexport const AISNITCH_DESCRIPTION =\n 'Universal bridge for AI coding tool activity โ€” capture, normalize, stream.';\n\n/**\n * Represents the stable scaffold metadata exposed by the package root.\n */\nexport interface AISnitchScaffoldInfo {\n readonly name: string;\n readonly version: string;\n readonly description: string;\n readonly supportedNodeRange: string;\n}\n\n/**\n * Builds a small metadata snapshot that other modules can consume without\n * reading package.json at runtime.\n */\nexport function getPackageScaffoldInfo(): AISnitchScaffoldInfo {\n return {\n name: AISNITCH_PACKAGE_NAME,\n version: AISNITCH_VERSION,\n description: AISNITCH_DESCRIPTION,\n supportedNodeRange: '>=20.0.0',\n };\n}\n","import { once } from 'node:events';\nimport {\n createServer,\n type IncomingMessage,\n type Server,\n type ServerResponse,\n} from 'node:http';\n\nimport { ToolNameSchema } from '../events/schema.js';\nimport type { ToolName } from '../events/types.js';\nimport { logger } from './logger.js';\n\n/**\n * @file src/core/engine/http-receiver.ts\n * @description Lightweight localhost-only HTTP receiver for tool hooks and daemon health checks.\n * @functions\n * โ†’ none\n * @exports HealthSnapshot, HTTPReceiverStartOptions, HTTPReceiverStats, HTTPReceiver\n * @see ./pipeline.ts\n */\n\n/**\n * Health payload returned by the HTTP receiver.\n */\nexport interface HealthSnapshot {\n readonly status: 'ok';\n readonly uptime: number;\n readonly consumers: number;\n readonly events: number;\n readonly droppedEvents: number;\n}\n\n/**\n * Startup configuration for the HTTP hook receiver.\n */\nexport interface HTTPReceiverStartOptions {\n readonly port: number;\n readonly host?: string;\n readonly onHook: (tool: ToolName, payload: unknown) => Promise<void> | void;\n readonly getHealthSnapshot: () => HealthSnapshot;\n}\n\n/**\n * Observable runtime stats for the HTTP receiver.\n */\nexport interface HTTPReceiverStats {\n readonly listening: boolean;\n readonly host: string;\n readonly port: number | null;\n readonly requestCount: number;\n readonly invalidRequestCount: number;\n readonly acceptedHooks: number;\n}\n\n/**\n * ๐Ÿ“– The hook receiver keeps zero framework magic on purpose. One endpoint plus\n * one health route do not justify hauling a whole server framework into core.\n */\nexport class HTTPReceiver {\n private server: Server | undefined;\n\n private host = '127.0.0.1';\n\n private port: number | null = null;\n\n private requestCount = 0;\n\n private invalidRequestCount = 0;\n\n private acceptedHooks = 0;\n\n /**\n * Starts the HTTP receiver on localhost and exposes hook and health routes.\n */\n public async start(options: HTTPReceiverStartOptions): Promise<number> {\n if (this.server) {\n return this.port ?? options.port;\n }\n\n this.host = options.host ?? '127.0.0.1';\n\n this.server = createServer((request, response) => {\n void this.handleRequest(request, response, options);\n });\n\n this.server.on('error', (error) => {\n logger.error({ error }, 'HTTP receiver error');\n });\n\n this.server.listen(options.port, this.host);\n await once(this.server, 'listening');\n\n const address = this.server.address();\n\n if (!address || typeof address === 'string') {\n throw new Error('Unable to resolve HTTP receiver address.');\n }\n\n this.port = address.port;\n\n logger.info(\n {\n host: this.host,\n port: this.port,\n },\n 'HTTP receiver started',\n );\n\n return this.port;\n }\n\n /**\n * Stops the receiver and closes the listening socket.\n */\n public async stop(): Promise<void> {\n if (!this.server) {\n this.port = null;\n return;\n }\n\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n\n this.port = null;\n\n logger.info('HTTP receiver stopped');\n }\n\n /**\n * Returns live HTTP receiver stats for health/status endpoints.\n */\n public getStats(): HTTPReceiverStats {\n return {\n listening: this.server !== undefined,\n host: this.host,\n port: this.port,\n requestCount: this.requestCount,\n invalidRequestCount: this.invalidRequestCount,\n acceptedHooks: this.acceptedHooks,\n };\n }\n\n private async handleRequest(\n request: IncomingMessage,\n response: ServerResponse,\n options: HTTPReceiverStartOptions,\n ): Promise<void> {\n this.requestCount += 1;\n\n let requestUrl: URL;\n\n try {\n requestUrl = new URL(\n request.url ?? '/',\n `http://${this.host}:${this.port ?? options.port}`,\n );\n } catch {\n this.invalidRequestCount += 1;\n this.sendJson(response, 400, { error: 'malformed request url' });\n return;\n }\n\n if (request.method === 'GET' && requestUrl.pathname === '/health') {\n this.sendJson(response, 200, options.getHealthSnapshot());\n return;\n }\n\n if (request.method === 'POST' && requestUrl.pathname.startsWith('/hooks/')) {\n const toolSegment = decodeURIComponent(\n requestUrl.pathname.slice('/hooks/'.length),\n );\n const parsedTool = ToolNameSchema.safeParse(toolSegment);\n\n if (!parsedTool.success || parsedTool.data === 'unknown') {\n this.invalidRequestCount += 1;\n this.sendJson(response, 404, {\n error: 'unknown tool',\n });\n return;\n }\n\n let payload: unknown;\n\n try {\n payload = await this.readJsonBody(request);\n } catch (error: unknown) {\n this.invalidRequestCount += 1;\n this.sendJson(response, 400, {\n error: error instanceof Error ? error.message : 'invalid json body',\n });\n return;\n }\n\n this.acceptedHooks += 1;\n this.sendJson(response, 202, {\n status: 'accepted',\n });\n\n queueMicrotask(() => {\n void Promise.resolve(options.onHook(parsedTool.data, payload)).catch((error) => {\n logger.error(\n {\n error,\n tool: parsedTool.data,\n },\n 'Hook handler failed',\n );\n });\n });\n return;\n }\n\n this.invalidRequestCount += 1;\n this.sendJson(response, 404, {\n error: 'not found',\n });\n }\n\n private async readJsonBody(request: IncomingMessage): Promise<unknown> {\n let rawBody = '';\n let bodyLength = 0;\n\n for await (const chunk of request) {\n const chunkText =\n typeof chunk === 'string'\n ? chunk\n : Buffer.from(chunk).toString('utf8');\n\n bodyLength += Buffer.byteLength(chunkText);\n\n if (bodyLength > 1_000_000) {\n throw new Error('request body too large');\n }\n\n rawBody += chunkText;\n }\n\n if (rawBody.length === 0) {\n throw new Error('missing json body');\n }\n\n try {\n return JSON.parse(rawBody) as unknown;\n } catch (error: unknown) {\n throw new Error('malformed json body', {\n cause: error,\n });\n }\n }\n\n private sendJson(\n response: ServerResponse,\n statusCode: number,\n payload: unknown,\n ): void {\n response.writeHead(statusCode, {\n 'content-type': 'application/json; charset=utf-8',\n });\n response.end(`${JSON.stringify(payload)}\\n`);\n }\n}\n","import { access, rm } from 'node:fs/promises';\nimport { constants } from 'node:fs';\nimport { createConnection, createServer, type Server, type Socket } from 'node:net';\nimport { createInterface } from 'node:readline';\nimport { once } from 'node:events';\n\nimport { AISnitchEventSchema } from '../events/schema.js';\nimport type { AISnitchEvent } from '../events/types.js';\nimport { logger } from './logger.js';\n\n/**\n * @file src/core/engine/uds-server.ts\n * @description NDJSON Unix domain socket ingress for out-of-process AISnitch adapters.\n * @functions\n * โ†’ none\n * @exports UDSServerStartOptions, UDSServerStats, UDSServer\n * @see ./pipeline.ts\n */\n\n/**\n * Startup configuration for the UDS server.\n */\nexport interface UDSServerStartOptions {\n readonly socketPath: string;\n readonly onEvent: (event: AISnitchEvent) => Promise<void> | void;\n}\n\n/**\n * Observable runtime stats for the UDS server.\n */\nexport interface UDSServerStats {\n readonly listening: boolean;\n readonly socketPath: string | null;\n readonly activeConnections: number;\n readonly acceptedConnections: number;\n readonly receivedEvents: number;\n readonly rejectedMessages: number;\n}\n\n/**\n * ๐Ÿ“– UDS is the low-friction IPC path for community adapters. NDJSON keeps the\n * protocol debuggable with shell tools and trivial to implement elsewhere.\n */\nexport class UDSServer {\n private server: Server | undefined;\n\n private socketPath: string | null = null;\n\n private readonly sockets = new Set<Socket>();\n\n private acceptedConnections = 0;\n\n private receivedEvents = 0;\n\n private rejectedMessages = 0;\n\n /**\n * Starts listening on the provided socket path.\n */\n public async start(options: UDSServerStartOptions): Promise<string> {\n if (this.server) {\n return this.socketPath ?? options.socketPath;\n }\n\n await this.ensureSocketPathAvailable(options.socketPath);\n\n this.server = createServer((socket) => {\n this.handleSocket(socket, options.onEvent);\n });\n\n this.server.on('error', (error) => {\n logger.error({ error }, 'UDS server error');\n });\n\n this.server.listen(options.socketPath);\n await once(this.server, 'listening');\n\n this.socketPath = options.socketPath;\n\n logger.info(\n {\n socketPath: this.socketPath,\n },\n 'UDS server started',\n );\n\n return this.socketPath;\n }\n\n /**\n * Stops the UDS server and removes the socket file.\n */\n public async stop(): Promise<void> {\n for (const socket of this.sockets) {\n socket.destroy();\n }\n this.sockets.clear();\n\n if (this.server) {\n const server = this.server;\n this.server = undefined;\n\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n return;\n }\n\n resolve();\n });\n });\n }\n\n if (this.socketPath && process.platform !== 'win32') {\n await rm(this.socketPath, { force: true });\n }\n\n this.socketPath = null;\n\n logger.info('UDS server stopped');\n }\n\n /**\n * Returns current runtime metrics for the UDS ingress channel.\n */\n public getStats(): UDSServerStats {\n return {\n listening: this.server !== undefined,\n socketPath: this.socketPath,\n activeConnections: this.sockets.size,\n acceptedConnections: this.acceptedConnections,\n receivedEvents: this.receivedEvents,\n rejectedMessages: this.rejectedMessages,\n };\n }\n\n private handleSocket(\n socket: Socket,\n onEvent: (event: AISnitchEvent) => Promise<void> | void,\n ): void {\n this.sockets.add(socket);\n this.acceptedConnections += 1;\n\n socket.on('close', () => {\n this.sockets.delete(socket);\n });\n\n socket.on('error', (error) => {\n logger.warn({ error }, 'UDS client socket error');\n });\n\n const lineReader = createInterface({\n input: socket,\n crlfDelay: Infinity,\n });\n\n lineReader.on('line', (line) => {\n if (line.trim().length === 0) {\n return;\n }\n\n let parsedPayload: unknown;\n\n try {\n parsedPayload = JSON.parse(line) as unknown;\n } catch (error: unknown) {\n this.rejectedMessages += 1;\n logger.warn({ error, line }, 'Rejected malformed UDS NDJSON payload');\n return;\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n if (!parsedEvent.success) {\n this.rejectedMessages += 1;\n logger.warn(\n {\n issues: parsedEvent.error.issues,\n },\n 'Rejected invalid UDS event payload',\n );\n return;\n }\n\n this.receivedEvents += 1;\n\n queueMicrotask(() => {\n void Promise.resolve(onEvent(parsedEvent.data)).catch((error) => {\n logger.error({ error }, 'UDS event handler failed');\n });\n });\n });\n }\n\n private async ensureSocketPathAvailable(socketPath: string): Promise<void> {\n if (process.platform === 'win32') {\n return;\n }\n\n try {\n await access(socketPath, constants.F_OK);\n } catch (error: unknown) {\n if (\n error instanceof Error &&\n 'code' in error &&\n error.code === 'ENOENT'\n ) {\n return;\n }\n\n throw error;\n }\n\n const staleSocket = await new Promise<boolean>((resolve, reject) => {\n const probe = createConnection(socketPath);\n\n probe.once('connect', () => {\n probe.destroy();\n resolve(false);\n });\n\n probe.once('error', (error: NodeJS.ErrnoException) => {\n if (\n error.code === 'ECONNREFUSED' ||\n error.code === 'ENOENT' ||\n error.code === 'EINVAL' ||\n error.code === 'ENOTSOCK'\n ) {\n resolve(true);\n return;\n }\n\n reject(error);\n });\n });\n\n if (!staleSocket) {\n throw new Error(`Socket path is already in use: ${socketPath}`);\n }\n\n await rm(socketPath, { force: true });\n }\n}\n","import { join } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { AdapterRegistry, createDefaultAdapters } from '../../adapters/index.js';\nimport {\n DEFAULT_CONFIG,\n type ConfigPathOptions,\n ensureConfigDir,\n getAISnitchHomePath,\n resolveAvailablePort,\n} from '../config/index.js';\nimport {\n AISnitchEventSchema,\n AISnitchEventTypeSchema,\n EventDataSchema,\n ToolNameSchema,\n createEvent,\n} from '../events/index.js';\nimport type { AISnitchConfig } from '../config/index.js';\nimport type { AISnitchEvent, ToolName } from '../events/index.js';\nimport { resolveSessionId } from '../session-identity.js';\nimport { ContextDetector, type ProcessContext } from './context-detector.js';\nimport { EventBus, type EventBusStats } from './event-bus.js';\nimport {\n HTTPReceiver,\n type HealthSnapshot,\n type HTTPReceiverStats,\n} from './http-receiver.js';\nimport { logger } from './logger.js';\nimport { UDSServer, type UDSServerStats } from './uds-server.js';\nimport { WSServer, type WSServerStats } from './ws-server.js';\n\n/**\n * @file src/core/engine/pipeline.ts\n * @description Orchestrates the in-memory AISnitch core pipeline and ingress/egress components.\n * @functions\n * โ†’ getSocketPath\n * @exports HookHandler, PipelineStartOptions, PipelineStatus, Pipeline\n * @see ./event-bus.ts\n * @see ./ws-server.ts\n * @see ./http-receiver.ts\n * @see ./uds-server.ts\n * @see ./context-detector.ts\n */\n\nconst HookIngressPayloadSchema = z.strictObject({\n type: AISnitchEventTypeSchema,\n source: z.string().min(1).optional(),\n sessionId: z.string().min(1).optional(),\n seqnum: z.number().int().min(1).optional(),\n data: EventDataSchema.partial().optional(),\n pid: z.number().int().positive().optional(),\n transcriptPath: z.string().min(1).optional(),\n cwd: z.string().min(1).optional(),\n env: z.record(z.string(), z.string()).optional(),\n hookPayload: z.record(z.string(), z.unknown()).optional(),\n});\n\n/**\n * Hook handler signature for future adapter-specific hook processors.\n */\nexport type HookHandler = (payload: unknown) => Promise<void> | void;\n\n/**\n * Startup options for the orchestrating pipeline.\n */\nexport interface PipelineStartOptions {\n readonly config?: AISnitchConfig;\n readonly configPath?: string;\n readonly env?: NodeJS.ProcessEnv;\n readonly homeDirectory?: string;\n}\n\n/**\n * Snapshot of the full runtime pipeline state.\n */\nexport interface PipelineStatus {\n readonly running: boolean;\n readonly uptimeMs: number;\n readonly wsPort: number | null;\n readonly httpPort: number | null;\n readonly socketPath: string | null;\n readonly eventBus: EventBusStats;\n readonly websocket: WSServerStats;\n readonly http: HTTPReceiverStats;\n readonly uds: UDSServerStats;\n}\n\n/**\n * Returns the platform-specific IPC socket path for the AISnitch daemon.\n */\nexport function getSocketPath(aisnitchHomePath: string): string {\n if (process.platform === 'win32') {\n return '\\\\\\\\.\\\\pipe\\\\aisnitch.sock';\n }\n\n return join(aisnitchHomePath, 'aisnitch.sock');\n}\n\n/**\n * ๐Ÿ“– The pipeline is the real in-process backbone: one EventBus in the middle,\n * ingress on HTTP/UDS, egress on WS, and context enrichment before fan-out.\n */\nexport class Pipeline {\n private readonly eventBus = new EventBus();\n\n private readonly wsServer = new WSServer();\n\n private readonly httpReceiver = new HTTPReceiver();\n\n private readonly udsServer = new UDSServer();\n\n private readonly contextDetector = new ContextDetector();\n\n private adapterRegistry: AdapterRegistry | null = null;\n\n private enabledTools = new Set<ToolName>();\n\n private readonly hookHandlers = new Map<ToolName, HookHandler>();\n\n private startedAt: number | null = null;\n\n private wsPort: number | null = null;\n\n private httpPort: number | null = null;\n\n private socketPath: string | null = null;\n\n /**\n * Starts the full in-memory core pipeline.\n */\n public async start(options: PipelineStartOptions = {}): Promise<PipelineStatus> {\n if (this.startedAt !== null) {\n return this.getStatus();\n }\n\n const config = options.config ?? DEFAULT_CONFIG;\n const pathOptions: ConfigPathOptions = {\n configPath: options.configPath,\n env: options.env,\n homeDirectory: options.homeDirectory,\n };\n\n await ensureConfigDir(pathOptions);\n\n const resolvedWsPort = await resolveAvailablePort(config.wsPort, {\n logger: (message) => logger.info(message),\n });\n let resolvedHttpPort = await resolveAvailablePort(config.httpPort, {\n logger: (message) => logger.info(message),\n });\n\n if (resolvedHttpPort === resolvedWsPort) {\n resolvedHttpPort = await resolveAvailablePort(resolvedHttpPort + 1, {\n logger: (message) => logger.info(message),\n });\n }\n const aisnitchHomePath = getAISnitchHomePath(pathOptions);\n const socketPath = getSocketPath(aisnitchHomePath);\n const activeTools = Object.entries(config.adapters)\n .filter((entry): entry is [ToolName, { enabled: boolean }] => {\n const [toolName, adapterConfig] = entry;\n return (\n ToolNameSchema.safeParse(toolName).success &&\n adapterConfig?.enabled === true\n );\n })\n .map(([toolName]) => toolName);\n const adapterRegistry = new AdapterRegistry();\n\n for (const adapter of createDefaultAdapters({\n config,\n env: options.env,\n homeDirectory: options.homeDirectory,\n publishEvent: async (event, context) => {\n return await this.publishEvent(event, context);\n },\n })) {\n adapterRegistry.register(adapter);\n }\n\n this.adapterRegistry = adapterRegistry;\n this.enabledTools = new Set(activeTools);\n this.hookHandlers.clear();\n\n for (const toolName of activeTools) {\n const adapter = this.adapterRegistry.get(toolName);\n\n if (!adapter) {\n continue;\n }\n\n this.registerHookHandler(toolName, async (payload) => {\n await adapter.handleHook(payload);\n });\n }\n\n try {\n this.wsPort = await this.wsServer.start({\n port: resolvedWsPort,\n eventBus: this.eventBus,\n activeTools,\n });\n this.httpPort = await this.httpReceiver.start({\n port: resolvedHttpPort,\n onHook: async (tool, payload) => {\n await this.handleHook(tool, payload);\n },\n getHealthSnapshot: () => this.getHealthSnapshot(),\n });\n this.socketPath = await this.udsServer.start({\n socketPath,\n onEvent: async (event) => {\n await this.publishEvent(event);\n },\n });\n await this.adapterRegistry.startAll(config);\n } catch (error: unknown) {\n logger.error({ error }, '๐Ÿ“– Pipeline start failed โ€” rolling back already-started components');\n await this.rollbackPartialStart();\n throw error;\n }\n\n this.startedAt = Date.now();\n\n logger.info(this.getStatus(), 'Core pipeline started');\n\n return this.getStatus();\n }\n\n /**\n * Stops every pipeline component in reverse dependency order.\n */\n public async stop(): Promise<void> {\n const stopSafely = async (label: string, fn: () => Promise<void>) => {\n try {\n await fn();\n } catch (error: unknown) {\n logger.warn({ error }, `๐Ÿ“– Error while stopping ${label} โ€” continuing shutdown`);\n }\n };\n\n await stopSafely('adapter registry', async () => {\n await this.adapterRegistry?.stopAll();\n });\n await stopSafely('HTTP receiver', async () => {\n await this.httpReceiver.stop();\n });\n await stopSafely('UDS server', async () => {\n await this.udsServer.stop();\n });\n await stopSafely('WebSocket server', async () => {\n await this.wsServer.stop();\n });\n\n this.eventBus.unsubscribeAll();\n this.adapterRegistry = null;\n this.enabledTools.clear();\n this.hookHandlers.clear();\n\n this.startedAt = null;\n this.wsPort = null;\n this.httpPort = null;\n this.socketPath = null;\n\n logger.info('Core pipeline stopped');\n }\n\n /**\n * Registers a future adapter-specific hook handler for one tool.\n */\n public registerHookHandler(tool: ToolName, handler: HookHandler): void {\n this.hookHandlers.set(tool, handler);\n }\n\n /**\n * ๐Ÿ“– Rolls back any components that were successfully started before a\n * failure occurred, preventing orphaned servers or leaking resources.\n */\n private async rollbackPartialStart(): Promise<void> {\n const stopSafe = async (label: string, fn: () => Promise<void>) => {\n try {\n await fn();\n } catch (error: unknown) {\n logger.warn({ error }, `๐Ÿ“– Error rolling back ${label}`);\n }\n };\n\n await stopSafe('adapter registry', async () => {\n await this.adapterRegistry?.stopAll();\n });\n await stopSafe('UDS server', async () => {\n await this.udsServer.stop();\n });\n await stopSafe('HTTP receiver', async () => {\n await this.httpReceiver.stop();\n });\n await stopSafe('WebSocket server', async () => {\n await this.wsServer.stop();\n });\n\n this.adapterRegistry = null;\n this.enabledTools.clear();\n this.hookHandlers.clear();\n }\n\n /**\n * Publishes an event after best-effort context enrichment.\n * ๐Ÿ“– If enrichment fails, the original event is published un-enriched\n * rather than being dropped entirely.\n */\n public async publishEvent(\n event: AISnitchEvent,\n context: ProcessContext = {},\n ): Promise<boolean> {\n let enrichedEvent: AISnitchEvent;\n\n try {\n enrichedEvent = await this.contextDetector.enrich(event, context);\n } catch (error: unknown) {\n logger.warn(\n { error, eventId: event.id },\n '๐Ÿ“– Context enrichment failed โ€” publishing un-enriched event',\n );\n enrichedEvent = event;\n }\n\n return this.eventBus.publish(enrichedEvent);\n }\n\n /**\n * Exposes current pipeline state for tests, health checks, and future status commands.\n */\n public getStatus(): PipelineStatus {\n return {\n running: this.startedAt !== null,\n uptimeMs: this.startedAt === null ? 0 : Date.now() - this.startedAt,\n wsPort: this.wsPort,\n httpPort: this.httpPort,\n socketPath: this.socketPath,\n eventBus: this.eventBus.getStats(),\n websocket: this.wsServer.getStats(),\n http: this.httpReceiver.getStats(),\n uds: this.udsServer.getStats(),\n };\n }\n\n /**\n * Returns the in-process event bus for direct wiring in tests or future TUI code.\n */\n public getEventBus(): EventBus {\n return this.eventBus;\n }\n\n /**\n * Returns the adapter registry for graceful shutdown coordination.\n */\n public getAdapterRegistry(): AdapterRegistry | undefined {\n return this.adapterRegistry ?? undefined;\n }\n\n /**\n * Returns the HTTP receiver for graceful shutdown coordination.\n */\n public getHttpReceiver(): HTTPReceiver {\n return this.httpReceiver;\n }\n\n /**\n * Returns the UDS server for graceful shutdown coordination.\n */\n public getUdsServer(): UDSServer {\n return this.udsServer;\n }\n\n /**\n * Returns the WebSocket server for graceful shutdown coordination.\n */\n public getWsServer(): WSServer {\n return this.wsServer;\n }\n\n private getHealthSnapshot(): HealthSnapshot {\n const status = this.getStatus();\n\n return {\n status: 'ok',\n uptime: status.uptimeMs,\n consumers: status.websocket.consumerCount,\n events: status.eventBus.publishedEvents,\n droppedEvents: status.websocket.droppedEvents,\n };\n }\n\n private async handleHook(tool: ToolName, payload: unknown): Promise<void> {\n try {\n await this.handleHookInner(tool, payload);\n } catch (error: unknown) {\n logger.error(\n { error, tool },\n '๐Ÿ“– Unhandled error in hook handler โ€” swallowing to prevent daemon crash',\n );\n }\n }\n\n private async handleHookInner(tool: ToolName, payload: unknown): Promise<void> {\n if (!this.enabledTools.has(tool)) {\n logger.debug({ tool }, 'Ignoring hook for disabled tool');\n return;\n }\n\n const registeredHandler = this.hookHandlers.get(tool);\n\n if (registeredHandler) {\n await registeredHandler(payload);\n return;\n }\n\n const alreadyNormalizedEvent = AISnitchEventSchema.safeParse(payload);\n\n if (alreadyNormalizedEvent.success) {\n await this.publishEvent(alreadyNormalizedEvent.data);\n return;\n }\n\n const normalizedHook = HookIngressPayloadSchema.safeParse(payload);\n\n if (!normalizedHook.success) {\n logger.warn(\n {\n tool,\n issues: normalizedHook.error.issues,\n },\n 'Unable to normalize hook payload',\n );\n return;\n }\n\n const resolvedSessionId = resolveSessionId({\n activeFile: normalizedHook.data.data?.activeFile,\n cwd: normalizedHook.data.data?.cwd ?? normalizedHook.data.cwd,\n pid: normalizedHook.data.pid,\n project: normalizedHook.data.data?.project,\n projectPath: normalizedHook.data.data?.projectPath,\n sessionId: normalizedHook.data.sessionId,\n tool,\n transcriptPath: normalizedHook.data.transcriptPath,\n });\n const event = createEvent({\n source: normalizedHook.data.source ?? `aisnitch://hooks/${tool}`,\n type: normalizedHook.data.type,\n 'aisnitch.tool': tool,\n 'aisnitch.sessionid': resolvedSessionId,\n 'aisnitch.seqnum': normalizedHook.data.seqnum ?? 1,\n data: {\n ...normalizedHook.data.data,\n cwd:\n normalizedHook.data.data?.cwd ??\n normalizedHook.data.cwd,\n },\n });\n\n await this.publishEvent(event, {\n pid: normalizedHook.data.pid,\n env: normalizedHook.data.env,\n sessionId: resolvedSessionId,\n transcriptPath: normalizedHook.data.transcriptPath,\n hookPayload:\n normalizedHook.data.hookPayload ??\n (this.isPlainRecord(payload) ? payload : undefined),\n });\n }\n\n private isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n}\n","import type { AISnitchEvent, AISnitchEventType, CESPCategory } from './types.js';\n\n/**\n * @file src/core/events/cesp.ts\n * @description CESP compatibility helpers for mapping normalized AISnitch events into legacy categories.\n * @functions\n * โ†’ getCESPCategory\n * @exports CESP_MAP, getCESPCategory\n * @see ./types.ts\n */\n\n/**\n * ๐Ÿ“– Some normalized states have no direct CESP equivalent. Returning `null`\n * makes that gap explicit instead of inventing fake sound-pack categories.\n */\nexport const CESP_MAP: Record<AISnitchEventType, CESPCategory | null> = {\n 'session.start': 'session.start',\n 'session.end': 'session.end',\n 'task.start': 'task.acknowledge',\n 'task.complete': 'task.complete',\n 'agent.thinking': null,\n 'agent.coding': null,\n 'agent.tool_call': null,\n 'agent.streaming': null,\n 'agent.asking_user': 'input.required',\n 'agent.idle': null,\n 'agent.error': 'task.error',\n 'agent.compact': 'resource.limit',\n};\n\n/**\n * Resolves the CESP category for either a full event object or an event type.\n */\nexport function getCESPCategory(\n eventOrType: AISnitchEvent | AISnitchEventType,\n): CESPCategory | null {\n const eventType =\n typeof eventOrType === 'string' ? eventOrType : eventOrType.type;\n\n return CESP_MAP[eventType];\n}\n","/**\n * @file src/core/timeout.ts\n * @description Async operation timeout wrappers to prevent indefinite blocking.\n *\n * AISnitch processes many async operations (file reads, HTTP requests, process\n * detection, file watchers, adapter startup/shutdown). Without explicit timeouts,\n * any of these can block the entire daemon indefinitely if the underlying resource\n * becomes unresponsive (e.g., NFS mount stuck, disk I/O stalled, external API hanging).\n *\n * This module provides:\n * - `withTimeout()` โ€” race a promise against a deadline\n * - `TimeoutError` โ€” typed error thrown on timeout\n * - `DEFAULT_TIMEOUTS` โ€” sane defaults per operation type\n *\n * Usage:\n * ```typescript\n * // Fail-fast: don't wait more than 3s for a file read\n * const content = await withTimeout(\n * readFile('/path/to/transcript.jsonl', 'utf8'),\n * 3_000,\n * 'claude-transcript-read'\n * );\n * ```\n *\n * @functions\n * โ†’ withTimeout\n * โ†’ DEFAULT_TIMEOUTS\n * @exports DEFAULT_TIMEOUTS, withTimeout\n * @see ./errors.ts (TimeoutError)\n * @see ./graceful-shutdown.ts\n */\n\nimport { TimeoutError } from './errors.js';\nimport { logger } from './engine/logger.js';\n\n/**\n * Named timeout windows for common AISnitch operations.\n *\n * These defaults are conservative but reasonable for local development:\n * - File operations: fast on local SSDs, need headroom for larger logs\n * - HTTP requests: generous (30s) because AI tool hooks can be slow\n * - Process detection: frequent polling, keep each poll short\n * - Adapter lifecycle: moderate (10s) for graceful shutdowns\n *\n * Override per-call via the `withTimeout()` `timeoutMs` parameter.\n */\nexport const DEFAULT_TIMEOUTS = Object.freeze({\n /**\n * File read/write operations (JSONL transcripts, config files).\n * Default: 5 seconds\n */\n fileOperation: 5_000,\n\n /**\n * HTTP requests to health endpoint or external APIs.\n * Default: 30 seconds\n */\n httpRequest: 30_000,\n\n /**\n * Process detection commands (`pgrep`, `ps aux`).\n * Default: 3 seconds\n */\n processDetection: 3_000,\n\n /**\n * Adapter startup (file watchers, hook bridges, pollers).\n * Default: 10 seconds\n */\n adapterStartup: 10_000,\n\n /**\n * Adapter shutdown (graceful cleanup, watcher close).\n * Default: 5 seconds โ€” after this, resources are force-closed\n */\n adapterShutdown: 5_000,\n\n /**\n * Daemon graceful shutdown (stop all components in order).\n * Default: 30 seconds\n */\n daemonShutdown: 30_000,\n\n /**\n * WebSocket connection establishment.\n * Default: 10 seconds\n */\n wsConnection: 10_000,\n\n /**\n * Overall pipeline start (all components).\n * Default: 15 seconds\n */\n pipelineStartup: 15_000,\n} as const);\n\n/**\n * Type representing the keys of `DEFAULT_TIMEOUTS`.\n */\nexport type TimeoutName = keyof typeof DEFAULT_TIMEOUTS;\n\n/**\n * Races a promise against a deadline.\n *\n * If the promise resolves first, returns the resolved value.\n * If the timeout fires first, throws a `TimeoutError`.\n *\n * The timeout is implemented via `Promise.race()` so it does not\n * forcefully abort the underlying promise โ€” the promise continues\n * running in the background. For truly cancellable operations,\n * consider `AbortController` in addition to this utility.\n *\n * @example\n * ```typescript\n * try {\n * const result = await withTimeout(\n * fetch('http://example.com/slow-endpoint'),\n * 5_000,\n * 'external-api-call'\n * );\n * return await result.json();\n * } catch (error) {\n * if (error instanceof TimeoutError) {\n * logger.warn({ context: error.context }, 'Operation timed out');\n * return null;\n * }\n * throw error;\n * }\n * ```\n *\n * @param promise - The async operation to race\n * @param timeoutMs - Maximum time to wait in milliseconds\n * @param context - Human-readable label for logging and error context\n * @returns The resolved value if `promise` wins the race\n * @throws TimeoutError if the timeout fires first\n */\nexport function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n context: string,\n): Promise<T> {\n if (timeoutMs <= 0) {\n // Immediately reject invalid timeouts rather than silently hanging\n throw new TimeoutError(\n `Invalid timeout value: ${timeoutMs}ms (must be > 0)`,\n 'TIMEOUT_INVALID_VALUE',\n { context, timeoutMs },\n );\n }\n\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n const timeoutId = setTimeout(() => {\n reject(\n new TimeoutError(\n `Operation exceeded ${timeoutMs}ms deadline`,\n 'TIMEOUT_EXCEEDED',\n { context, timeoutMs },\n ),\n );\n }, timeoutMs);\n\n // Allow the timeout to be garbage-collected if the promise resolves\n timeoutId.unref();\n }),\n ]);\n}\n\n/**\n * Wraps a promise with a timeout and logs a warning if it times out.\n * Unlike `withTimeout()`, this never throws โ€” it falls through to the\n * original promise's result (or error) if the timeout fires first.\n *\n * Best-effort: useful for non-critical background operations where a\n * timeout should log a warning but not crash the flow.\n *\n * @example\n * ```typescript\n * // Log a warning but don't fail if process detection hangs\n * await timeoutWarning(\n * listProcesses(processListCommand),\n * DEFAULT_TIMEOUTS.processDetection,\n * 'claude-process-detection'\n * );\n * ```\n */\nexport async function timeoutWarning<T>(\n promise: Promise<T>,\n timeoutMs: number,\n context: string,\n): Promise<T> {\n try {\n return await withTimeout(promise, timeoutMs, context);\n } catch (error) {\n if (error instanceof TimeoutError) {\n logger.warn(\n { context: error.context, timeoutMs: error.context },\n `Best-effort operation timed out after ${timeoutMs}ms`,\n );\n // Fall through: the original promise may still resolve (fire-and-forget)\n // Return a rejected promise so the caller can handle it if needed\n return await promise;\n }\n\n throw error;\n }\n}\n\n/**\n * Gets the timeout value for a named operation.\n *\n * @example\n * ```typescript\n * const timeoutMs = getTimeout('adapterShutdown');\n * // โ†’ 5_000\n * ```\n */\nexport function getTimeout(name: TimeoutName): number {\n return DEFAULT_TIMEOUTS[name];\n}\n\n/**\n * Checks whether an error is a TimeoutError.\n * Shorthand for `error instanceof TimeoutError` with explicit return type.\n */\nexport function isTimeoutError(error: unknown): error is TimeoutError {\n return error instanceof TimeoutError;\n}\n","/**\n * @file src/core/graceful-shutdown.ts\n * @description Graceful shutdown coordination to prevent orphaned resources and partial state.\n *\n * Graceful shutdown is critical for a long-running daemon like AISnitch:\n * - **No orphaned servers**: HTTP/WebSocket/UDS servers must be closed cleanly\n * - **No resource leaks**: file watchers, pollers, timers must be stopped\n * - **Clean PID files**: stale PID files confuse subsequent launches\n * - **Clean state files**: daemon-state.json must be removed on exit\n *\n * This module provides:\n * - `withShutdownTimeout()` โ€” wrap a shutdown function with a deadline\n * - `shutdownInOrder()` โ€” stop components in reverse dependency order\n * - `GracefulShutdownManager` โ€” coordinates all shutdown signals (SIGTERM, SIGINT, SIGHUP)\n *\n * ## Shutdown order for AISnitch pipeline\n *\n * ```\n * 1. adapters.stopAll() โ€” stop watching files, kill pollers, close watchers\n * 2. httpReceiver.stop() โ€” close HTTP server\n * 3. udsServer.stop() โ€” close Unix Domain Socket\n * 4. wsServer.stop() โ€” close WebSocket server (consumers get disconnected)\n * 5. eventBus.unsubscribeAll() โ€” remove all listeners\n * 6. cleanup PID/state files โ€” prevent stale state on next launch\n * ```\n *\n * @functions\n * โ†’ withShutdownTimeout\n * โ†’ shutdownInOrder\n * @exports GracefulShutdownManager, ShutdownComponents, withShutdownTimeout, shutdownInOrder\n * @see ./errors.ts (TimeoutError)\n * @see ./timeout.ts (DEFAULT_TIMEOUTS)\n * @see ../cli/runtime.ts (shutdown orchestration)\n */\n\nimport { isTimeoutError, withTimeout } from './timeout.js';\nimport { logger } from './engine/logger.js';\nimport { DEFAULT_TIMEOUTS } from './timeout.js';\n\n/**\n * All AISnitch components that participate in graceful shutdown.\n * Stopped in reverse dependency order (last-started = first-stopped).\n */\nexport interface ShutdownComponents {\n readonly adapterRegistry?: {\n stopAll: () => Promise<void>;\n };\n readonly httpReceiver?: {\n stop: () => Promise<void>;\n };\n readonly udsServer?: {\n stop: () => Promise<void>;\n };\n readonly wsServer?: {\n stop: () => Promise<void>;\n };\n readonly eventBus?: {\n unsubscribeAll: () => void;\n };\n readonly cleanupFns?: ReadonlyArray<() => Promise<void> | void>;\n}\n\n/**\n * Wraps an async shutdown operation with a deadline.\n *\n * If the shutdown completes within `timeoutMs`, returns normally.\n * If the timeout fires first, logs a warning and continues (forces through).\n *\n * This ensures that a misbehaving component can never indefinitely block\n * daemon shutdown and leave the system in a half-dead state.\n *\n * @example\n * ```typescript\n * await withShutdownTimeout(\n * () => adapter.stop(),\n * DEFAULT_TIMEOUTS.adapterShutdown,\n * 'ClaudeCodeAdapter'\n * );\n * ```\n *\n * @param fn - Async shutdown function to execute\n * @param timeoutMs - Maximum time to wait in milliseconds\n * @param component - Human-readable name for logging\n */\nexport async function withShutdownTimeout(\n fn: () => Promise<void>,\n timeoutMs: number,\n component: string,\n): Promise<void> {\n if (timeoutMs <= 0) {\n // Execute without timeout if 0 or negative is passed (tests, forced shutdown)\n await fn();\n return;\n }\n\n const timeoutPromise = new Promise<'timed_out' | 'completed'>((resolve) => {\n setTimeout(() => {\n resolve('timed_out');\n }, timeoutMs).unref();\n });\n\n const result = await Promise.race([\n fn().then(() => 'completed' as const),\n timeoutPromise,\n ]);\n\n if (result === 'timed_out') {\n logger.warn(\n { component, timeoutMs },\n `Graceful shutdown exceeded ${timeoutMs}ms timeout โ€” forcing through`,\n );\n }\n}\n\n/**\n * Stops AISnitch components in safe reverse-dependency order with individual timeouts.\n *\n * ## Why reverse order?\n *\n * The pipeline starts: adapters โ†’ HTTP โ†’ UDS โ†’ WS โ†’ eventBus\n * If we stop WS before HTTP, new connections keep arriving at HTTP.\n * If we stop eventBus before WS, consumers get events from the bus but can't send them.\n * Therefore, stop in reverse: eventBus โ†’ WS โ†’ UDS โ†’ HTTP โ†’ adapters.\n *\n * @example\n * ```typescript\n * await shutdownInOrder(\n * {\n * eventBus: pipeline.getEventBus(),\n * wsServer: pipeline.getWSServer(),\n * httpReceiver: pipeline.getHTTPReceiver(),\n * udsServer: pipeline.getUDSServer(),\n * adapterRegistry: pipeline.getAdapterRegistry(),\n * cleanupFns: [\n * () => removePid(pathOptions),\n * () => removeDaemonState(pathOptions),\n * ],\n * },\n * {\n * eventBus: 1_000,\n * wsServer: 3_000,\n * httpReceiver: 2_000,\n * udsServer: 2_000,\n * adapterRegistry: 5_000,\n * },\n * 'AISnitch pipeline'\n * );\n * ```\n *\n * @param components - Components to shut down\n * @param timeouts - Per-component timeout in milliseconds\n * @param label - Human-readable label for logging\n */\nexport async function shutdownInOrder(\n components: ShutdownComponents,\n timeouts: Partial<Record<keyof ShutdownComponents, number>>,\n label: string,\n): Promise<void> {\n const getTimeout = (key: keyof ShutdownComponents): number => {\n return timeouts[key] ?? DEFAULT_TIMEOUTS.daemonShutdown;\n };\n\n const stopSafely = async (\n key: keyof ShutdownComponents,\n fn: () => Promise<void>,\n ): Promise<void> => {\n const timeoutMs = getTimeout(key);\n\n try {\n await withShutdownTimeout(fn, timeoutMs, `${label}.${key}`);\n } catch (error) {\n // Log but never re-throw โ€” one broken component must not abort the rest\n logger.warn(\n { error, key, label },\n `Error during shutdown of ${key} โ€” continuing with remaining components`,\n );\n }\n };\n\n // Shutdown in reverse dependency order\n if (components.cleanupFns) {\n for (const cleanupFn of components.cleanupFns) {\n try {\n await withShutdownTimeout(\n async () => {\n const result = cleanupFn();\n if (result instanceof Promise) {\n await result;\n }\n },\n 1_000,\n `${label}.cleanup`,\n );\n } catch (error) {\n logger.warn({ error, label }, 'Cleanup function failed');\n }\n }\n }\n\n if (components.eventBus) {\n components.eventBus.unsubscribeAll();\n }\n\n await stopSafely('wsServer', () => components.wsServer!.stop());\n\n await stopSafely('udsServer', () => components.udsServer!.stop());\n\n await stopSafely('httpReceiver', () => components.httpReceiver!.stop());\n\n if (components.adapterRegistry) {\n await stopSafely('adapterRegistry', () => components.adapterRegistry!.stopAll());\n }\n}\n\n/**\n * Coordinates all shutdown signals (SIGTERM, SIGINT, SIGHUP) for a process.\n *\n * ## Why a manager class?\n *\n * - Multiple signals can arrive in quick succession (e.g., SIGTERM then SIGINT)\n * - Handlers must be idempotent (second call does nothing)\n * - The manager tracks whether shutdown is already in progress\n * - It ensures the main process exits with the correct exit code\n *\n * @example\n * ```typescript\n * const manager = new GracefulShutdownManager({\n * onShutdown: async (signal) => {\n * await shutdownInOrder(pipeline, timeouts, 'pipeline');\n * await cleanupFiles(pathOptions);\n * },\n * signal: 'SIGTERM',\n * });\n *\n * process.on('SIGTERM', manager.handler);\n * process.on('SIGINT', manager.handler);\n *\n * // Call handler manually to trigger shutdown from anywhere\n * await manager.shutdown('manual-trigger');\n * ```\n */\nexport class GracefulShutdownManager {\n private shuttingDown = false;\n\n private readonly pendingHandlers = new Set<() => void>();\n\n /**\n * Creates a new shutdown manager.\n *\n * @param options - Configuration options\n * @param options.onShutdown - Async function called when shutdown is triggered\n * @param options.exitCode - Exit code to use (default: 0 for graceful, 1 for errors)\n * @param options.exitDelayMs - Delay before `process.exit()` (default: 100ms for flush)\n */\n public constructor(\n private readonly options: {\n readonly onShutdown: (signal: string) => Promise<void>;\n readonly exitCode?: number;\n readonly exitDelayMs?: number;\n },\n ) {}\n\n /**\n * Synchronous handler function suitable for `process.on()`.\n *\n * Multiple calls are safe โ€” only the first call executes `onShutdown`.\n * Subsequent calls queue to the internal pending set and run after the\n * first shutdown completes.\n */\n public get handler(): (signal: string) => void {\n return (signal: string) => {\n if (!this.shuttingDown) {\n this.shuttingDown = true;\n void this.runShutdown(signal);\n } else {\n // Queue additional signals to run after current shutdown finishes\n this.pendingHandlers.add(() => {\n void this.runShutdown(signal);\n });\n }\n };\n }\n\n /**\n * Manually triggers shutdown from async code (e.g., TUI quit button).\n *\n * @param signal - Signal name (for logging)\n */\n public shutdown(signal = 'manual'): void {\n this.handler(signal);\n }\n\n /**\n * Returns whether shutdown is currently in progress.\n */\n public isShuttingDown(): boolean {\n return this.shuttingDown;\n }\n\n private async runShutdown(signal: string): Promise<void> {\n const exitCode = this.options.exitCode ?? (signal === 'uncaughtException' || signal === 'unhandledRejection' ? 1 : 0);\n const exitDelayMs = this.options.exitDelayMs ?? 100;\n\n try {\n await this.options.onShutdown(signal);\n } catch (error) {\n logger.error(\n { error, signal },\n 'Error during graceful shutdown โ€” forcing exit',\n );\n } finally {\n // Allow buffered logs to flush before exiting\n await new Promise<void>((resolve) => {\n setTimeout(resolve, exitDelayMs).unref();\n });\n\n // Run any pending handlers from queued signals before we exit\n for (const pendingHandler of this.pendingHandlers) {\n pendingHandler();\n }\n\n process.exit(exitCode);\n }\n }\n}\n\n/**\n * Wraps a shutdown promise with an overall deadline.\n * If the overall shutdown exceeds the deadline, forces the process to exit.\n *\n * This is the last resort: no shutdown operation should ever take this long,\n * but a runaway deadlock could theoretically block forever without it.\n *\n * @example\n * ```typescript\n * const shutdownComplete = shutdownInOrder(components, timeouts, 'pipeline');\n * await withOverallShutdownTimeout(shutdownComplete, DEFAULT_TIMEOUTS.daemonShutdown, 'AISnitch');\n * ```\n */\nexport async function withOverallShutdownTimeout(\n shutdownPromise: Promise<void>,\n timeoutMs: number,\n label: string,\n): Promise<void> {\n try {\n await withTimeout(shutdownPromise, timeoutMs, `${label}-overall-shutdown`);\n } catch (error) {\n if (isTimeoutError(error)) {\n logger.error(\n { timeoutMs, label },\n `Overall shutdown timeout exceeded โ€” forcing process exit`,\n );\n }\n\n // Always exit after an overall timeout, regardless of error\n process.exit(1);\n }\n}\n","/**\n * @file src/core/result.ts\n * @description Simple Result type for explicit error handling without relying on try/catch.\n *\n * This is a lightweight alternative to fp-ts Either for cases where you want to force\n * callers to handle the error case explicitly but don't need the full fp-ts ecosystem.\n *\n * The `Result<T, E>` type has two states:\n * - `{ success: true, value: T }` โ€” operation succeeded with a value\n * - `{ success: false, error: E }` โ€” operation failed with an error\n *\n * Usage pattern:\n * ```typescript\n * function parseConfig(raw: unknown): Result<AISnitchConfig, ValidationError> {\n * const result = ConfigSchema.safeParse(raw);\n * if (!result.success) {\n * return err(new ValidationError(\n * 'Invalid config', 'VALIDATION_CONFIG_INVALID',\n * { issues: result.error.issues }\n * ));\n * }\n * return ok(result.data);\n * }\n *\n * // Caller must handle both cases\n * const result = parseConfig(raw);\n * if (isErr(result)) {\n * logger.error({ error: result.error }, 'Config parsing failed');\n * return;\n * }\n * // result.value is guaranteed to exist here\n * useConfig(result.value);\n * ```\n *\n * @functions\n * โ†’ ok\n * โ†’ err\n * โ†’ isOk\n * โ†’ isErr\n * โ†’ mapOk\n * โ†’ mapErr\n * โ†’ flatMap\n * โ†’ fromPromise\n * @exports Result, ok, err, isOk, isErr, mapOk, mapErr, flatMap, fromPromise\n * @see ./errors.ts\n * @see ./retry.ts\n */\n\n/**\n * Discriminated union representing either a successful value or a failure error.\n *\n * @typeParam T - The success value type\n * @typeParam E - The error type (defaults to `Error`)\n */\nexport type Result<T, E = Error> =\n | { readonly success: true; readonly value: T }\n | { readonly success: false; readonly error: E };\n\n/**\n * Narrowing type guard for the success case.\n *\n * @example\n * ```typescript\n * const result = maybeDoSomething();\n * if (isOk(result)) {\n * console.log(result.value); // TypeScript knows result.value exists\n * }\n * ```\n */\nexport function isOk<T, E>(result: Result<T, E>): result is { success: true; value: T } {\n return result.success === true;\n}\n\n/**\n * Narrowing type guard for the error case.\n *\n * @example\n * ```typescript\n * const result = maybeDoSomething();\n * if (isErr(result)) {\n * console.error(result.error); // TypeScript knows result.error exists\n * }\n * ```\n */\nexport function isErr<T, E>(result: Result<T, E>): result is { success: false; error: E } {\n return result.success === false;\n}\n\n/**\n * Constructs a successful result with a value.\n *\n * @example\n * ```typescript\n * const result = ok({ userId: 42, name: 'Alice' });\n * // { success: true, value: { userId: 42, name: 'Alice' } }\n * ```\n */\nexport function ok<T>(value: T): Result<T, never> {\n return Object.freeze({ success: true, value });\n}\n\n/**\n * Constructs a failed result with an error.\n *\n * @example\n * ```typescript\n * const result = err(new Error('Not found'));\n * // { success: false, error: Error('Not found') }\n * ```\n */\nexport function err<E extends Error = Error>(error: E): Result<never, E> {\n return Object.freeze({ success: false, error });\n}\n\n/**\n * Maps the success value through a transformation function.\n * Errors pass through unchanged.\n *\n * @example\n * ```typescript\n * const result: Result<User, Error> = ok({ id: 1, name: 'Alice' });\n * const mapped = mapOk(result, (user) => user.name.toUpperCase());\n * // { success: true, value: 'ALICE' }\n * ```\n */\nexport function mapOk<T, E, U>(\n result: Result<T, E>,\n fn: (value: T) => U,\n): Result<U, E> {\n if (!result.success) {\n // TypeScript needs this cast because it can't narrow both union branches at once\n return result as unknown as Result<U, E>;\n }\n\n return ok(fn(result.value));\n}\n\n/**\n * Maps the error value through a transformation function.\n * Success values pass through unchanged.\n *\n * @example\n * ```typescript\n * const result: Result<User, Error> = err(new Error('original'));\n * const mapped = mapErr(result, (error) => new CustomError(error.message));\n * // { success: false, error: CustomError('original') }\n * ```\n */\nexport function mapErr<T, E, F extends Error>(\n result: Result<T, E>,\n fn: (error: E) => F,\n): Result<T, F> {\n if (result.success) {\n return result as unknown as Result<T, F>;\n }\n\n return err(fn(result.error));\n}\n\n/**\n * Chains Result operations: if the first Result succeeds, apply `fn` to its value.\n * If it fails, propagate the error without calling `fn`.\n *\n * @example\n * ```typescript\n * const result = await flatMap(\n * await parseConfig(raw),\n * (config) => validateAdapters(config.adapters)\n * );\n * // Either returns parseConfig's error, or the error from validateAdapters\n * ```\n */\nexport async function flatMap<T, E, U, F extends Error>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, F> | Promise<Result<U, F>>,\n): Promise<Result<U, E | F>> {\n if (!result.success) {\n return result as unknown as Result<U, E | F>;\n }\n\n const mapped = await fn(result.value);\n\n if (!mapped.success) {\n return mapped as unknown as Result<U, E | F>;\n }\n\n return ok(mapped.value);\n}\n\n/**\n * Converts a Promise to a Result, catching errors automatically.\n * Rejections become `{ success: false, error: E }`.\n *\n * @example\n * ```typescript\n * const result = await fromPromise(\n * fetch('http://127.0.0.1:4821/health'),\n * (error) => new NetworkError(\n * 'Health check failed',\n * 'NETWORK_HTTP_CONNECT_FAILED',\n * { cause: error }\n * )\n * );\n * if (isErr(result)) {\n * logger.warn({ error: result.error }, 'Daemon health check failed');\n * return null;\n * }\n * const health = await result.value.json();\n * ```\n */\nexport async function fromPromise<T, E extends Error>(\n promise: Promise<T>,\n mapError: (reason: unknown) => E,\n): Promise<Result<T, E>> {\n try {\n const value = await promise;\n return ok(value);\n } catch (reason) {\n return err(mapError(reason));\n }\n}\n\n/**\n * Synchronous version of `fromPromise` for non-async functions.\n *\n * @example\n * ```typescript\n * const result = fromSync(() => JSON.parse(rawJson), (e) =>\n * new ValidationError('Invalid JSON', 'VALIDATION_JSON_PARSE', { cause: e })\n * );\n * ```\n */\nexport function fromSync<T, E extends Error>(\n fn: () => T,\n mapError: (reason: unknown) => E,\n): Result<T, E> {\n try {\n return ok(fn());\n } catch (reason) {\n return err(mapError(reason));\n }\n}\n","/**\n * @file src/core/retry.ts\n * @description Exponential backoff retry utilities for transient operations.\n *\n * Retry logic is essential for resilience against:\n * - Network flakiness (connection refused, timeouts, DNS failures)\n * - Transient file-system contention (file locked, directory not ready)\n * - External API rate limits (backoff on 429 Too Many Requests)\n *\n * This module provides:\n * - `withRetry()` โ€” async function with exponential backoff\n * - `RetryOptions` โ€” configurable retry parameters\n * - `DefaultRetryOptions` โ€” sensible defaults for AISnitch workloads\n *\n * Usage:\n * ```typescript\n * const result = await withRetry(\n * () => fetchHealth(daemonPort),\n * {\n * attempts: 3,\n * delayMs: 500,\n * backoff: 2,\n * context: 'daemon-health-check',\n * }\n * );\n * ```\n *\n * @functions\n * โ†’ withRetry\n * โ†’ sleep\n * โ†’ DefaultRetryOptions\n * @exports RetryOptions, DefaultRetryOptions, withRetry, sleep\n * @see ./errors.ts\n * @see ./result.ts\n */\n\nimport { logger } from './engine/logger.js';\nimport { isRetryableError } from './errors.js';\n\n/**\n * Configuration for retry behaviour.\n */\nexport interface RetryOptions {\n /**\n * Maximum number of attempts before giving up.\n * @default 3\n */\n readonly attempts: number;\n\n /**\n * Initial delay in milliseconds between retries.\n * @default 500\n */\n readonly delayMs: number;\n\n /**\n * Multiplicative factor for delay after each attempt.\n * @default 2\n */\n readonly backoff: number;\n\n /**\n * Maximum total time in milliseconds across all retries.\n * @default 30_000\n */\n readonly maxTotalDelayMs: number;\n\n /**\n * Human-readable label used in log messages for traceability.\n */\n readonly context: string;\n\n /**\n * Optional predicate to filter which errors trigger a retry.\n * By default, `isRetryableError()` is used.\n * Return `true` to retry, `false` to give up immediately.\n */\n readonly shouldRetry?: (error: unknown) => boolean;\n\n /**\n * Set to `true` to jitter the delay slightly (ยฑ25%) to avoid thundering herd.\n * @default true\n */\n readonly jitter?: boolean;\n}\n\n/**\n * Sensible defaults tuned for AISnitch workloads:\n * - Quick first retry (500ms) for responsiveness\n * - Exponential backoff to back off gracefully\n * - 3 attempts to avoid long stalls\n * - Jitter enabled to spread load\n */\nexport const DefaultRetryOptions: Readonly<RetryOptions> = {\n attempts: 3,\n backoff: 2,\n context: 'unknown',\n delayMs: 500,\n jitter: true,\n maxTotalDelayMs: 30_000,\n shouldRetry: isRetryableError,\n};\n\n/**\n * Blocks the current async execution for the given number of milliseconds.\n *\n * @example\n * ```typescript\n * await sleep(1000); // wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms).unref();\n });\n}\n\n/**\n * Calculates the actual delay for a given attempt, applying jitter when enabled.\n */\nfunction computeDelay(\n attempt: number,\n baseDelayMs: number,\n backoff: number,\n jitter: boolean,\n): number {\n // Exponential backoff: baseDelay * backoff^(attempt-1)\n const exponentialDelay = baseDelayMs * Math.pow(backoff, attempt - 1);\n\n if (!jitter) {\n return exponentialDelay;\n }\n\n // Jitter: ยฑ25% of the delay to avoid thundering herd\n const jitterFactor = 0.75 + Math.random() * 0.5;\n return Math.round(exponentialDelay * jitterFactor);\n}\n\n/**\n * Wraps an async operation with exponential-backoff retry logic.\n *\n * ## How it works\n *\n * 1. Executes `fn` immediately (no initial delay)\n * 2. If it succeeds โ†’ returns the result\n * 3. If it throws and `shouldRetry(error)` returns `true` and attempts remain:\n * - Logs a warning at attempt level (warn) and at failure level (error)\n * - Waits `delayMs * backoff^attempt` milliseconds (with optional jitter)\n * - Repeats from step 1\n * 4. If it throws and `shouldRetry(error)` returns `false` โ†’ throws immediately\n * 5. If all attempts are exhausted โ†’ throws the last error\n *\n * ## When NOT to use this\n *\n * - **Permanent failures** (e.g., validation errors, missing required files)\n * โ†’ Use `isRetryableError()` to filter these out automatically\n * - **Operations that are not idempotent** โ†’ only retry if `fn` is safe to re-execute\n * - **User-facing latency-sensitive paths** โ†’ use a shorter `delayMs` and fewer `attempts`\n *\n * @example\n * ```typescript\n * // Retry a flaky health check up to 3 times\n * const health = await withRetry(\n * () => fetch('http://127.0.0.1:4821/health').then(r => r.json()),\n * {\n * ...DefaultRetryOptions,\n * context: 'daemon-health-check',\n * }\n * );\n * ```\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> & { context: string },\n): Promise<T> {\n const {\n attempts = DefaultRetryOptions.attempts,\n backoff = DefaultRetryOptions.backoff,\n delayMs = DefaultRetryOptions.delayMs,\n maxTotalDelayMs = DefaultRetryOptions.maxTotalDelayMs,\n jitter = DefaultRetryOptions.jitter,\n shouldRetry = DefaultRetryOptions.shouldRetry,\n } = options;\n\n let lastError: unknown;\n let totalDelayMs = 0;\n const shouldRetryWithDefault = shouldRetry ?? DefaultRetryOptions.shouldRetry!;\n\n for (let attempt = 1; attempt <= attempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n\n const retryable = shouldRetryWithDefault(error);\n const attemptsRemaining = attempt < attempts;\n\n if (!retryable || !attemptsRemaining) {\n // Non-retryable error or last attempt โ†’ propagate\n if (!retryable) {\n logger.debug(\n { attempt, context: options.context, error },\n 'Non-retryable error โ€” giving up immediately',\n );\n } else {\n logger.error(\n { attempt, attempts, context: options.context, error },\n 'All retry attempts exhausted',\n );\n }\n\n throw error;\n }\n\n const delay = computeDelay(attempt, delayMs, backoff, jitter ?? false);\n totalDelayMs += delay;\n\n if (totalDelayMs > maxTotalDelayMs) {\n logger.warn(\n { attempt, delay, totalDelayMs, maxTotalDelayMs, context: options.context },\n 'Retry max total delay exceeded โ€” giving up',\n );\n throw lastError;\n }\n\n logger.debug(\n { attempt, attempts, delay, nextDelayMs: delay, context: options.context },\n `Operation failed โ€” retrying in ${delay}ms`,\n );\n\n await sleep(delay);\n }\n }\n\n // Should never reach here, but TypeScript needs it\n throw lastError;\n}\n\n/**\n * Convenience wrapper for fire-and-forget retries (no return value needed).\n * Logs failures but never throws โ€” useful for non-critical background tasks.\n *\n * @example\n * ```typescript\n * // Best-effort metric reporting โ€” don't fail the main flow\n * fireAndForgetRetry(\n * () => sendMetrics(metrics),\n * { context: 'metrics-report', attempts: 2 }\n * );\n * ```\n */\nexport function fireAndForgetRetry<T>(\n fn: () => Promise<T>,\n options: Partial<RetryOptions> & { context: string },\n): void {\n void withRetry(fn, {\n ...options,\n attempts: options.attempts ?? 2,\n }).catch((error) => {\n logger.warn(\n { error, context: options.context },\n 'Fire-and-forget retry also failed โ€” giving up silently',\n );\n });\n}\n\n/**\n * Builds a retry-enabled version of any async function.\n * The returned function will automatically retry on retryable errors.\n *\n * @example\n * ```typescript\n * const safeReadFile = withRetryOn(\n * (path: string) => readFile(path, 'utf8'),\n * { attempts: 3, delayMs: 200, context: 'file-read' }\n * );\n *\n * const content = await safeReadFile('/path/to/file.txt');\n * ```\n */\nexport function withRetryOn<T extends (...args: never[]) => Promise<unknown>>(\n fn: T,\n options: Partial<RetryOptions> & { context: string },\n): T {\n return ((...args: Parameters<T>) => withRetry(() => fn(...args), options)) as T;\n}\n","/**\n * @file src/core/safety.ts\n * @description Type-safe extraction helpers for working with untyped record data.\n *\n * AISnitch often deals with loosely-typed payloads:\n * - Hook payloads from third-party tools (Claude Code, OpenCode, etc.)\n * - JSONL transcript observations parsed from raw JSON\n * - Config files loaded from disk\n * - Event data fields that may be undefined\n *\n * This module provides:\n * - `getString()` / `getNumber()` / `getBoolean()` โ€” safe extractors with type narrowing\n * - `getStringOrDefault()` / `getNumberOrDefault()` โ€” with fallback defaults\n * - `getArray()` / `getObject()` โ€” structural validation\n * - `getSafeInteger()` โ€” integer with bounds checking\n * - `getPositiveNumber()` โ€” positive values only\n * - `isValidPort()` โ€” network port validation (1-65535)\n * - `isValidPathLength()` โ€” POSIX path limit check (4096 chars)\n * - `isValidStringLength()` โ€” max string length check\n *\n * ## Why not just use optional chaining?\n *\n * Optional chaining (`?.`) protects against null/undefined access chains, but it:\n * - Does NOT validate the type of the value (e.g., `obj.key` could be `string | number | null`)\n * - Does NOT enforce constraints (e.g., port range, string max length)\n * - Does NOT normalize values (e.g., trimming strings, clamping numbers)\n *\n * These helpers do all of the above in one call.\n *\n * @functions\n * โ†’ getString\n * โ†’ getNumber\n * โ†’ getBoolean\n * โ†’ getSafeInteger\n * โ†’ getPositiveNumber\n * โ†’ isValidPort\n * โ†’ isValidPathLength\n * โ†’ isValidStringLength\n * โ†’ getArray\n * โ†’ getObject\n * @exports getString, getNumber, getBoolean, getSafeInteger, getPositiveNumber, isValidPort, isValidPathLength, isValidStringLength, getArray, getObject\n * @see ./errors.ts\n * @see ./result.ts\n */\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Constants\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Maximum valid TCP/UDP port number.\n * Ports below 1024 require root privileges on Unix.\n */\nexport const MAX_PORT = 65_535;\n\n/**\n * Minimum valid TCP/UDP port number.\n */\nexport const MIN_PORT = 1;\n\n/**\n * Maximum path length per POSIX (NAME_MAX).\n * Most filesystems support 255 bytes per path component, but the total path\n * can grow much longer. 4096 is a safe upper bound for in-memory validation.\n */\nexport const MAX_PATH_LENGTH = 4_096;\n\n/**\n * Maximum string length for most AISnitch fields (file paths, model names, etc.).\n * Beyond this, truncation or rejection is safer than silent truncation.\n */\nexport const MAX_GENERIC_STRING_LENGTH = 10_000;\n\n/**\n * Maximum length for short labels (tool names, session IDs, event types).\n * These should always be kept short for display.\n */\nexport const MAX_LABEL_LENGTH = 255;\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// String extractors\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a non-empty trimmed string from a record field.\n *\n * @example\n * ```typescript\n * const model = getString(payload, 'model');\n * // โ†’ 'claude-sonnet-4-20250514' | undefined\n * ```\n */\nexport function getString(\n record: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = record[key];\n\n if (typeof value !== 'string') {\n return undefined;\n }\n\n const trimmed = value.trim();\n\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\n/**\n * Extracts a string and enforces a maximum length.\n * If the string exceeds `maxLength`, it is truncated to that length.\n *\n * @example\n * ```typescript\n * const truncated = getStringWithMaxLength(payload, 'errorMessage', 10_000);\n * ```\n */\nexport function getStringWithMaxLength(\n record: Record<string, unknown>,\n key: string,\n maxLength: number,\n): string | undefined {\n const value = getString(record, key);\n\n if (value === undefined) {\n return undefined;\n }\n\n return value.length > maxLength ? value.slice(0, maxLength) : value;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Number extractors\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a finite number from a record field.\n *\n * Filters out `NaN`, `Infinity`, `-Infinity`.\n *\n * @example\n * ```typescript\n * const pid = getNumber(payload, 'pid');\n * // โ†’ 12345 | undefined\n * ```\n */\nexport function getNumber(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = record[key];\n\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return undefined;\n }\n\n return value;\n}\n\n/**\n * Extracts a finite integer within a range.\n *\n * @example\n * ```typescript\n * const seqnum = getSafeInteger(payload, 'seqnum', { min: 1 });\n * // โ†’ 42 | undefined\n * ```\n */\nexport function getSafeInteger(\n record: Record<string, unknown>,\n key: string,\n options: { min?: number; max?: number } = {},\n): number | undefined {\n const value = getNumber(record, key);\n\n if (value === undefined) {\n return undefined;\n }\n\n // Must be an integer (Math.floor === self for whole numbers)\n if (!Number.isInteger(value)) {\n return undefined;\n }\n\n if (options.min !== undefined && value < options.min) {\n return undefined;\n }\n\n if (options.max !== undefined && value > options.max) {\n return undefined;\n }\n\n return value;\n}\n\n/**\n * Extracts a positive number ( > 0).\n *\n * @example\n * ```typescript\n * const tokens = getPositiveNumber(payload, 'tokensUsed');\n * // โ†’ 1500 | undefined (rejects 0, negative)\n * ```\n */\nexport function getPositiveNumber(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = getNumber(record, key);\n\n return value !== undefined && value > 0 ? value : undefined;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Boolean extractor\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a boolean from a record field.\n *\n * Handles the common \"stringified boolean\" pattern where config files\n * or query parameters store booleans as strings ('true', 'false').\n *\n * @example\n * ```typescript\n * const enabled = getBoolean(record, 'enabled');\n * // โ†’ true | false | undefined\n * ```\n */\nexport function getBoolean(\n record: Record<string, unknown>,\n key: string,\n): boolean | undefined {\n const value = record[key];\n\n if (typeof value === 'boolean') {\n return value;\n }\n\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n\n if (lower === 'true' || lower === '1') {\n return true;\n }\n\n if (lower === 'false' || lower === '0') {\n return false;\n }\n }\n\n return undefined;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Structural validators\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts an array from a record field.\n *\n * @example\n * ```typescript\n * const parts = getArray(payload, 'content');\n * // โ†’ unknown[] | undefined\n * ```\n */\nexport function getArray<T = unknown>(\n record: Record<string, unknown>,\n key: string,\n): T[] | undefined {\n const value = record[key];\n\n return Array.isArray(value) ? (value as T[]) : undefined;\n}\n\n/**\n * Extracts a plain object from a record field.\n *\n * Returns `undefined` for arrays, class instances, `null`, primitives.\n *\n * @example\n * ```typescript\n * const toolInput = getObject(payload, 'tool_input');\n * // โ†’ Record<string, unknown> | undefined\n * ```\n */\nexport function getObject(\n record: Record<string, unknown>,\n key: string,\n): Record<string, unknown> | undefined {\n const value = record[key];\n\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return undefined;\n }\n\n return value as Record<string, unknown>;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Common constraint validators\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Validates whether a port number is within the valid TCP/UDP range (1-65535).\n *\n * @example\n * ```typescript\n * const port = getSafeInteger(payload, 'port', { min: 1, max: 65535 });\n * if (isValidPort(port)) {\n * server.listen(port);\n * }\n * ```\n */\nexport function isValidPort(port: number | undefined): port is number {\n return (\n port !== undefined &&\n Number.isInteger(port) &&\n port >= MIN_PORT &&\n port <= MAX_PORT\n );\n}\n\n/**\n * Validates whether a path string is within the POSIX NAME_MAX limit.\n *\n * Uses the conservative 4096-character limit (actual NAME_MAX varies by FS).\n * This check is useful for in-memory validation before file system operations.\n *\n * @example\n * ```typescript\n * const filePath = getString(payload, 'filePath');\n * if (filePath && isValidPathLength(filePath)) {\n * readFile(filePath);\n * }\n * ```\n */\nexport function isValidPathLength(path: string | undefined): path is string {\n return path !== undefined && path.length > 0 && path.length <= MAX_PATH_LENGTH;\n}\n\n/**\n * Validates whether a string does not exceed a maximum length.\n *\n * @example\n * ```typescript\n * const message = getString(payload, 'errorMessage');\n * if (message && isValidStringLength(message, 10_000)) {\n * log(message);\n * }\n * ```\n */\nexport function isValidStringLength(\n value: string | undefined,\n maxLength: number,\n): value is string {\n return value !== undefined && value.length <= maxLength;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Record predicate helpers\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Checks whether a value is a plain object (not null, not array, not class instance).\n *\n * Uses `Object.prototype.toString` to detect class instances:\n * - Plain objects return `'[object Object]'`\n * - Class instances return `'[object ClassName]'`\n *\n * @example\n * ```typescript\n * if (isRecord(payload)) {\n * const value = payload[key]; // TypeScript narrows to Record<string, unknown>\n * }\n * ```\n */\nexport function isRecord(\n value: unknown,\n): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n\n // Exclude class instances (Date, Map, Set, etc.)\n const proto = Object.prototype.toString.call(value);\n return proto === '[object Object]';\n}\n\n/**\n * Type guard to narrow any `unknown` to a non-null value.\n *\n * @example\n * ```typescript\n * const cleaned = value != null ? value : defaultValue;\n * // or using the guard:\n * if (isNotNull(value)) { ... }\n * ```\n */\nexport function isNotNull<T>(value: T): value is T & NonNullable<unknown> {\n return value != null;\n}\n\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n// Bounded value extractors (shortcuts for common patterns)\n// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n\n/**\n * Extracts a port number with full validation (in range, integer, finite).\n *\n * @example\n * ```typescript\n * const port = getPort(record, 'httpPort');\n * // โ†’ 4821 | undefined\n * ```\n */\nexport function getPort(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n const value = getSafeInteger(record, key, { min: MIN_PORT, max: MAX_PORT });\n\n return value;\n}\n\n/**\n * Extracts a sequence number (positive integer >= 1).\n *\n * @example\n * ```typescript\n * const seqnum = getSeqnum(record, 'seqnum');\n * // โ†’ 42 | undefined\n * ```\n */\nexport function getSeqnum(\n record: Record<string, unknown>,\n key: string,\n): number | undefined {\n return getSafeInteger(record, key, { min: 1 });\n}\n","import React from 'react';\nimport { render } from 'ink';\nimport { withFullScreen } from 'fullscreen-ink';\nimport WebSocket from 'ws';\n\nimport { AISNITCH_VERSION } from '../package-info.js';\nimport type { EventBus, PipelineStatus, ToolName } from '../core/index.js';\nimport { App } from './App.js';\nimport { ManagedDaemonApp } from './ManagedDaemonApp.js';\nimport type { ManagedTuiSnapshot, TuiInitialFilters } from './types.js';\n\n/**\n * @file src/tui/index.tsx\n * @description Foreground Ink renderer entrypoint plus barrel exports for TUI modules.\n * @functions\n * โ†’ renderForegroundTui\n * @exports renderForegroundTui and all TUI modules\n * @see ./App.tsx\n * @see ./live-monitor.ts\n * @see ../../tasks/05-tui/01_tui_foundation-layout_DONE.md\n */\n\n/**\n * Props required to render the foreground TUI.\n */\nexport interface ForegroundTuiOptions {\n readonly configuredAdapters: readonly ToolName[];\n readonly eventBus: EventBus;\n readonly initialFilters?: TuiInitialFilters;\n readonly onQuit?: () => void;\n readonly status: PipelineStatus;\n}\n\n/**\n * Props required to render the attached WebSocket TUI.\n */\nexport interface AttachedTuiOptions {\n readonly configuredAdapters: readonly ToolName[];\n readonly initialFilters?: TuiInitialFilters;\n readonly onQuit?: () => void;\n readonly status: {\n readonly consumerCount: number;\n readonly eventCount: number;\n readonly uptimeMs: number;\n };\n readonly wsUrl: string;\n}\n\n/**\n * Props required by the managed daemon dashboard renderer.\n */\nexport interface ManagedTuiOptions {\n readonly initialFilters?: TuiInitialFilters;\n readonly initialSnapshot: ManagedTuiSnapshot;\n readonly onQuit?: () => void;\n readonly refreshSnapshot: () => Promise<ManagedTuiSnapshot>;\n readonly toggleDaemon: () => Promise<ManagedTuiSnapshot>;\n}\n\n/**\n * Renders the foreground Ink TUI and resolves once the app exits.\n */\nexport async function renderForegroundTui(\n options: ForegroundTuiOptions,\n): Promise<void> {\n const ink = withFullScreen(\n <App\n configuredAdapters={options.configuredAdapters}\n initialFilters={options.initialFilters}\n onQuit={options.onQuit}\n source={{\n kind: 'event-bus',\n eventBus: options.eventBus,\n }}\n status={{\n connected: true,\n connectionLabel: 'Foreground Bus',\n consumerCount: options.status.websocket.consumerCount,\n eventCount: options.status.eventBus.publishedEvents,\n uptimeMs: options.status.uptimeMs,\n }}\n version={AISNITCH_VERSION}\n />,\n );\n\n await ink.start();\n await ink.waitUntilExit;\n}\n\n/**\n * Renders the TUI against a remote AISnitch daemon over WebSocket.\n */\nexport async function renderAttachedTui(\n options: AttachedTuiOptions,\n): Promise<void> {\n const socket = new WebSocket(options.wsUrl);\n const app = render(\n <App\n configuredAdapters={options.configuredAdapters}\n initialFilters={options.initialFilters}\n onQuit={options.onQuit}\n source={{\n kind: 'websocket',\n socket,\n }}\n status={{\n connected: true,\n connectionLabel: 'Attached Stream',\n consumerCount: options.status.consumerCount,\n eventCount: options.status.eventCount,\n uptimeMs: options.status.uptimeMs,\n }}\n version={AISNITCH_VERSION}\n />,\n );\n\n try {\n await app.waitUntilExit();\n } finally {\n if (\n socket.readyState === WebSocket.OPEN ||\n socket.readyState === WebSocket.CONNECTING\n ) {\n socket.close();\n }\n }\n}\n\n/**\n * Renders the PM2-style dashboard that can start/stop and attach to the daemon.\n */\nexport async function renderManagedTui(\n options: ManagedTuiOptions,\n): Promise<void> {\n const app = render(\n <ManagedDaemonApp\n initialFilters={options.initialFilters}\n initialSnapshot={options.initialSnapshot}\n onQuit={options.onQuit}\n refreshSnapshot={options.refreshSnapshot}\n toggleDaemon={options.toggleDaemon}\n version={AISNITCH_VERSION}\n />,\n );\n\n await app.waitUntilExit();\n}\n\nexport * from './App.js';\nexport * from './ManagedDaemonApp.js';\nexport * from './types.js';\nexport * from './filters.js';\nexport * from './theme.js';\nexport * from './live-monitor.js';\nexport * from './hooks/useEventStream.js';\nexport * from './hooks/useKeyBinds.js';\nexport * from './hooks/useSessions.js';\nexport * from './components/EventLine.js';\nexport * from './components/EventStream.js';\nexport * from './components/FilterBar.js';\nexport * from './components/GlobalBadge.js';\nexport * from './components/Header.js';\nexport * from './components/HelpOverlay.js';\nexport * from './components/Layout.js';\nexport * from './components/SessionPanel.js';\nexport * from './components/StatusBar.js';\n","import React, { useEffect, useState } from 'react';\nimport { Box, useApp, useStdout } from 'ink';\n\nimport type { ToolName } from '../core/index.js';\nimport { EventInspector } from './components/EventInspector.js';\nimport { EventStream } from './components/EventStream.js';\nimport { FilterBar } from './components/FilterBar.js';\nimport { Header } from './components/Header.js';\nimport { HelpOverlay } from './components/HelpOverlay.js';\nimport { Panel, PanelStack } from './components/Layout.js';\nimport { SessionPanel } from './components/SessionPanel.js';\nimport { StatusBar } from './components/StatusBar.js';\nimport {\n applyEventFilters,\n applySessionFilters,\n countActiveFilters,\n} from './filters.js';\nimport { buildEventInspectorLines } from './event-inspector.js';\nimport { TUI_THEME } from './theme.js';\nimport type { TuiInitialFilters, TuiStatusSnapshot } from './types.js';\nimport {\n getPendingFrozenEventCount,\n getVisibleEventWindow,\n type EventStreamSource,\n useEventStream,\n} from './hooks/useEventStream.js';\nimport { useKeyBinds } from './hooks/useKeyBinds.js';\nimport {\n deriveGlobalActivityStatus,\n useSessions,\n} from './hooks/useSessions.js';\n\n/**\n * @file src/tui/App.tsx\n * @description Root Ink application for the AISnitch terminal UI foundation, including layout chrome and live summary state.\n * @functions\n * โ†’ App\n * @exports App, type AppProps\n * @see ./index.tsx\n * @see ./hooks/useEventStream.ts\n * @see ./components/EventStream.tsx\n * @see ./components/Header.tsx\n * @see ./components/Layout.tsx\n * @see ./components/StatusBar.tsx\n */\n\n/**\n * Props injected by the foreground runtime renderer.\n */\nexport interface AppProps {\n readonly configuredAdapters: readonly ToolName[];\n readonly initialFilters?: TuiInitialFilters;\n readonly managerControls?: {\n readonly onRefreshStatus: () => Promise<void> | void;\n readonly onToggleDaemon: () => Promise<void> | void;\n };\n readonly onQuit?: () => void;\n readonly source: EventStreamSource;\n readonly status: TuiStatusSnapshot;\n readonly version: string;\n}\n\n/**\n * ๐Ÿ“– This first TUI pass focuses on shape and feel: strong header, framed\n * panels, responsive composition, and just enough live state to prove the\n * foreground runtime is now a real terminal app instead of a raw log stream.\n */\nexport function App({\n configuredAdapters,\n initialFilters,\n managerControls,\n onQuit,\n source,\n status,\n version,\n}: AppProps): React.JSX.Element {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const [columns, setColumns] = useState(stdout.columns ?? 80);\n const [rows, setRows] = useState(stdout.rows ?? 24);\n const [inspectorLineOffset, setInspectorLineOffset] = useState(0);\n const [selectedEventIndex, setSelectedEventIndex] = useState<number | null>(\n null,\n );\n const [uptimeMs, setUptimeMs] = useState(status.uptimeMs);\n const initialTuiFilters = {\n eventType: initialFilters?.type ?? null,\n query: initialFilters?.query ?? '',\n tool: initialFilters?.tool ?? null,\n };\n const initialFullDataMode = initialFilters?.view === 'full-data';\n\n useEffect(() => {\n const handleResize = (): void => {\n setColumns(stdout.columns ?? 80);\n setRows(stdout.rows ?? 24);\n };\n\n stdout.on('resize', handleResize);\n\n return () => {\n stdout.off('resize', handleResize);\n };\n }, [stdout]);\n\n const compactLayout = columns < 112;\n const eventStream = useEventStream(\n source,\n {\n initialTotalEvents: status.eventCount,\n visibleCount: compactLayout ? 4 : 6,\n },\n );\n const sessions = useSessions(eventStream.bufferedEvents);\n const [frozenFilteredEventCount, setFrozenFilteredEventCount] = useState<\n number | null\n >(null);\n const inspectorVisibleLineCount = Math.max(\n 10,\n compactLayout ? rows - 22 : rows - 18,\n );\n const keyBinds = useKeyBinds({\n fullDataModeEnabled: initialFullDataMode,\n initialFilters: initialTuiFilters,\n onClearStream: () => {\n eventStream.clearEvents();\n setFrozenFilteredEventCount(null);\n setSelectedEventIndex(null);\n setInspectorLineOffset(0);\n },\n onInspectorPageScroll: (delta) => {\n setInspectorLineOffset((currentValue) =>\n Math.max(0, currentValue + delta * inspectorVisibleLineCount),\n );\n },\n onInspectorScroll: (delta) => {\n setInspectorLineOffset((currentValue) =>\n Math.max(0, currentValue + delta),\n );\n },\n onQuit: () => {\n onQuit?.();\n exit();\n },\n onSelectNextEvent: () => {\n setSelectedEventIndex((currentValue) => {\n if (displayedEvents.length === 0) {\n return null;\n }\n\n return Math.min(\n displayedEvents.length - 1,\n (currentValue ?? displayedEvents.length - 1) + 1,\n );\n });\n },\n onSelectPreviousEvent: () => {\n setSelectedEventIndex((currentValue) => {\n if (displayedEvents.length === 0) {\n return null;\n }\n\n return Math.max(0, (currentValue ?? displayedEvents.length - 1) - 1);\n });\n },\n onToggleFreeze: () => {\n const nextFrozen = !eventStream.isFrozen;\n\n eventStream.toggleFrozen();\n setFrozenFilteredEventCount(nextFrozen ? displayedEvents.length : null);\n },\n onToggleFullDataMode: () => {\n setInspectorLineOffset(0);\n },\n onRefreshStatus: managerControls?.onRefreshStatus,\n onToggleDaemon: managerControls?.onToggleDaemon,\n toolOptions: configuredAdapters,\n });\n const displayedEvents = applyEventFilters(\n eventStream.bufferedEvents,\n keyBinds.filters,\n );\n const fullDataModeEnabled = keyBinds.viewMode === 'full-data';\n const displayedSessions = applySessionFilters(sessions, keyBinds.filters);\n const safeSelectedEventIndex =\n displayedEvents.length === 0\n ? null\n : Math.min(\n selectedEventIndex ?? displayedEvents.length - 1,\n displayedEvents.length - 1,\n );\n const selectedEvent =\n safeSelectedEventIndex === null\n ? null\n : displayedEvents[safeSelectedEventIndex] ?? null;\n const inspectorLines =\n selectedEvent === null ? [] : buildEventInspectorLines(selectedEvent);\n const maxInspectorLineOffset = Math.max(\n 0,\n inspectorLines.length - inspectorVisibleLineCount,\n );\n const pendingFilteredEvents = eventStream.isFrozen\n ? getPendingFrozenEventCount(\n displayedEvents.length,\n frozenFilteredEventCount,\n )\n : 0;\n const visibleEvents = getVisibleEventWindow(displayedEvents, {\n anchorIndex: fullDataModeEnabled ? safeSelectedEventIndex : null,\n frozenAtTotalEvents: eventStream.isFrozen ? frozenFilteredEventCount : null,\n totalEvents: displayedEvents.length,\n visibleCount: compactLayout ? 4 : 6,\n });\n const globalStatus = deriveGlobalActivityStatus(displayedSessions);\n const activeFilterCount = countActiveFilters(keyBinds.filters);\n\n useEffect(() => {\n const startedAt = Date.now() - status.uptimeMs;\n const uptimeTimer = setInterval(() => {\n setUptimeMs(Date.now() - startedAt);\n }, 1_000);\n uptimeTimer.unref();\n\n return () => {\n clearInterval(uptimeTimer);\n };\n }, [status.uptimeMs]);\n\n useEffect(() => {\n if (eventStream.isFrozen) {\n setFrozenFilteredEventCount(displayedEvents.length);\n }\n }, [\n displayedEvents.length,\n eventStream.isFrozen,\n keyBinds.filters.eventType,\n keyBinds.filters.query,\n keyBinds.filters.tool,\n ]);\n\n useEffect(() => {\n if (displayedEvents.length === 0) {\n setSelectedEventIndex(null);\n return;\n }\n\n if (!fullDataModeEnabled) {\n setSelectedEventIndex(displayedEvents.length - 1);\n return;\n }\n\n setSelectedEventIndex((currentValue) => {\n if (currentValue === null) {\n return displayedEvents.length - 1;\n }\n\n return Math.min(currentValue, displayedEvents.length - 1);\n });\n }, [displayedEvents.length, fullDataModeEnabled]);\n\n useEffect(() => {\n setInspectorLineOffset(0);\n }, [selectedEvent?.id]);\n\n useEffect(() => {\n setInspectorLineOffset((currentValue) =>\n Math.min(currentValue, maxInspectorLineOffset),\n );\n }, [maxInspectorLineOffset]);\n\n return (\n <Box flexDirection=\"column\">\n <Header\n adapterCount={configuredAdapters.length}\n columns={columns}\n connectionLabel={status.connectionLabel}\n connected={status.connected}\n daemon={status.daemon}\n globalStatus={globalStatus}\n version={version}\n />\n <FilterBar\n filters={keyBinds.filters}\n focusPanel={keyBinds.focusPanel}\n interaction={keyBinds.interaction}\n viewMode={keyBinds.viewMode}\n />\n {keyBinds.interaction.kind === 'help' ? <HelpOverlay /> : null}\n <Box marginTop={1}>\n <PanelStack compact={compactLayout}>\n <Panel\n accentColor={TUI_THEME.warning}\n focused={keyBinds.focusPanel === 'events'}\n title=\"Event Stream\"\n >\n <EventStream\n emptyState={\n eventStream.bufferedEvents.length === 0 ? 'no-events' : 'no-match'\n }\n events={visibleEvents}\n frozen={eventStream.isFrozen}\n pendingEventCount={pendingFilteredEvents}\n selectedEventId={selectedEvent?.id ?? null}\n />\n </Panel>\n <Panel\n accentColor={fullDataModeEnabled ? TUI_THEME.warning : TUI_THEME.success}\n focused={keyBinds.focusPanel === 'sessions'}\n title={fullDataModeEnabled ? 'Full Data Inspector' : 'Sessions'}\n >\n {fullDataModeEnabled ? (\n <EventInspector\n event={selectedEvent}\n lineOffset={inspectorLineOffset}\n selectedEventIndex={safeSelectedEventIndex}\n totalEventCount={displayedEvents.length}\n visibleLineCount={inspectorVisibleLineCount}\n />\n ) : (\n <SessionPanel sessions={displayedSessions} />\n )}\n </Panel>\n </PanelStack>\n </Box>\n <Box marginTop={1}>\n <StatusBar\n activeFilterCount={activeFilterCount}\n adapterCount={configuredAdapters.length}\n columns={columns}\n connected={status.connected}\n consumerCount={status.consumerCount}\n daemon={status.daemon}\n eventCount={eventStream.totalEvents}\n focusPanel={keyBinds.focusPanel}\n latestEvent={displayedEvents.at(-1) ?? eventStream.latestEvent}\n pendingEventCount={pendingFilteredEvents}\n streamFrozen={eventStream.isFrozen}\n uptimeMs={uptimeMs}\n viewMode={keyBinds.viewMode}\n />\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { AISnitchEvent } from '../../core/index.js';\nimport {\n buildEventInspectorLines,\n getVisibleInspectorWindow,\n} from '../event-inspector.js';\nimport { TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/EventInspector.tsx\n * @description Scrollable full-data event inspector for the Ink TUI, rendering colorful metadata and the complete selected payload.\n * @functions\n * โ†’ EventInspector\n * @exports EventInspector, type EventInspectorProps\n * @see ../event-inspector.ts\n * @see ../App.tsx\n */\n\n/**\n * Props required by the full-data inspector panel.\n */\nexport interface EventInspectorProps {\n readonly event: AISnitchEvent | null;\n readonly lineOffset: number;\n readonly selectedEventIndex: number | null;\n readonly totalEventCount: number;\n readonly visibleLineCount: number;\n}\n\n/**\n * Renders the currently selected event with a colorful, scrollable full-data view.\n */\nexport function EventInspector({\n event,\n lineOffset,\n selectedEventIndex,\n totalEventCount,\n visibleLineCount,\n}: EventInspectorProps): React.JSX.Element {\n if (event === null || selectedEventIndex === null) {\n return (\n <Box flexDirection=\"column\">\n <Text color={TUI_THEME.panelTitle}>\n No event selected yet.\n </Text>\n <Text color={TUI_THEME.muted}>\n Press [v] to open full-data mode, then use [โ†‘/โ†“] on the event panel to pick one event.\n </Text>\n </Box>\n );\n }\n\n const inspectorLines = buildEventInspectorLines(event);\n const visibleLines = getVisibleInspectorWindow(inspectorLines, {\n lineOffset,\n visibleLineCount,\n });\n const hiddenAbove = Math.max(0, lineOffset);\n const hiddenBelow = Math.max(\n 0,\n inspectorLines.length - (lineOffset + visibleLines.length),\n );\n\n return (\n <Box flexDirection=\"column\">\n <Text color={TUI_THEME.panelBody}>\n {`Selected ${selectedEventIndex + 1}/${totalEventCount} โ€ข ${inspectorLines.length} lines โ€ข [v] close โ€ข [โ†‘/โ†“] scroll โ€ข [[/]] page`}\n </Text>\n {hiddenAbove > 0 ? (\n <Text color={TUI_THEME.muted}>\n {`โ†‘ ${hiddenAbove} line${hiddenAbove === 1 ? '' : 's'} above`}\n </Text>\n ) : null}\n {visibleLines.map((line, lineIndex) => (\n <Text key={`${event.id}:${lineOffset + lineIndex}`}>\n {line.length === 0 || line.every((segment) => segment.text.length === 0)\n ? ' '\n : line.map((segment, segmentIndex) => (\n <Text\n key={`${event.id}:${lineOffset + lineIndex}:${segmentIndex}`}\n bold={segment.bold}\n color={segment.color}\n >\n {segment.text}\n </Text>\n ))}\n </Text>\n ))}\n {hiddenBelow > 0 ? (\n <Text color={TUI_THEME.muted}>\n {`โ†“ ${hiddenBelow} line${hiddenBelow === 1 ? '' : 's'} below`}\n </Text>\n ) : null}\n </Box>\n );\n}\n","import type { AISnitchEvent } from '../core/events/types.js';\n\n/**\n * @file src/tui/event-details.ts\n * @description Shared event-detail extraction for the Ink stream and plain-text monitor output.\n * @functions\n * โ†’ formatEventDetail\n * โ†’ getEventDetailSegments\n * @exports formatEventDetail, getEventDetailSegments\n * @see ./components/EventLine.tsx\n * @see ./live-monitor.ts\n */\n\nconst DETAIL_SEGMENT_LIMIT = 120;\n\n/**\n * ๐Ÿ“– The adapters already stash richer source-native payloads in `data.raw`.\n * This helper squeezes the high-signal parts back out into short human-readable\n * fragments so operators can see prompts, thinking, tool targets, and streamed\n * assistant text without opening raw JSON.\n */\nexport function formatEventDetail(event: AISnitchEvent): string | null {\n const segments = getEventDetailSegments(event);\n\n return segments.length > 0 ? segments.join(' | ') : null;\n}\n\n/**\n * Returns stable, truncated detail segments for one event.\n */\nexport function getEventDetailSegments(event: AISnitchEvent): string[] {\n const raw = getRecord(event.data.raw);\n const segments: Array<string | undefined> = [];\n\n switch (event.type) {\n case 'agent.tool_call':\n case 'agent.coding':\n segments.push(formatToolSegment(event));\n segments.push(formatModelSegment(event.data.model));\n segments.push(formatTokenSegment(event.data.tokensUsed));\n break;\n\n case 'agent.thinking':\n segments.push(formatThinkingSegment(raw));\n segments.push(formatModelSegment(event.data.model));\n segments.push(formatTokenSegment(event.data.tokensUsed));\n segments.push(event.data.activeFile ?? event.data.cwd);\n break;\n\n case 'agent.streaming':\n segments.push(formatStreamingSegment(raw));\n segments.push(formatModelSegment(event.data.model));\n segments.push(formatTokenSegment(event.data.tokensUsed));\n segments.push(event.data.activeFile ?? event.data.cwd);\n break;\n\n case 'task.start':\n segments.push(formatPromptSegment(raw));\n segments.push(event.data.projectPath ?? event.data.project ?? event.data.cwd);\n break;\n\n case 'task.complete':\n segments.push(\n event.data.duration !== undefined\n ? `duration ${event.data.duration}ms`\n : undefined,\n );\n segments.push(formatTokenSegment(event.data.tokensUsed));\n segments.push(event.data.activeFile ?? event.data.projectPath ?? event.data.cwd);\n break;\n\n case 'agent.error':\n segments.push(event.data.errorType);\n segments.push(event.data.errorMessage);\n break;\n\n case 'agent.compact':\n segments.push('context compaction');\n segments.push(event.data.projectPath ?? event.data.cwd);\n break;\n\n case 'agent.asking_user':\n segments.push(\n getString(raw, 'notification_type') ??\n getString(raw, 'notificationType') ??\n getString(raw, 'type'),\n );\n segments.push(event.data.errorMessage ?? extractLooseString(raw, [\n 'message',\n 'reason',\n ]));\n break;\n\n case 'agent.idle':\n segments.push(event.data.activeFile ?? event.data.projectPath ?? event.data.cwd);\n break;\n\n case 'session.start':\n case 'session.end':\n segments.push(event.data.projectPath ?? event.data.project ?? event.data.cwd);\n segments.push(formatModelSegment(event.data.model));\n break;\n\n default:\n break;\n }\n\n return segments\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .map((value) => truncateSegment(value));\n}\n\nfunction formatToolSegment(event: AISnitchEvent): string | undefined {\n const toolName = event.data.toolName;\n const filePath = event.data.toolInput?.filePath ?? event.data.activeFile;\n const command = event.data.toolInput?.command;\n\n if (!toolName && !filePath && !command) {\n return undefined;\n }\n\n const label = toolName ?? 'tool';\n\n if (filePath && command) {\n return `${label}: ${filePath} | cmd ${command}`;\n }\n\n if (filePath) {\n return `${label}: ${filePath}`;\n }\n\n if (command) {\n return `${label}: ${command}`;\n }\n\n return label;\n}\n\nfunction formatThinkingSegment(\n raw: Record<string, unknown> | undefined,\n): string | undefined {\n const snippet =\n extractContentPart(raw, 'thinking', 'thinking') ??\n extractLooseString(raw, ['thinking', 'message']);\n\n return snippet ? `thinking: ${snippet}` : undefined;\n}\n\nfunction formatStreamingSegment(\n raw: Record<string, unknown> | undefined,\n): string | undefined {\n const snippet =\n extractContentPart(raw, 'text', 'text') ??\n extractLooseString(raw, ['message', 'text', 'content']);\n\n return snippet ? `reply: ${snippet}` : undefined;\n}\n\nfunction formatPromptSegment(\n raw: Record<string, unknown> | undefined,\n): string | undefined {\n const snippet = extractLooseString(raw, [\n 'prompt',\n 'query',\n 'message',\n 'text',\n 'content',\n ]);\n\n return snippet ? `prompt: ${snippet}` : undefined;\n}\n\nfunction formatModelSegment(model: string | undefined): string | undefined {\n return model ? `model ${model}` : undefined;\n}\n\nfunction formatTokenSegment(tokensUsed: number | undefined): string | undefined {\n return tokensUsed !== undefined ? `${tokensUsed.toLocaleString('en-US')} tok` : undefined;\n}\n\nfunction extractContentPart(\n raw: Record<string, unknown> | undefined,\n partType: string,\n valueKey: string,\n): string | undefined {\n if (!raw) {\n return undefined;\n }\n\n const message = getRecord(raw.message);\n const content = message?.content ?? raw.content;\n\n if (!Array.isArray(content)) {\n return undefined;\n }\n\n for (const part of content) {\n const record = getRecord(part);\n\n if (!record || getString(record, 'type') !== partType) {\n continue;\n }\n\n const value = getString(record, valueKey);\n\n if (value) {\n return value;\n }\n }\n\n return undefined;\n}\n\nfunction extractLooseString(\n raw: Record<string, unknown> | undefined,\n keys: readonly string[],\n): string | undefined {\n if (!raw) {\n return undefined;\n }\n\n for (const key of keys) {\n const directValue = getString(raw, key);\n\n if (directValue) {\n return directValue;\n }\n\n const nestedRecord = getRecord(raw[key]);\n const nestedValue =\n getString(nestedRecord, 'text') ??\n getString(nestedRecord, 'message') ??\n getString(nestedRecord, 'content');\n\n if (nestedValue) {\n return nestedValue;\n }\n }\n\n return undefined;\n}\n\nfunction truncateSegment(value: string): string {\n const normalized = value.replace(/\\s+/gu, ' ').trim();\n\n if (normalized.length <= DETAIL_SEGMENT_LIMIT) {\n return normalized;\n }\n\n return `${normalized.slice(0, DETAIL_SEGMENT_LIMIT - 1)}โ€ฆ`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction getRecord(value: unknown): Record<string, unknown> | undefined {\n return isRecord(value) ? value : undefined;\n}\n\nfunction getString(\n payload: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n if (!payload) {\n return undefined;\n }\n\n const value = payload[key];\n\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n","import type { AISnitchEventType, ToolName } from '../core/index.js';\n\n/**\n * @file src/tui/theme.ts\n * @description Shared color palette and presentation constants for the Ink-based AISnitch terminal UI.\n * @functions\n * โ†’ none\n * @exports TOOL_COLORS, EVENT_COLORS, TUI_THEME, type TuiThemeColor\n * @see ./App.tsx\n * @see ./components/Header.tsx\n * @see ./components/StatusBar.tsx\n */\n\n/**\n * Hex color string used across the terminal UI theme.\n */\nexport type TuiThemeColor = `#${string}`;\n\n/**\n * ๐Ÿ“– Tools keep distinct colors so operators can scan mixed activity without\n * having to read every label in a busy stream.\n */\nexport const TOOL_COLORS: Record<ToolName, TuiThemeColor> = {\n 'aider': '#14b8a6',\n 'amp': '#fb7185',\n 'augment-code': '#c084fc',\n 'claude-code': '#f59e0b',\n 'cline': '#f43f5e',\n 'codex': '#f97316',\n 'continue': '#06b6d4',\n 'copilot-cli': '#60a5fa',\n 'cursor': '#8b5cf6',\n 'devin': '#f59e0b',\n 'gemini-cli': '#38bdf8',\n 'goose': '#ec4899',\n 'kilo': '#84cc16',\n 'kiro': '#06b6d4',\n 'mistral': '#fb923c',\n 'openhands': '#facc15',\n 'openclaw': '#ef4444',\n 'opencode': '#10b981',\n 'pi': '#1db954',\n 'qwen-code': '#22c55e',\n 'unknown': '#94a3b8',\n 'windsurf': '#a855f7',\n 'zed': '#e85d04',\n};\n\n/**\n * Event types get their own accents so state changes read as a visual rhythm.\n */\nexport const EVENT_COLORS: Record<AISnitchEventType, TuiThemeColor> = {\n 'agent.asking_user': '#ef4444',\n 'agent.coding': '#22c55e',\n 'agent.compact': '#f97316',\n 'agent.error': '#ef4444',\n 'agent.idle': '#64748b',\n 'agent.streaming': '#22d3ee',\n 'agent.thinking': '#facc15',\n 'agent.tool_call': '#fb7185',\n 'session.end': '#94a3b8',\n 'session.start': '#10b981',\n 'task.complete': '#34d399',\n 'task.start': '#60a5fa',\n};\n\n/**\n * Global palette used for layout chrome and section accents.\n */\nexport const TUI_THEME = {\n background: '#111827',\n border: '#1f2937',\n danger: '#ef4444',\n footer: '#0f172a',\n frame: '#334155',\n headerGradient: ['#f59e0b', '#fb7185', '#22d3ee'] as const,\n muted: '#94a3b8',\n panelBody: '#e2e8f0',\n panelTitle: '#f8fafc',\n success: '#22c55e',\n warning: '#facc15',\n} as const;\n","import { formatSessionLabelFromEvent, type AISnitchEvent } from '../core/index.js';\nimport { formatEventDetail } from './event-details.js';\nimport { EVENT_COLORS, TOOL_COLORS, TUI_THEME, type TuiThemeColor } from './theme.js';\n\n/**\n * @file src/tui/event-inspector.ts\n * @description Visual full-data formatter for the TUI event inspector, including colorful metadata rows and syntax-highlighted JSON blocks.\n * @functions\n * โ†’ buildEventInspectorLines\n * โ†’ getVisibleInspectorWindow\n * @exports InspectorSegment, InspectorLine, buildEventInspectorLines, getVisibleInspectorWindow\n * @see ./components/EventInspector.tsx\n * @see ./App.tsx\n */\n\nconst JSON_TOKEN_PATTERN =\n /(\"(?:\\\\.|[^\"])*\"(?=\\s*:))|(\"(?:\\\\.|[^\"])*\")|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|[[\\]{}:,]/gu;\n\n/**\n * Small token model rendered by the Ink inspector component.\n */\nexport interface InspectorSegment {\n readonly bold?: boolean;\n readonly color?: TuiThemeColor;\n readonly text: string;\n}\n\n/**\n * One rendered line inside the full-data inspector.\n */\nexport type InspectorLine = readonly InspectorSegment[];\n\n/**\n * ๐Ÿ“– The inspector deliberately mixes curated metadata with raw pretty JSON.\n * Operators get a friendly summary first, then the complete payload without\n * needing to mentally decode one enormous unstyled blob.\n */\nexport function buildEventInspectorLines(\n event: AISnitchEvent,\n): readonly InspectorLine[] {\n const eventColor = EVENT_COLORS[event.type];\n const toolColor = TOOL_COLORS[event['aisnitch.tool']];\n const sessionLabel = formatSessionLabelFromEvent(event);\n const detailSummary = formatEventDetail(event);\n const normalizedData = removeRawPayload(event.data);\n const rawPayload = event.data.raw ?? {\n note: 'No adapter raw payload was attached to this event.',\n };\n\n return [\n [\n { color: eventColor, text: 'โ—‰ ' },\n {\n bold: true,\n color: eventColor,\n text: event.type,\n },\n { color: TUI_THEME.muted, text: ' ' },\n { bold: true, color: toolColor, text: `[${event['aisnitch.tool']}]` },\n ],\n [\n { color: TUI_THEME.muted, text: 'session ' },\n { color: TUI_THEME.panelBody, text: sessionLabel },\n { color: TUI_THEME.muted, text: ' โ€ข ' },\n { color: TUI_THEME.panelBody, text: formatEventTimestamp(event.time) },\n { color: TUI_THEME.muted, text: ' โ€ข seq ' },\n { color: TUI_THEME.panelBody, text: `#${event['aisnitch.seqnum']}` },\n ],\n [\n { color: TUI_THEME.warning, text: 'โ”โ” Spotlight โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildOptionalKeyValueLines([\n ['summary', detailSummary],\n ['project', event.data.projectPath ?? event.data.project],\n ['cwd', event.data.cwd],\n ['active_file', event.data.activeFile],\n ['command', event.data.toolInput?.command],\n ['model', event.data.model],\n [\n 'tokens',\n event.data.tokensUsed !== undefined\n ? `${event.data.tokensUsed.toLocaleString('en-US')} tok`\n : undefined,\n ],\n ['terminal', event.data.terminal],\n ['pid', event.data.pid],\n [\n 'instance',\n event.data.instanceIndex !== undefined &&\n event.data.instanceTotal !== undefined\n ? `${event.data.instanceIndex}/${event.data.instanceTotal}`\n : event.data.instanceId,\n ],\n ]),\n [{ text: '' }],\n [\n { color: TUI_THEME.warning, text: 'โ”โ” Envelope โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildKeyValueLines([\n ['id', event.id],\n ['source', event.source],\n ['specversion', event.specversion],\n ['seq', String(event['aisnitch.seqnum'])],\n ['session_id', event['aisnitch.sessionid']],\n ['tool', event['aisnitch.tool']],\n ['time', event.time],\n ['type', event.type],\n ]),\n [{ text: '' }],\n [\n { color: TUI_THEME.success, text: 'โ”โ” Normalized Data โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildJsonLines(normalizedData),\n [{ text: '' }],\n [\n { color: TUI_THEME.warning, text: 'โ”โ” Raw Source Payload โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”' },\n ],\n ...buildJsonLines(rawPayload),\n ];\n}\n\n/**\n * Returns the visible scroll window for inspector lines.\n */\nexport function getVisibleInspectorWindow(\n lines: readonly InspectorLine[],\n options: {\n readonly lineOffset: number;\n readonly visibleLineCount: number;\n },\n): readonly InspectorLine[] {\n const safeLineOffset = Math.max(0, options.lineOffset);\n const safeVisibleLineCount = Math.max(1, options.visibleLineCount);\n\n return lines.slice(safeLineOffset, safeLineOffset + safeVisibleLineCount);\n}\n\nfunction buildKeyValueLines(\n entries: readonly (readonly [string, unknown])[],\n): readonly InspectorLine[] {\n return entries.map(([key, value]) => [\n { color: TUI_THEME.muted, text: ' ' },\n { color: '#7dd3fc', text: `${key}: ` },\n { color: TUI_THEME.panelBody, text: formatKeyValue(value) },\n ]);\n}\n\nfunction buildOptionalKeyValueLines(\n entries: readonly (readonly [string, unknown])[],\n): readonly InspectorLine[] {\n return buildKeyValueLines(\n entries.filter((entry): entry is readonly [string, unknown] => {\n const [, value] = entry;\n\n return hasDisplayValue(value);\n }),\n );\n}\n\nfunction buildJsonLines(value: unknown): readonly InspectorLine[] {\n const prettyJson = JSON.stringify(value, null, 2);\n\n if (!prettyJson) {\n return [[{ color: TUI_THEME.muted, text: ' (empty)' }]];\n }\n\n return prettyJson.split('\\n').map((line) => highlightJsonLine(line));\n}\n\nfunction highlightJsonLine(line: string): InspectorLine {\n if (line.length === 0) {\n return [{ text: '' }];\n }\n\n const segments: InspectorSegment[] = [];\n let lastIndex = 0;\n\n for (const match of line.matchAll(JSON_TOKEN_PATTERN)) {\n const matchedValue = match[0];\n const matchIndex = match.index ?? 0;\n\n if (matchIndex > lastIndex) {\n segments.push({\n color: TUI_THEME.panelBody,\n text: line.slice(lastIndex, matchIndex),\n });\n }\n\n segments.push({\n color: resolveJsonTokenColor(matchedValue, match),\n text: matchedValue,\n });\n lastIndex = matchIndex + matchedValue.length;\n }\n\n if (lastIndex < line.length) {\n segments.push({\n color: TUI_THEME.panelBody,\n text: line.slice(lastIndex),\n });\n }\n\n return segments.length > 0\n ? segments\n : [{ color: TUI_THEME.panelBody, text: line }];\n}\n\nfunction resolveJsonTokenColor(\n token: string,\n match: RegExpMatchArray,\n): TuiThemeColor {\n if (match[1]) {\n return '#7dd3fc';\n }\n\n if (match[2]) {\n return '#86efac';\n }\n\n if (token === 'true' || token === 'false') {\n return '#c084fc';\n }\n\n if (token === 'null') {\n return TUI_THEME.muted;\n }\n\n if (/^-?\\d/u.test(token)) {\n return '#fb923c';\n }\n\n return TUI_THEME.muted;\n}\n\nfunction removeRawPayload(\n data: AISnitchEvent['data'],\n): Record<string, unknown> {\n const { raw: _raw, ...normalizedData } = data;\n\n return normalizedData;\n}\n\nfunction formatKeyValue(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n\n if (value === null || value === undefined) {\n return 'n/a';\n }\n\n return JSON.stringify(value);\n}\n\nfunction hasDisplayValue(value: unknown): boolean {\n if (value === undefined || value === null) {\n return false;\n }\n\n if (typeof value === 'string') {\n return value.length > 0;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n\n return Object.keys(value).length > 0;\n}\n\nfunction formatEventTimestamp(timestamp: string): string {\n return new Intl.DateTimeFormat('en-GB', {\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n month: '2-digit',\n second: '2-digit',\n }).format(new Date(timestamp));\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { AISnitchEvent } from '../../core/index.js';\nimport { TUI_THEME } from '../theme.js';\nimport { EventLine } from './EventLine.js';\n\n/**\n * @file src/tui/components/EventStream.tsx\n * @description Live event stream panel content for the Ink TUI, rendering the visible event window and frozen-state hints.\n * @functions\n * โ†’ EventStream\n * @exports EventStream, type EventStreamProps\n * @see ./EventLine.tsx\n * @see ../hooks/useEventStream.ts\n */\n\n/**\n * Props accepted by the live event stream component.\n */\nexport interface EventStreamProps {\n readonly emptyState?: 'no-events' | 'no-match';\n readonly events: readonly AISnitchEvent[];\n readonly frozen: boolean;\n readonly pendingEventCount: number;\n readonly selectedEventId?: string | null;\n}\n\n/**\n * Renders the current visible portion of the live event stream.\n */\nexport function EventStream({\n emptyState = 'no-events',\n events,\n frozen,\n pendingEventCount,\n selectedEventId = null,\n}: EventStreamProps): React.JSX.Element {\n if (events.length === 0) {\n return (\n <Box flexDirection=\"column\">\n <Text color={TUI_THEME.panelTitle}>\n {emptyState === 'no-events'\n ? 'No events yet. Start with Claude Code or OpenCode and the foreground bus will light up here.'\n : 'No buffered events match the current filters.'}\n </Text>\n <Text color={TUI_THEME.muted}>\n {emptyState === 'no-events'\n ? 'Use [f], [t], [/], and [?] to shape the live view once events start flowing.'\n : 'Change the active filters or clear them with Esc.'}\n </Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\">\n {events.map((event) => (\n <EventLine\n key={event.id}\n event={event}\n selected={selectedEventId === event.id}\n />\n ))}\n <Text color={TUI_THEME.muted}>\n {frozen\n ? `Frozen tail: ${pendingEventCount} newer ${\n pendingEventCount === 1 ? 'event is' : 'events are'\n } buffered.`\n : 'Live tail: newest events stay in view automatically.'}\n </Text>\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport {\n formatSessionLabelFromEvent,\n type AISnitchEvent,\n type AISnitchEventType,\n} from '../../core/index.js';\nimport { formatEventDetail } from '../event-details.js';\nimport { EVENT_COLORS, TOOL_COLORS, TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/EventLine.tsx\n * @description Single formatted event row for the Ink live stream, including icon mapping, timestamp formatting, and optional detail output.\n * @functions\n * โ†’ EventLine\n * โ†’ formatEventTime\n * โ†’ formatEventDetail\n * @exports EVENT_ICONS, EventLine, formatEventTime, formatEventDetail\n * @see ./EventStream.tsx\n * @see ../hooks/useEventStream.ts\n */\n\n/**\n * ๐Ÿ“– The stream gets much easier to scan when each normalized state has a\n * stable visual marker instead of relying on color alone.\n */\nexport const EVENT_ICONS: Record<AISnitchEventType, string> = {\n 'session.start': '๐Ÿš€',\n 'session.end': '๐Ÿ‘‹',\n 'task.start': '๐Ÿ“',\n 'task.complete': 'โœ…',\n 'agent.thinking': '๐Ÿค”',\n 'agent.coding': 'โŒจ๏ธ',\n 'agent.tool_call': '๐Ÿ”ง',\n 'agent.streaming': '๐Ÿ’ฌ',\n 'agent.asking_user': 'โœ‹',\n 'agent.idle': '๐Ÿ’ค',\n 'agent.error': 'โŒ',\n 'agent.compact': '๐Ÿง ',\n};\n\n/**\n * Props required to render one formatted event row.\n */\nexport interface EventLineProps {\n readonly event: AISnitchEvent;\n readonly selected?: boolean;\n}\n\n/**\n * Renders a single event row plus its optional detail line.\n */\nexport function EventLine({\n event,\n selected = false,\n}: EventLineProps): React.JSX.Element {\n const detail = formatEventDetail(event);\n const sessionLabel = formatSessionLabelFromEvent(event);\n\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text color={selected ? TUI_THEME.warning : TUI_THEME.muted}>\n {selected ? 'โ€บ' : ' '}\n </Text>\n <Text> </Text>\n <Text color={TUI_THEME.muted}>{formatEventTime(event.time)}</Text>\n <Text> </Text>\n <Text>{EVENT_ICONS[event.type]}</Text>\n <Text> </Text>\n <Text color={TOOL_COLORS[event['aisnitch.tool']]}>\n [{event['aisnitch.tool']}]\n </Text>\n <Text> </Text>\n <Text bold color={EVENT_COLORS[event.type]}>\n {event.type}\n </Text>\n {sessionLabel !== event['aisnitch.tool'] ? (\n <>\n <Text color={TUI_THEME.muted}> ยท </Text>\n <Text color={TUI_THEME.muted}>{sessionLabel}</Text>\n </>\n ) : null}\n </Box>\n {detail ? (\n <Box marginLeft={4}>\n <Text color={selected ? TUI_THEME.panelBody : TUI_THEME.muted}>\n โ””โ”€ {detail}\n </Text>\n </Box>\n ) : null}\n </Box>\n );\n}\n\n/**\n * Converts an ISO timestamp into a compact wall-clock string.\n */\nexport function formatEventTime(timestamp: string): string {\n return new Intl.DateTimeFormat('en-GB', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n }).format(new Date(timestamp));\n}\nexport { formatEventDetail } from '../event-details.js';\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport { countActiveFilters, type TuiFilters } from '../filters.js';\nimport type {\n FocusedPanel,\n TuiInteractionMode,\n} from '../hooks/useKeyBinds.js';\nimport { TUI_THEME } from '../theme.js';\nimport type { TuiViewMode } from '../types.js';\n\n/**\n * @file src/tui/components/FilterBar.tsx\n * @description Filter and command prompt bar for the AISnitch TUI, showing active filters, focus, and current interaction mode.\n * @functions\n * โ†’ FilterBar\n * @exports FilterBar, type FilterBarProps\n * @see ../hooks/useKeyBinds.ts\n * @see ../filters.ts\n * @see ../App.tsx\n */\n\n/**\n * Props accepted by the TUI filter bar.\n */\nexport interface FilterBarProps {\n readonly filters: TuiFilters;\n readonly focusPanel: FocusedPanel;\n readonly interaction: TuiInteractionMode;\n readonly viewMode: TuiViewMode;\n}\n\n/**\n * Renders the currently active filters and the inline prompt state.\n */\nexport function FilterBar({\n filters,\n focusPanel,\n interaction,\n viewMode,\n}: FilterBarProps): React.JSX.Element {\n const activeFilterCount = countActiveFilters(filters);\n const focusLabel =\n focusPanel === 'events'\n ? 'events'\n : viewMode === 'full-data'\n ? 'inspector'\n : 'sessions';\n\n return (\n <Box\n borderColor={TUI_THEME.border}\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginTop={1}\n paddingX={1}\n >\n <Text color={TUI_THEME.panelBody}>\n {`Focus ${focusLabel} | View ${viewMode} | Active filters ${activeFilterCount} | ${formatFilterSummary(\n filters,\n )}`}\n </Text>\n <Text color={TUI_THEME.muted}>\n {formatInteractionHint(interaction, focusPanel, viewMode)}\n </Text>\n </Box>\n );\n}\n\nfunction formatFilterSummary(filters: TuiFilters): string {\n const parts = [\n filters.tool ? `tool=${filters.tool}` : null,\n filters.eventType ? `type=${filters.eventType}` : null,\n filters.query.trim().length > 0 ? `search=\"${filters.query}\"` : null,\n ].filter((value): value is string => value !== null);\n\n return parts.length > 0 ? parts.join(' | ') : 'no filters active';\n}\n\nfunction formatInteractionHint(\n interaction: TuiInteractionMode,\n focusPanel: FocusedPanel,\n viewMode: TuiViewMode,\n): string {\n switch (interaction.kind) {\n case 'tool-filter':\n return `Tool filter > ${\n interaction.options[interaction.selectedIndex]?.label ?? 'All tools'\n } (โ†‘/โ†“ select, Enter apply, Esc clear)`;\n case 'type-filter':\n return `Type filter > ${\n interaction.options[interaction.selectedIndex]?.label ?? 'All event types'\n } (โ†‘/โ†“ select, Enter apply, Esc clear)`;\n case 'search':\n return `Search > ${interaction.draft}`;\n case 'help':\n return 'Help open (? or Esc to close)';\n default:\n if (viewMode === 'full-data') {\n return focusPanel === 'events'\n ? 'Commands: [v] summary [โ†‘/โ†“ or j/k] select event [Tab] inspector [f/t//] filters'\n : 'Commands: [v] summary [โ†‘/โ†“ or j/k] scroll [[/]] page [Tab] events';\n }\n\n return 'Commands: [v] full-data [f] tool [t] type [/] search [Esc] clear filters [Tab] focus';\n }\n}\n","import type {\n AISnitchEvent,\n AISnitchEventType,\n ToolName,\n} from '../core/index.js';\nimport { formatEventDetail } from './event-details.js';\n\n/**\n * @file src/tui/filters.ts\n * @description Pure filtering helpers shared by the TUI event stream, session panel, and CLI pre-filter handling.\n * @functions\n * โ†’ applyEventFilters\n * โ†’ applySessionFilters\n * โ†’ countActiveFilters\n * @exports TuiFilters, SessionFilterTarget, DEFAULT_TUI_FILTERS, applyEventFilters, applySessionFilters, countActiveFilters\n * @see ./App.tsx\n * @see ./hooks/useKeyBinds.ts\n * @see ./hooks/useSessions.ts\n */\n\n/**\n * Global filter state applied across the TUI.\n */\nexport interface TuiFilters {\n readonly eventType: AISnitchEventType | null;\n readonly query: string;\n readonly tool: ToolName | null;\n}\n\n/**\n * Structural session shape accepted by the generic session filter helper.\n */\nexport interface SessionFilterTarget {\n readonly activeFile?: string;\n readonly currentState: AISnitchEventType;\n readonly cwd?: string;\n readonly displayLabel?: string;\n readonly project?: string;\n readonly projectPath?: string;\n readonly sessionId: string;\n readonly shortSessionId?: string;\n readonly tool: ToolName;\n}\n\n/**\n * Default empty filter state used by the TUI.\n */\nexport const DEFAULT_TUI_FILTERS: TuiFilters = {\n eventType: null,\n query: '',\n tool: null,\n};\n\n/**\n * Filters buffered events by tool, event type, and free-text search.\n */\nexport function applyEventFilters(\n events: readonly AISnitchEvent[],\n filters: TuiFilters,\n): readonly AISnitchEvent[] {\n return events.filter((event) => {\n if (filters.tool !== null && event['aisnitch.tool'] !== filters.tool) {\n return false;\n }\n\n if (filters.eventType !== null && event.type !== filters.eventType) {\n return false;\n }\n\n if (!matchesTextQuery(getEventSearchFields(event), filters.query)) {\n return false;\n }\n\n return true;\n });\n}\n\n/**\n * Filters active sessions using the same global TUI filter state.\n */\nexport function applySessionFilters<T extends SessionFilterTarget>(\n sessions: readonly T[],\n filters: TuiFilters,\n): readonly T[] {\n return sessions.filter((session) => {\n if (filters.tool !== null && session.tool !== filters.tool) {\n return false;\n }\n\n if (filters.eventType !== null && session.currentState !== filters.eventType) {\n return false;\n }\n\n if (\n !matchesTextQuery(\n [\n session.sessionId,\n session.tool,\n session.currentState,\n session.displayLabel,\n session.project,\n session.projectPath,\n session.cwd,\n session.activeFile,\n session.shortSessionId,\n ],\n filters.query,\n )\n ) {\n return false;\n }\n\n return true;\n });\n}\n\n/**\n * Counts how many filter categories are currently active.\n */\nexport function countActiveFilters(filters: TuiFilters): number {\n let count = 0;\n\n if (filters.tool !== null) {\n count += 1;\n }\n\n if (filters.eventType !== null) {\n count += 1;\n }\n\n if (filters.query.trim().length > 0) {\n count += 1;\n }\n\n return count;\n}\n\nfunction getEventSearchFields(event: AISnitchEvent): readonly (string | undefined)[] {\n return [\n event['aisnitch.tool'],\n event.type,\n event['aisnitch.sessionid'],\n formatEventDetail(event) ?? undefined,\n event.data.toolName,\n event.data.toolInput?.filePath,\n event.data.toolInput?.command,\n event.data.activeFile,\n event.data.errorMessage,\n event.data.cwd,\n event.data.project,\n event.data.projectPath,\n ];\n}\n\nfunction matchesTextQuery(\n values: readonly (string | undefined)[],\n query: string,\n): boolean {\n const normalizedQuery = query.trim().toLowerCase();\n\n if (normalizedQuery.length === 0) {\n return true;\n }\n\n return values.some((value) => value?.toLowerCase().includes(normalizedQuery));\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport BigText from 'ink-big-text';\nimport Gradient from 'ink-gradient';\nimport Spinner from 'ink-spinner';\n\nimport type { GlobalActivityStatus } from '../hooks/useSessions.js';\nimport { TUI_THEME } from '../theme.js';\nimport type { TuiDaemonSnapshot } from '../types.js';\nimport { GlobalBadge } from './GlobalBadge.js';\n\n/**\n * @file src/tui/components/Header.tsx\n * @description Header chrome for the AISnitch TUI, including title treatment and connection status badge.\n * @functions\n * โ†’ Header\n * @exports Header, type HeaderProps\n * @see ../App.tsx\n * @see ./StatusBar.tsx\n */\n\n/**\n * Props accepted by the header component.\n */\nexport interface HeaderProps {\n readonly adapterCount: number;\n readonly columns: number;\n readonly connectionLabel: string;\n readonly connected: boolean;\n readonly daemon?: TuiDaemonSnapshot;\n readonly globalStatus: GlobalActivityStatus;\n readonly version: string;\n}\n\n/**\n * ๐Ÿ“– The header does the \"vitrine\" job from the spec: bold title treatment,\n * a little theater, and the essential runtime badges in one glance.\n */\nexport function Header({\n adapterCount,\n columns,\n connectionLabel,\n connected,\n daemon,\n globalStatus,\n version,\n}: HeaderProps): React.JSX.Element {\n const showBigTitle = columns >= 88;\n const daemonBusyAction = daemon?.busyAction ?? null;\n\n return (\n <Box\n borderColor={TUI_THEME.border}\n borderStyle=\"round\"\n flexDirection=\"column\"\n paddingX={1}\n paddingY={0}\n >\n <Box justifyContent=\"space-between\">\n <Text color={TUI_THEME.muted}>memory-only live bridge</Text>\n <Text color={TUI_THEME.muted}>v{version}</Text>\n </Box>\n <Box justifyContent=\"space-between\">\n <Box flexDirection=\"column\" flexGrow={1}>\n {showBigTitle ? (\n <Gradient colors={[...TUI_THEME.headerGradient]}>\n <BigText font=\"tiny\" text=\"AISnitch\" />\n </Gradient>\n ) : (\n <Gradient colors={[...TUI_THEME.headerGradient]}>\n <Text bold> AISnitch </Text>\n </Gradient>\n )}\n <Text color={TUI_THEME.muted}>\n live AI tool telemetry with adapter-driven normalization\n </Text>\n </Box>\n <Box\n alignItems=\"flex-end\"\n flexDirection=\"column\"\n marginLeft={2}\n minWidth={38}\n >\n <Box>\n {daemon ? (\n daemonBusyAction ? (\n <>\n <Text bold color={TUI_THEME.warning}>\n <Spinner type=\"dots\" />\n </Text>\n <Text color={TUI_THEME.warning}>\n {' '}\n daemon {daemonBusyAction}\n </Text>\n </>\n ) : daemon.active ? (\n <Text bold color={TUI_THEME.success}>\n โ— Daemon active ยท PID {daemon.pid ?? 'none'}\n </Text>\n ) : (\n <Text bold color={TUI_THEME.warning}>\n โ—‹ Daemon not active\n </Text>\n )\n ) : connected ? (\n <Text bold color={TUI_THEME.success}>\n โ— Connected ยท {connectionLabel}\n </Text>\n ) : (\n <>\n <Text bold color={TUI_THEME.warning}>\n <Spinner type=\"dots\" />\n </Text>\n <Text color={TUI_THEME.warning}> reconnecting</Text>\n </>\n )}\n </Box>\n {daemon ? (\n <>\n <Text color={connected ? TUI_THEME.success : TUI_THEME.warning}>\n {connected ? `โ— ${connectionLabel}` : `โ—‹ ${connectionLabel}`}\n </Text>\n <Text color={TUI_THEME.muted}>WS {daemon.wsUrl}</Text>\n </>\n ) : null}\n <GlobalBadge status={globalStatus} />\n <Text color={TUI_THEME.muted}>{adapterCount} adapters armed</Text>\n </Box>\n </Box>\n </Box>\n );\n}\n","import React from 'react';\nimport { Text } from 'ink';\n\nimport type { GlobalActivityStatus } from '../hooks/useSessions.js';\nimport { TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/GlobalBadge.tsx\n * @description Compact activity badge for the TUI header, summarizing whether the system is idle, busy, or waiting on the user.\n * @functions\n * โ†’ GlobalBadge\n * @exports GlobalBadge, type GlobalBadgeProps\n * @see ./Header.tsx\n * @see ../hooks/useSessions.ts\n */\n\n/**\n * Props accepted by the global activity badge.\n */\nexport interface GlobalBadgeProps {\n readonly status: GlobalActivityStatus;\n}\n\n/**\n * Renders the high-level activity badge displayed in the TUI header.\n */\nexport function GlobalBadge({\n status,\n}: GlobalBadgeProps): React.JSX.Element {\n switch (status) {\n case 'action-required':\n return (\n <Text bold color={TUI_THEME.danger}>\n โœ‹ Action Required\n </Text>\n );\n case 'working':\n return (\n <Text bold color={TUI_THEME.warning}>\n โœฆ Working\n </Text>\n );\n default:\n return (\n <Text bold color={TUI_THEME.success}>\n โ—‡ Ready\n </Text>\n );\n }\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport { TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/HelpOverlay.tsx\n * @description Compact help overlay listing the current AISnitch TUI keybinds.\n * @functions\n * โ†’ HelpOverlay\n * @exports HelpOverlay\n * @see ../hooks/useKeyBinds.ts\n * @see ../App.tsx\n */\n\nconst HELP_LINES = [\n 'q / Ctrl+C quit cleanly',\n 'v toggle full-data inspector',\n 'f filter by tool',\n 't filter by event type',\n '/ free-text search',\n 'Esc clear filters',\n 'Space freeze or resume stream',\n 'c clear buffered stream',\n 'โ†‘/โ†“ or j/k inspect-mode navigate / scroll',\n '[ / ] inspect-mode page scroll',\n '? toggle help',\n 'Tab cycle focused panel',\n];\n\n/**\n * Renders the help box shown above the main panels.\n */\nexport function HelpOverlay(): React.JSX.Element {\n return (\n <Box\n borderColor={TUI_THEME.warning}\n borderStyle=\"round\"\n flexDirection=\"column\"\n marginTop={1}\n paddingX={1}\n >\n <Text bold color={TUI_THEME.panelTitle}>\n Keybinds\n </Text>\n {HELP_LINES.map((line) => (\n <Text key={line} color={TUI_THEME.panelBody}>\n {line}\n </Text>\n ))}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport { TUI_THEME, type TuiThemeColor } from '../theme.js';\n\n/**\n * @file src/tui/components/Layout.tsx\n * @description Reusable layout primitives for bordered panels and responsive panel stacks in the AISnitch TUI.\n * @functions\n * โ†’ Panel\n * โ†’ PanelStack\n * @exports Panel, PanelStack, type PanelProps, type PanelStackProps\n * @see ../App.tsx\n * @see ./Header.tsx\n * @see ./StatusBar.tsx\n */\n\n/**\n * Props for a single framed panel.\n */\nexport interface PanelProps {\n readonly accentColor: TuiThemeColor;\n readonly children: React.ReactNode;\n readonly flexGrow?: number;\n readonly focused?: boolean;\n readonly title: string;\n}\n\n/**\n * Props for a responsive panel stack.\n */\nexport interface PanelStackProps {\n readonly children: React.ReactNode;\n readonly compact?: boolean;\n}\n\n/**\n * ๐Ÿ“– A thin panel primitive keeps the TUI consistent without hiding Ink's\n * flexbox model behind too much framework glue.\n */\nexport function Panel({\n accentColor,\n children,\n flexGrow = 1,\n focused = false,\n title,\n}: PanelProps): React.JSX.Element {\n return (\n <Box\n borderColor={focused ? accentColor : TUI_THEME.frame}\n borderStyle=\"round\"\n flexDirection=\"column\"\n flexGrow={flexGrow}\n minHeight={8}\n paddingX={1}\n paddingY={0}\n >\n <Box marginBottom={1}>\n <Text bold color={accentColor}>\n {title}\n </Text>\n </Box>\n <Box flexDirection=\"column\" flexGrow={1}>\n {children}\n </Box>\n </Box>\n );\n}\n\n/**\n * Renders the main body panels side by side on wide terminals and stacked on narrow ones.\n */\nexport function PanelStack({\n children,\n compact = false,\n}: PanelStackProps): React.JSX.Element {\n return (\n <Box\n columnGap={1}\n flexDirection={compact ? 'column' : 'row'}\n flexGrow={1}\n rowGap={1}\n >\n {children}\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\nimport Spinner from 'ink-spinner';\n\nimport type { SessionState } from '../hooks/useSessions.js';\nimport { TOOL_COLORS, TUI_THEME } from '../theme.js';\n\n/**\n * @file src/tui/components/SessionPanel.tsx\n * @description Grouped active-session renderer for the AISnitch TUI, including state-specific visual cues and durations.\n * @functions\n * โ†’ SessionPanel\n * @exports SessionPanel, type SessionPanelProps\n * @see ../hooks/useSessions.ts\n * @see ../App.tsx\n */\n\n/**\n * Props accepted by the session panel renderer.\n */\nexport interface SessionPanelProps {\n readonly sessions: readonly SessionState[];\n}\n\n/**\n * ๐Ÿ“– Session grouping stays intentionally compact so operators can tell \"who\n * is doing what\" without the panel becoming wider than the event stream.\n */\nexport function SessionPanel({\n sessions,\n}: SessionPanelProps): React.JSX.Element {\n if (sessions.length === 0) {\n return (\n <Text color={TUI_THEME.muted}>\n No active sessions match the current view.\n </Text>\n );\n }\n\n const groupedSessions = groupSessionsByTool(sessions);\n\n return (\n <Box flexDirection=\"column\">\n {groupedSessions.map(([toolName, toolSessions]) => (\n <Box key={toolName} flexDirection=\"column\" marginBottom={1}>\n <Text bold color={TOOL_COLORS[toolName]}>\n {toolName} ({toolSessions.length})\n </Text>\n {toolSessions.map((session) => (\n <Box key={session.sessionId} flexDirection=\"column\" marginLeft={1}>\n <Text color={TOOL_COLORS[session.tool]}>\n โ— {session.displayLabel}\n </Text>\n {formatSessionLocation(session) ? (\n <Text color={TUI_THEME.muted}>\n {` โ†ณ ${formatSessionLocation(session)}`}\n </Text>\n ) : null}\n <Box marginLeft={2}>\n {renderStateLabel(session)}\n <Text color={TUI_THEME.muted}>\n {` ยท ${session.eventCount} events ยท ${formatDuration(session.durationMs)}`}\n </Text>\n {session.shortSessionId ? (\n <Text color={TUI_THEME.muted}>\n {` ยท sid ${session.shortSessionId}`}\n </Text>\n ) : null}\n </Box>\n </Box>\n ))}\n </Box>\n ))}\n </Box>\n );\n}\n\nfunction renderStateLabel(session: SessionState): React.JSX.Element {\n switch (session.currentState) {\n case 'agent.coding':\n return (\n <Text color={TUI_THEME.success}>\n <Spinner type=\"runner\" /> coding\n </Text>\n );\n case 'agent.thinking':\n return (\n <Text color={TUI_THEME.warning}>\n <Spinner type=\"dots\" /> thinking\n </Text>\n );\n case 'agent.asking_user':\n return (\n <Text bold color={TUI_THEME.danger}>\n โœ‹ asking_user\n </Text>\n );\n case 'agent.error':\n return (\n <Text bold color={TUI_THEME.danger}>\n โŒ error\n </Text>\n );\n case 'agent.idle':\n return <Text color={TUI_THEME.muted}>idle</Text>;\n default:\n return (\n <Text color={TUI_THEME.panelBody}>{session.currentState}</Text>\n );\n }\n}\n\nfunction groupSessionsByTool(\n sessions: readonly SessionState[],\n): readonly [SessionState['tool'], readonly SessionState[]][] {\n const groupedSessions = new Map<SessionState['tool'], SessionState[]>();\n\n for (const session of sessions) {\n const toolSessions = groupedSessions.get(session.tool) ?? [];\n\n toolSessions.push(session);\n groupedSessions.set(session.tool, toolSessions);\n }\n\n return [...groupedSessions.entries()];\n}\n\nfunction formatSessionLocation(session: SessionState): string | null {\n return session.activeFile ?? session.projectPath ?? session.cwd ?? null;\n}\n\nfunction formatDuration(durationMs: number): string {\n const totalSeconds = Math.max(0, Math.floor(durationMs / 1_000));\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n\n if (minutes === 0) {\n return `${seconds}s`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n","import React from 'react';\nimport { Box, Text } from 'ink';\n\nimport type { AISnitchEvent } from '../../core/index.js';\nimport type { FocusedPanel } from '../hooks/useKeyBinds.js';\nimport { TUI_THEME } from '../theme.js';\nimport type { TuiDaemonSnapshot, TuiViewMode } from '../types.js';\n\n/**\n * @file src/tui/components/StatusBar.tsx\n * @description Footer status bar for runtime counts, uptime, and keybind hints in the AISnitch TUI.\n * @functions\n * โ†’ StatusBar\n * @exports StatusBar, type StatusBarProps\n * @see ../App.tsx\n */\n\n/**\n * Props accepted by the status bar component.\n */\nexport interface StatusBarProps {\n readonly activeFilterCount: number;\n readonly adapterCount: number;\n readonly columns: number;\n readonly connected: boolean;\n readonly consumerCount: number;\n readonly daemon?: TuiDaemonSnapshot;\n readonly eventCount: number;\n readonly focusPanel: FocusedPanel;\n readonly latestEvent: AISnitchEvent | null;\n readonly pendingEventCount?: number;\n readonly streamFrozen: boolean;\n readonly uptimeMs: number;\n readonly viewMode: TuiViewMode;\n}\n\n/**\n * Renders the lower chrome with lightweight stats and keyboard hints.\n */\nexport function StatusBar({\n activeFilterCount,\n adapterCount,\n columns,\n connected,\n consumerCount,\n daemon,\n eventCount,\n focusPanel,\n latestEvent,\n pendingEventCount = 0,\n streamFrozen,\n uptimeMs,\n viewMode,\n}: StatusBarProps): React.JSX.Element {\n const streamState = streamFrozen\n ? `Frozen +${pendingEventCount}`\n : latestEvent?.type ?? 'Live';\n const focusLabel =\n focusPanel === 'events'\n ? 'events'\n : viewMode === 'full-data'\n ? 'inspector'\n : 'sessions';\n const daemonLabel =\n daemon === undefined\n ? null\n : daemon.busyAction\n ? `Daemon ${daemon.busyAction}`\n : daemon.active\n ? `Daemon active ยท ${daemon.wsUrl}`\n : `Daemon not active ยท ${daemon.wsUrl}`;\n\n return (\n <Box\n borderColor={TUI_THEME.border}\n borderStyle=\"round\"\n flexDirection=\"column\"\n paddingX={1}\n paddingY={0}\n >\n <Text color={TUI_THEME.panelBody}>\n {`Events ${eventCount} | Adapters ${adapterCount} | Consumers ${consumerCount} | Filters ${activeFilterCount} | Focus ${focusLabel} | View ${viewMode} | Up ${formatUptime(\n uptimeMs,\n )} | ${streamState}${daemonLabel ? ` | ${daemonLabel}` : ''} | Size ${columns}c`}\n </Text>\n <Text color={TUI_THEME.muted}>\n {daemon\n ? connected\n ? `${\n daemon.active ? '[d] stop daemon' : '[d] start daemon'\n } [r] refresh ${\n streamFrozen\n ? '[space] resume [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n : '[space] freeze [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n }`\n : `${daemon.active ? '[d] stop daemon' : '[d] start daemon'} [r] refresh [v] full-data [q] quit [?] help`\n : connected\n ? streamFrozen\n ? '[space] resume [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n : '[space] freeze [v] full-data [q] quit [?] help [f/t//] filters [c] clear'\n : '[q] quit waiting for foreground bus'}\n </Text>\n </Box>\n );\n}\n\nfunction formatUptime(uptimeMs: number): string {\n const totalSeconds = Math.max(0, Math.floor(uptimeMs / 1_000));\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n\n if (minutes === 0) {\n return `${seconds}s`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n","import { useEffect, useState } from 'react';\nimport type { RawData, WebSocket } from 'ws';\n\nimport {\n AISnitchEventSchema,\n type AISnitchEvent,\n type EventBus,\n} from '../../core/index.js';\n\n/**\n * @file src/tui/hooks/useEventStream.ts\n * @description React hook and pure helpers for collecting, bounding, and freezing the live AISnitch event stream.\n * @functions\n * โ†’ useEventStream\n * โ†’ appendEventToStream\n * โ†’ getVisibleEventWindow\n * โ†’ getPendingFrozenEventCount\n * @exports EVENT_STREAM_LIMIT, EventStreamSource, UseEventStreamOptions, UseEventStreamState, useEventStream, appendEventToStream, getVisibleEventWindow, getPendingFrozenEventCount\n * @see ../components/EventStream.tsx\n * @see ../../core/engine/event-bus.ts\n * @see ../../core/engine/ws-server.ts\n */\n\n/**\n * Maximum number of live events kept in memory for the TUI stream.\n */\nexport const EVENT_STREAM_LIMIT = 500;\n\n/**\n * Default number of rendered events kept in the visible terminal window.\n */\nexport const DEFAULT_VISIBLE_EVENT_COUNT = 8;\n\n/**\n * Supported live sources for the event stream hook.\n */\nexport type EventStreamSource =\n | {\n readonly kind: 'event-bus';\n readonly eventBus: EventBus;\n }\n | {\n readonly kind: 'websocket';\n readonly socket: Pick<WebSocket, 'on' | 'off'>;\n };\n\n/**\n * Configuration accepted by the event stream hook.\n */\nexport interface UseEventStreamOptions {\n readonly initialTotalEvents?: number;\n readonly limit?: number;\n readonly visibleCount?: number;\n}\n\n/**\n * State returned by the live event stream hook.\n */\nexport interface UseEventStreamState {\n readonly bufferedEvents: readonly AISnitchEvent[];\n readonly clearEvents: () => void;\n readonly isFrozen: boolean;\n readonly latestEvent: AISnitchEvent | null;\n readonly pendingEventCount: number;\n readonly toggleFrozen: () => void;\n readonly totalEvents: number;\n readonly visibleEvents: readonly AISnitchEvent[];\n}\n\n/**\n * ๐Ÿ“– The hook owns stream mechanics so `App` can stay focused on layout and\n * panel composition instead of juggling buffer trimming, freeze anchors, and\n * source-specific subscription code.\n */\nexport function useEventStream(\n source: EventStreamSource,\n options: UseEventStreamOptions = {},\n): UseEventStreamState {\n const limit = options.limit ?? EVENT_STREAM_LIMIT;\n const visibleCount = options.visibleCount ?? DEFAULT_VISIBLE_EVENT_COUNT;\n const [bufferedEvents, setBufferedEvents] = useState<readonly AISnitchEvent[]>(\n [],\n );\n const [totalEvents, setTotalEvents] = useState(options.initialTotalEvents ?? 0);\n const [latestEvent, setLatestEvent] = useState<AISnitchEvent | null>(null);\n const [frozenAtTotalEvents, setFrozenAtTotalEvents] = useState<number | null>(\n null,\n );\n\n useEffect(() => {\n const unsubscribe = subscribeToEventStream(source, (event) => {\n setLatestEvent(event);\n setTotalEvents((currentValue) => currentValue + 1);\n setBufferedEvents((currentValue) =>\n appendEventToStream(currentValue, event, limit),\n );\n });\n\n return () => {\n unsubscribe();\n };\n }, [limit, source]);\n\n const pendingEventCount = getPendingFrozenEventCount(\n totalEvents,\n frozenAtTotalEvents,\n );\n const visibleEvents = getVisibleEventWindow(bufferedEvents, {\n totalEvents,\n frozenAtTotalEvents,\n visibleCount,\n });\n\n return {\n bufferedEvents,\n clearEvents: () => {\n setBufferedEvents([]);\n setFrozenAtTotalEvents(null);\n setLatestEvent(null);\n },\n isFrozen: frozenAtTotalEvents !== null,\n latestEvent,\n pendingEventCount,\n toggleFrozen: () => {\n setFrozenAtTotalEvents((currentValue) =>\n currentValue === null ? totalEvents : null,\n );\n },\n totalEvents,\n visibleEvents,\n };\n}\n\n/**\n * Appends a new event while keeping the TUI stream buffer size bounded.\n */\nexport function appendEventToStream(\n currentEvents: readonly AISnitchEvent[],\n event: AISnitchEvent,\n limit = EVENT_STREAM_LIMIT,\n): readonly AISnitchEvent[] {\n const nextEvents = [...currentEvents, event];\n\n if (nextEvents.length <= limit) {\n return nextEvents;\n }\n\n return nextEvents.slice(-limit);\n}\n\n/**\n * Calculates the currently visible event window, respecting frozen tail mode.\n */\nexport function getVisibleEventWindow(\n bufferedEvents: readonly AISnitchEvent[],\n options: {\n readonly anchorIndex?: number | null;\n readonly frozenAtTotalEvents?: number | null;\n readonly totalEvents: number;\n readonly visibleCount: number;\n },\n): readonly AISnitchEvent[] {\n if (options.anchorIndex !== undefined && options.anchorIndex !== null) {\n const clampedAnchorIndex = Math.max(\n 0,\n Math.min(options.anchorIndex, Math.max(0, bufferedEvents.length - 1)),\n );\n const halfWindow = Math.floor(options.visibleCount / 2);\n const tentativeStartIndex = Math.max(0, clampedAnchorIndex - halfWindow);\n const tentativeEndIndex = Math.min(\n bufferedEvents.length,\n tentativeStartIndex + options.visibleCount,\n );\n const visibleStartIndex = Math.max(\n 0,\n tentativeEndIndex - options.visibleCount,\n );\n\n return bufferedEvents.slice(visibleStartIndex, tentativeEndIndex);\n }\n\n const pendingEventCount = getPendingFrozenEventCount(\n options.totalEvents,\n options.frozenAtTotalEvents ?? null,\n );\n const visibleEndIndex =\n pendingEventCount === 0\n ? bufferedEvents.length\n : Math.max(0, bufferedEvents.length - pendingEventCount);\n const visibleStartIndex = Math.max(0, visibleEndIndex - options.visibleCount);\n\n return bufferedEvents.slice(visibleStartIndex, visibleEndIndex);\n}\n\n/**\n * Returns how many newer events are hidden while the stream is frozen.\n */\nexport function getPendingFrozenEventCount(\n totalEvents: number,\n frozenAtTotalEvents: number | null,\n): number {\n if (frozenAtTotalEvents === null) {\n return 0;\n }\n\n return Math.max(0, totalEvents - frozenAtTotalEvents);\n}\n\nfunction subscribeToEventStream(\n source: EventStreamSource,\n onEvent: (event: AISnitchEvent) => void,\n): () => void {\n if (source.kind === 'event-bus') {\n return source.eventBus.subscribe(onEvent);\n }\n\n const handleMessage = (data: RawData): void => {\n const parsedPayload = parseSocketPayload(data);\n\n if (parsedPayload !== null) {\n onEvent(parsedPayload);\n }\n };\n\n source.socket.on('message', handleMessage);\n\n return () => {\n source.socket.off('message', handleMessage);\n };\n}\n\nfunction parseSocketPayload(data: RawData): AISnitchEvent | null {\n const parsedPayload = parseUnknownPayload(data);\n\n if (\n typeof parsedPayload === 'object' &&\n parsedPayload !== null\n ) {\n const messageCandidate = parsedPayload as Record<string, unknown>;\n\n if (messageCandidate.type === 'welcome') {\n return null;\n }\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n return parsedEvent.success ? parsedEvent.data : null;\n}\n\nfunction parseUnknownPayload(data: RawData): unknown {\n try {\n if (typeof data === 'string') {\n return JSON.parse(data) as unknown;\n }\n\n if (Array.isArray(data)) {\n return JSON.parse(Buffer.concat(data).toString('utf8')) as unknown;\n }\n\n if (data instanceof ArrayBuffer) {\n return JSON.parse(\n Buffer.from(new Uint8Array(data)).toString('utf8'),\n ) as unknown;\n }\n\n return JSON.parse(Buffer.from(data).toString('utf8')) as unknown;\n } catch {\n // ๐Ÿ“– Malformed WebSocket frame โ€” return null instead of crashing\n return null;\n }\n}\n","import { useState, type Dispatch, type SetStateAction } from 'react';\nimport { useInput } from 'ink';\n\nimport {\n AISNITCH_EVENT_TYPES,\n type AISnitchEventType,\n type ToolName,\n} from '../../core/index.js';\nimport {\n DEFAULT_TUI_FILTERS,\n type TuiFilters,\n} from '../filters.js';\nimport type { TuiViewMode } from '../types.js';\n\n/**\n * @file src/tui/hooks/useKeyBinds.ts\n * @description Centralized keyboard controller for the AISnitch TUI, including filters, focus, help, and stream actions.\n * @functions\n * โ†’ useKeyBinds\n * @exports FocusedPanel, SelectorOption, TuiInteractionMode, UseKeyBindsOptions, UseKeyBindsState, useKeyBinds\n * @see ../components/FilterBar.tsx\n * @see ../components/HelpOverlay.tsx\n * @see ../App.tsx\n */\n\n/**\n * Panel focus ids supported by the current TUI.\n */\nexport type FocusedPanel = 'events' | 'sessions';\n\n/**\n * Generic selector option used by tool/type filter pickers.\n */\nexport interface SelectorOption<TValue> {\n readonly label: string;\n readonly value: TValue;\n}\n\n/**\n * Current interactive mode of the TUI.\n */\nexport type TuiInteractionMode =\n | {\n readonly kind: 'normal';\n }\n | {\n readonly kind: 'help';\n }\n | {\n readonly kind: 'search';\n readonly draft: string;\n }\n | {\n readonly kind: 'tool-filter';\n readonly options: readonly SelectorOption<ToolName | null>[];\n readonly selectedIndex: number;\n }\n | {\n readonly kind: 'type-filter';\n readonly options: readonly SelectorOption<AISnitchEventType | null>[];\n readonly selectedIndex: number;\n };\n\n/**\n * Inputs needed by the keyboard controller.\n */\nexport interface UseKeyBindsOptions {\n readonly fullDataModeEnabled?: boolean;\n readonly initialFilters?: Partial<TuiFilters>;\n readonly onClearStream: () => void;\n readonly onInspectorPageScroll?: (delta: number) => void;\n readonly onInspectorScroll?: (delta: number) => void;\n readonly onQuit?: () => void;\n readonly onRefreshStatus?: () => Promise<void> | void;\n readonly onSelectNextEvent?: () => void;\n readonly onSelectPreviousEvent?: () => void;\n readonly onToggleDaemon?: () => Promise<void> | void;\n readonly onToggleFreeze: () => void;\n readonly onToggleFullDataMode?: () => void;\n readonly toolOptions: readonly ToolName[];\n}\n\n/**\n * State returned by the keyboard controller.\n */\nexport interface UseKeyBindsState {\n readonly filters: TuiFilters;\n readonly focusPanel: FocusedPanel;\n readonly interaction: TuiInteractionMode;\n readonly viewMode: TuiViewMode;\n}\n\n/**\n * ๐Ÿ“– Keeping key handling in one hook prevents `App` from turning into a pile\n * of unrelated `useInput` branches as the TUI grows more interactive.\n */\nexport function useKeyBinds(\n options: UseKeyBindsOptions,\n): UseKeyBindsState {\n const toolOptions = buildToolOptions(options.toolOptions);\n const typeOptions = buildTypeOptions();\n const [filters, setFilters] = useState<TuiFilters>({\n ...DEFAULT_TUI_FILTERS,\n ...options.initialFilters,\n query: options.initialFilters?.query ?? '',\n });\n const [focusPanel, setFocusPanel] = useState<FocusedPanel>('events');\n const [interaction, setInteraction] = useState<TuiInteractionMode>({\n kind: 'normal',\n });\n const [viewMode, setViewMode] = useState<TuiViewMode>(\n options.fullDataModeEnabled === true ? 'full-data' : 'summary',\n );\n\n useInput((input, key) => {\n if (key.ctrl && input === 'c') {\n options.onQuit?.();\n return;\n }\n\n if (interaction.kind === 'search') {\n if (key.escape) {\n clearFilters(setFilters, setInteraction);\n return;\n }\n\n if (key.return) {\n setInteraction({\n kind: 'normal',\n });\n return;\n }\n\n if (key.backspace || key.delete) {\n const nextDraft = interaction.draft.slice(0, -1);\n\n setFilters((currentValue) => ({\n ...currentValue,\n query: nextDraft,\n }));\n setInteraction({\n kind: 'search',\n draft: nextDraft,\n });\n return;\n }\n\n if (!key.ctrl && !key.meta && input.length > 0) {\n const nextDraft = `${interaction.draft}${input}`;\n\n setFilters((currentValue) => ({\n ...currentValue,\n query: nextDraft,\n }));\n setInteraction({\n kind: 'search',\n draft: nextDraft,\n });\n }\n\n return;\n }\n\n if (\n interaction.kind === 'tool-filter' ||\n interaction.kind === 'type-filter'\n ) {\n if (key.escape) {\n clearFilters(setFilters, setInteraction);\n return;\n }\n\n if (key.upArrow || input === 'k') {\n setInteraction(moveSelector(interaction, -1));\n return;\n }\n\n if (key.downArrow || input === 'j') {\n setInteraction(moveSelector(interaction, 1));\n return;\n }\n\n if (key.return) {\n if (interaction.kind === 'tool-filter') {\n setFilters((currentValue) => ({\n ...currentValue,\n tool: interaction.options[interaction.selectedIndex]?.value ?? null,\n }));\n } else {\n setFilters((currentValue) => ({\n ...currentValue,\n eventType:\n interaction.options[interaction.selectedIndex]?.value ?? null,\n }));\n }\n\n setInteraction({\n kind: 'normal',\n });\n }\n\n return;\n }\n\n if (interaction.kind === 'help') {\n if (input === 'q') {\n options.onQuit?.();\n return;\n }\n\n if (input === '?' || key.escape || key.return) {\n setInteraction({\n kind: 'normal',\n });\n }\n\n return;\n }\n\n if (input === 'q') {\n options.onQuit?.();\n return;\n }\n\n if (input === 'v') {\n const nextViewMode = viewMode === 'summary' ? 'full-data' : 'summary';\n\n options.onToggleFullDataMode?.();\n setViewMode(nextViewMode);\n\n if (nextViewMode === 'summary' && focusPanel === 'sessions') {\n setFocusPanel('events');\n }\n\n return;\n }\n\n if (input === ' ') {\n options.onToggleFreeze();\n return;\n }\n\n if (input === 'c') {\n options.onClearStream();\n return;\n }\n\n if (input === 'd' && options.onToggleDaemon) {\n void options.onToggleDaemon();\n return;\n }\n\n if (input === 'r' && options.onRefreshStatus) {\n void options.onRefreshStatus();\n return;\n }\n\n if (input === '?') {\n setInteraction({\n kind: 'help',\n });\n return;\n }\n\n if (input === 'f') {\n setInteraction({\n kind: 'tool-filter',\n options: toolOptions,\n selectedIndex: getSelectedIndex(toolOptions, filters.tool),\n });\n return;\n }\n\n if (input === 't') {\n setInteraction({\n kind: 'type-filter',\n options: typeOptions,\n selectedIndex: getSelectedIndex(typeOptions, filters.eventType),\n });\n return;\n }\n\n if (input === '/') {\n setInteraction({\n kind: 'search',\n draft: filters.query,\n });\n return;\n }\n\n if (key.escape) {\n clearFilters(setFilters, setInteraction);\n return;\n }\n\n if (\n viewMode === 'full-data' &&\n (key.upArrow || input === 'k')\n ) {\n if (focusPanel === 'events') {\n options.onSelectPreviousEvent?.();\n } else {\n options.onInspectorScroll?.(-1);\n }\n return;\n }\n\n if (\n viewMode === 'full-data' &&\n (key.downArrow || input === 'j')\n ) {\n if (focusPanel === 'events') {\n options.onSelectNextEvent?.();\n } else {\n options.onInspectorScroll?.(1);\n }\n return;\n }\n\n if (viewMode === 'full-data' && input === '[') {\n options.onInspectorPageScroll?.(-1);\n return;\n }\n\n if (viewMode === 'full-data' && input === ']') {\n options.onInspectorPageScroll?.(1);\n return;\n }\n\n if (key.tab) {\n setFocusPanel((currentValue) =>\n currentValue === 'events' ? 'sessions' : 'events',\n );\n }\n });\n\n return {\n filters,\n focusPanel,\n interaction,\n viewMode,\n };\n}\n\nfunction buildToolOptions(\n tools: readonly ToolName[],\n): readonly SelectorOption<ToolName | null>[] {\n return [\n {\n label: 'All tools',\n value: null,\n },\n ...tools.map((tool) => ({\n label: tool,\n value: tool,\n })),\n ];\n}\n\nfunction buildTypeOptions(): readonly SelectorOption<AISnitchEventType | null>[] {\n return [\n {\n label: 'All event types',\n value: null,\n },\n ...AISNITCH_EVENT_TYPES.map((eventType) => ({\n label: eventType,\n value: eventType,\n })),\n ];\n}\n\nfunction getSelectedIndex<TValue>(\n options: readonly SelectorOption<TValue>[],\n value: TValue,\n): number {\n const selectedIndex = options.findIndex((option) => option.value === value);\n\n return selectedIndex === -1 ? 0 : selectedIndex;\n}\n\nfunction moveSelector(\n interaction:\n | Extract<TuiInteractionMode, { readonly kind: 'tool-filter' }>\n | Extract<TuiInteractionMode, { readonly kind: 'type-filter' }>,\n delta: number,\n):\n | Extract<TuiInteractionMode, { readonly kind: 'tool-filter' }>\n | Extract<TuiInteractionMode, { readonly kind: 'type-filter' }> {\n const nextIndex =\n (interaction.selectedIndex + delta + interaction.options.length) %\n interaction.options.length;\n\n return {\n ...interaction,\n selectedIndex: nextIndex,\n };\n}\n\nfunction clearFilters(\n setFilters: Dispatch<SetStateAction<TuiFilters>>,\n setInteraction: Dispatch<SetStateAction<TuiInteractionMode>>,\n): void {\n setFilters(DEFAULT_TUI_FILTERS);\n setInteraction({\n kind: 'normal',\n });\n}\n","import { useEffect, useState } from 'react';\n\nimport type {\n AISnitchEvent,\n AISnitchEventType,\n ToolName,\n} from '../../core/index.js';\nimport { formatSessionLabel, formatSessionShortId } from '../../core/index.js';\n\n/**\n * @file src/tui/hooks/useSessions.ts\n * @description Session aggregation helpers for the TUI, including active-session derivation and high-level activity status.\n * @functions\n * โ†’ useSessions\n * โ†’ deriveSessions\n * โ†’ deriveGlobalActivityStatus\n * @exports SESSION_STALE_AFTER_MS, SessionState, GlobalActivityStatus, useSessions, deriveSessions, deriveGlobalActivityStatus\n * @see ../components/SessionPanel.tsx\n * @see ../components/GlobalBadge.tsx\n * @see ../App.tsx\n */\n\n/**\n * Default timeout used to evict stale sessions that never emitted `session.end`.\n */\nexport const SESSION_STALE_AFTER_MS = 120_000;\n\n/**\n * Derived session model rendered by the TUI.\n */\nexport interface SessionState {\n readonly activeFile?: string;\n readonly cwd?: string;\n readonly currentState: AISnitchEventType;\n readonly displayLabel: string;\n readonly durationMs: number;\n readonly eventCount: number;\n readonly instanceIndex?: number;\n readonly instanceTotal?: number;\n readonly lastEventAt: string;\n readonly pid?: number;\n readonly project?: string;\n readonly projectPath?: string;\n readonly sessionId: string;\n readonly shortSessionId?: string;\n readonly startedAt: string;\n readonly tool: ToolName;\n}\n\n/**\n * High-level activity summary used by the header badge.\n */\nexport type GlobalActivityStatus = 'action-required' | 'ready' | 'working';\n\n/**\n * ๐Ÿ“– Sessions are derived from normalized events instead of being tracked as a\n * second independent runtime channel. That keeps the TUI honest: if the event\n * contract says one thing and the session panel says another, the bug is local\n * and debuggable.\n */\nexport function useSessions(\n events: readonly AISnitchEvent[],\n options: {\n readonly staleAfterMs?: number;\n } = {},\n): readonly SessionState[] {\n const [now, setNow] = useState(Date.now());\n\n useEffect(() => {\n const timer = setInterval(() => {\n setNow(Date.now());\n }, 1_000);\n timer.unref();\n\n return () => {\n clearInterval(timer);\n };\n }, []);\n\n return deriveSessions(events, {\n now,\n staleAfterMs: options.staleAfterMs,\n });\n}\n\n/**\n * Builds the active-session list from the normalized event buffer.\n */\nexport function deriveSessions(\n events: readonly AISnitchEvent[],\n options: {\n readonly now?: number;\n readonly staleAfterMs?: number;\n } = {},\n): readonly SessionState[] {\n const now = options.now ?? Date.now();\n const staleAfterMs = options.staleAfterMs ?? SESSION_STALE_AFTER_MS;\n const sessionMap = new Map<string, SessionState>();\n\n for (const event of events) {\n const existingSession = sessionMap.get(event['aisnitch.sessionid']);\n const startedAt =\n existingSession?.startedAt ??\n (event.type === 'session.start' ? event.time : event.time);\n const nextSession: SessionState = {\n activeFile: event.data.activeFile ?? existingSession?.activeFile,\n cwd: event.data.cwd ?? existingSession?.cwd,\n currentState: event.type,\n displayLabel: formatSessionLabel({\n activeFile: event.data.activeFile ?? existingSession?.activeFile,\n cwd: event.data.cwd ?? existingSession?.cwd,\n instanceIndex: event.data.instanceIndex ?? existingSession?.instanceIndex,\n instanceTotal: event.data.instanceTotal ?? existingSession?.instanceTotal,\n pid: event.data.pid ?? existingSession?.pid,\n project: event.data.project ?? existingSession?.project,\n projectPath: event.data.projectPath ?? existingSession?.projectPath,\n sessionId: event['aisnitch.sessionid'],\n tool: event['aisnitch.tool'],\n }),\n durationMs: Math.max(0, now - Date.parse(startedAt)),\n eventCount: (existingSession?.eventCount ?? 0) + 1,\n instanceIndex:\n event.data.instanceIndex ?? existingSession?.instanceIndex,\n instanceTotal:\n event.data.instanceTotal ?? existingSession?.instanceTotal,\n lastEventAt: event.time,\n pid: event.data.pid ?? existingSession?.pid,\n project: event.data.project ?? existingSession?.project,\n projectPath: event.data.projectPath ?? existingSession?.projectPath,\n sessionId: event['aisnitch.sessionid'],\n shortSessionId: formatSessionShortId(\n event['aisnitch.tool'],\n event['aisnitch.sessionid'],\n ),\n startedAt,\n tool: event['aisnitch.tool'],\n };\n\n sessionMap.set(event['aisnitch.sessionid'], nextSession);\n }\n\n return [...sessionMap.values()]\n .filter((session) => {\n if (session.currentState === 'session.end') {\n return false;\n }\n\n return now - Date.parse(session.lastEventAt) <= staleAfterMs;\n })\n .sort((left, right) => {\n return Date.parse(right.lastEventAt) - Date.parse(left.lastEventAt);\n });\n}\n\n/**\n * Derives the global activity badge state from the active sessions list.\n */\nexport function deriveGlobalActivityStatus(\n sessions: readonly SessionState[],\n): GlobalActivityStatus {\n if (\n sessions.some((session) =>\n session.currentState === 'agent.asking_user' ||\n session.currentState === 'agent.error',\n )\n ) {\n return 'action-required';\n }\n\n if (\n sessions.some((session) =>\n session.currentState === 'agent.coding' ||\n session.currentState === 'agent.thinking' ||\n session.currentState === 'agent.tool_call' ||\n session.currentState === 'agent.streaming' ||\n session.currentState === 'task.start',\n )\n ) {\n return 'working';\n }\n\n return 'ready';\n}\n","import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport WebSocket, { type RawData } from 'ws';\n\nimport { EventBus, AISnitchEventSchema } from '../core/index.js';\nimport type { AISnitchEvent } from '../core/index.js';\nimport { App } from './App.js';\nimport type {\n ManagedTuiSnapshot,\n TuiInitialFilters,\n TuiStatusSnapshot,\n} from './types.js';\n\n/**\n * @file src/tui/ManagedDaemonApp.tsx\n * @description PM2-style dashboard wrapper that keeps the TUI open even when the AISnitch daemon is offline.\n * @functions\n * โ†’ ManagedDaemonApp\n * โ†’ parseSocketPayload\n * @exports ManagedDaemonApp, type ManagedDaemonAppProps\n * @see ./App.tsx\n * @see ../cli/runtime.ts\n */\n\nconst DASHBOARD_REFRESH_INTERVAL_MS = 1_500;\n\n/**\n * Props required by the managed dashboard wrapper.\n */\nexport interface ManagedDaemonAppProps {\n readonly initialFilters?: TuiInitialFilters;\n readonly initialSnapshot: ManagedTuiSnapshot;\n readonly onQuit?: () => void;\n readonly refreshSnapshot: () => Promise<ManagedTuiSnapshot>;\n readonly toggleDaemon: () => Promise<ManagedTuiSnapshot>;\n readonly version: string;\n}\n\n/**\n * ๐Ÿ“– The managed dashboard keeps a local EventBus mirror so the UI can stay\n * mounted while daemon connectivity comes and goes underneath it.\n */\nexport function ManagedDaemonApp({\n initialFilters,\n initialSnapshot,\n onQuit,\n refreshSnapshot,\n toggleDaemon,\n version,\n}: ManagedDaemonAppProps): React.JSX.Element {\n const eventBus = useMemo(() => new EventBus(), []);\n const [snapshot, setSnapshot] = useState(initialSnapshot);\n const [busyAction, setBusyAction] = useState<'starting' | 'stopping' | null>(\n null,\n );\n const socketRef = useRef<WebSocket | null>(null);\n const refreshInFlightRef = useRef(false);\n\n useEffect(() => {\n let disposed = false;\n\n const refresh = async (): Promise<void> => {\n if (disposed || refreshInFlightRef.current || busyAction !== null) {\n return;\n }\n\n refreshInFlightRef.current = true;\n\n try {\n const nextSnapshot = await refreshSnapshot();\n\n if (!disposed) {\n setSnapshot(nextSnapshot);\n }\n } finally {\n refreshInFlightRef.current = false;\n }\n };\n\n const timer = setInterval(() => {\n void refresh();\n }, DASHBOARD_REFRESH_INTERVAL_MS);\n\n timer.unref();\n\n return () => {\n disposed = true;\n clearInterval(timer);\n };\n }, [busyAction, refreshSnapshot]);\n\n useEffect(() => {\n const daemon = snapshot.status.daemon;\n const currentSocket = socketRef.current;\n\n if (!daemon?.active) {\n if (currentSocket !== null) {\n socketRef.current = null;\n currentSocket.removeAllListeners();\n currentSocket.close();\n }\n\n return;\n }\n\n if (\n currentSocket !== null &&\n currentSocket.url === daemon.wsUrl &&\n (currentSocket.readyState === WebSocket.OPEN ||\n currentSocket.readyState === WebSocket.CONNECTING)\n ) {\n return;\n }\n\n if (currentSocket !== null) {\n socketRef.current = null;\n currentSocket.removeAllListeners();\n currentSocket.close();\n }\n\n const nextSocket = new WebSocket(daemon.wsUrl);\n socketRef.current = nextSocket;\n\n nextSocket.on('message', (payload: RawData) => {\n const parsedEvent = parseSocketPayload(payload);\n\n if (parsedEvent !== null) {\n eventBus.publish(parsedEvent);\n }\n });\n\n nextSocket.on('close', () => {\n if (socketRef.current === nextSocket) {\n socketRef.current = null;\n }\n });\n\n nextSocket.on('error', () => {\n if (socketRef.current === nextSocket) {\n socketRef.current = null;\n }\n });\n\n return () => {\n if (socketRef.current === nextSocket) {\n socketRef.current = null;\n }\n\n nextSocket.removeAllListeners();\n nextSocket.close();\n };\n }, [eventBus, snapshot.status.daemon]);\n\n useEffect(() => {\n return () => {\n const currentSocket = socketRef.current;\n\n if (currentSocket !== null) {\n currentSocket.removeAllListeners();\n currentSocket.close();\n }\n };\n }, []);\n\n async function handleRefresh(): Promise<void> {\n const nextSnapshot = await refreshSnapshot();\n setSnapshot(nextSnapshot);\n }\n\n async function handleToggleDaemon(): Promise<void> {\n const currentDaemon = snapshot.status.daemon;\n\n setBusyAction(currentDaemon?.active ? 'stopping' : 'starting');\n\n try {\n const nextSnapshot = await toggleDaemon();\n setSnapshot(nextSnapshot);\n } finally {\n setBusyAction(null);\n }\n }\n\n const effectiveStatus: TuiStatusSnapshot = {\n ...snapshot.status,\n daemon:\n snapshot.status.daemon === undefined\n ? undefined\n : {\n ...snapshot.status.daemon,\n busyAction,\n },\n };\n\n return (\n <App\n configuredAdapters={snapshot.configuredAdapters}\n initialFilters={initialFilters}\n managerControls={{\n onRefreshStatus: handleRefresh,\n onToggleDaemon: handleToggleDaemon,\n }}\n onQuit={onQuit}\n source={{\n kind: 'event-bus',\n eventBus,\n }}\n status={effectiveStatus}\n version={version}\n />\n );\n}\n\nfunction parseSocketPayload(data: RawData): AISnitchEvent | null {\n let parsedPayload: unknown;\n\n try {\n if (typeof data === 'string') {\n parsedPayload = JSON.parse(data) as unknown;\n } else if (Array.isArray(data)) {\n parsedPayload = JSON.parse(Buffer.concat(data).toString('utf8')) as unknown;\n } else if (data instanceof ArrayBuffer) {\n parsedPayload = JSON.parse(\n Buffer.from(new Uint8Array(data)).toString('utf8'),\n ) as unknown;\n } else {\n parsedPayload = JSON.parse(Buffer.from(data).toString('utf8')) as unknown;\n }\n } catch {\n // ๐Ÿ“– Malformed WebSocket frame โ€” silently ignore instead of crashing\n return null;\n }\n\n if (\n typeof parsedPayload === 'object' &&\n parsedPayload !== null &&\n 'type' in parsedPayload &&\n parsedPayload.type === 'welcome'\n ) {\n return null;\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n return parsedEvent.success ? parsedEvent.data : null;\n}\n","import type { AISnitchEventType, ToolName } from '../core/index.js';\n\n/**\n * @file src/tui/types.ts\n * @description Shared TUI runtime types reused by the renderer entrypoints, app shell, and CLI integration layer.\n * @functions\n * โ†’ none\n * @exports TUI_VIEW_MODES, TuiViewMode, TuiInitialFilters, TuiDaemonSnapshot, TuiStatusSnapshot, ManagedTuiSnapshot\n * @see ./App.tsx\n * @see ./index.tsx\n */\n\n/**\n * Supported body views for the interactive TUI.\n */\nexport const TUI_VIEW_MODES = ['summary', 'full-data'] as const;\n\n/**\n * Union of the TUI body views accepted by CLI and renderer code.\n */\nexport type TuiViewMode = (typeof TUI_VIEW_MODES)[number];\n\n/**\n * CLI or runtime-provided filters applied when the TUI opens.\n */\nexport interface TuiInitialFilters {\n readonly query?: string;\n readonly tool?: ToolName;\n readonly type?: AISnitchEventType;\n readonly view?: TuiViewMode;\n}\n\n/**\n * Optional daemon-management metadata displayed by the PM2-style dashboard.\n */\nexport interface TuiDaemonSnapshot {\n readonly active: boolean;\n readonly busyAction?: 'starting' | 'stopping' | null;\n readonly httpUrl: string;\n readonly pid: number | null;\n readonly socketPath: string | null;\n readonly wsUrl: string;\n}\n\n/**\n * Lightweight runtime snapshot consumed by the TUI shell.\n */\nexport interface TuiStatusSnapshot {\n readonly connected: boolean;\n readonly connectionLabel: string;\n readonly consumerCount: number;\n readonly daemon?: TuiDaemonSnapshot;\n readonly eventCount: number;\n readonly uptimeMs: number;\n}\n\n/**\n * Full renderer snapshot used by the managed dashboard mode.\n */\nexport interface ManagedTuiSnapshot {\n readonly configuredAdapters: readonly ToolName[];\n readonly status: TuiStatusSnapshot;\n}\n","import { once } from 'node:events';\n\nimport WebSocket, { type RawData } from 'ws';\n\nimport { AISnitchEventSchema } from '../core/events/index.js';\nimport type {\n AISnitchEvent,\n EventBus,\n WelcomeMessage,\n} from '../core/index.js';\nimport { formatSessionLabelFromEvent } from '../core/index.js';\nimport { formatEventDetail } from './event-details.js';\n\n/**\n * @file src/tui/live-monitor.ts\n * @description Lightweight plain-text live event monitor formatter retained for tests and fallback console output.\n * @functions\n * โ†’ formatEventLine\n * โ†’ formatWelcomeLine\n * โ†’ attachEventBusMonitor\n * โ†’ attachWebSocketMonitor\n * @exports MonitorOutput, MonitorCloseHandler, formatEventLine, formatWelcomeLine, attachEventBusMonitor, attachWebSocketMonitor\n * @see ../core/engine/ws-server.ts\n * @see ../core/events/schema.ts\n */\n\n/**\n * Minimal output contract shared by CLI monitor renderers.\n */\nexport interface MonitorOutput {\n readonly stdout: (text: string) => void;\n readonly stderr: (text: string) => void;\n}\n\n/**\n * Async close callback returned by monitor attach helpers.\n */\nexport type MonitorCloseHandler = () => Promise<void> | void;\n\n/**\n * ๐Ÿ“– The Ink TUI is now the primary operator surface, but these formatters are\n * still useful for tests and any future low-friction text fallbacks.\n */\nexport function formatEventLine(event: AISnitchEvent): string {\n const detail = formatEventDetail(event);\n const summary = detail ? ` :: ${detail}` : '';\n\n return [\n `[${event.time}]`,\n event['aisnitch.tool'],\n event.type,\n `session=${formatSessionLabelFromEvent(event)}`,\n `sid=${event['aisnitch.sessionid']}`,\n event.data.cwd ? `cwd=${event.data.cwd}` : undefined,\n ]\n .filter((value): value is string => typeof value === 'string')\n .join(' ') + summary;\n}\n\n/**\n * Formats the WebSocket welcome payload for human-readable output.\n */\nexport function formatWelcomeLine(message: WelcomeMessage): string {\n const tools =\n message.tools.length > 0 ? message.tools.join(', ') : 'none configured';\n\n return `Connected to AISnitch ${message.version} (tools: ${tools})`;\n}\n\n/**\n * Attaches a live writer to the in-process EventBus.\n */\nexport function attachEventBusMonitor(\n eventBus: EventBus,\n output: MonitorOutput,\n): MonitorCloseHandler {\n output.stdout('AISnitch live monitor attached (foreground mode).\\n');\n\n return eventBus.subscribe((event) => {\n output.stdout(`${formatEventLine(event)}\\n`);\n });\n}\n\n/**\n * Attaches to an existing daemon over WebSocket and streams monitor lines.\n */\nexport async function attachWebSocketMonitor(\n url: string,\n output: MonitorOutput,\n): Promise<MonitorCloseHandler> {\n const socket = new WebSocket(url);\n\n socket.on('message', (data) => {\n const parsedPayload = parseSocketMessage(data);\n\n if (isWelcomeMessage(parsedPayload)) {\n output.stdout(`${formatWelcomeLine(parsedPayload)}\\n`);\n return;\n }\n\n const parsedEvent = AISnitchEventSchema.safeParse(parsedPayload);\n\n if (parsedEvent.success) {\n output.stdout(`${formatEventLine(parsedEvent.data)}\\n`);\n return;\n }\n\n output.stderr('Received an unrecognized monitor payload.\\n');\n });\n\n socket.on('error', (error) => {\n output.stderr(\n `AISnitch attach socket error: ${\n error instanceof Error ? error.message : 'unknown error'\n }\\n`,\n );\n });\n\n await once(socket, 'open');\n\n return async () => {\n if (\n socket.readyState === WebSocket.CLOSING ||\n socket.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n socket.close();\n await once(socket, 'close');\n };\n}\n\nfunction parseSocketMessage(data: RawData): unknown {\n try {\n if (typeof data === 'string') {\n return JSON.parse(data) as unknown;\n }\n\n if (Array.isArray(data)) {\n return JSON.parse(Buffer.concat(data).toString('utf8')) as unknown;\n }\n\n if (data instanceof ArrayBuffer) {\n return JSON.parse(\n Buffer.from(new Uint8Array(data)).toString('utf8'),\n ) as unknown;\n }\n\n return JSON.parse(Buffer.from(data).toString('utf8')) as unknown;\n } catch {\n // ๐Ÿ“– Malformed WebSocket frame โ€” return null instead of crashing\n return null;\n }\n}\n\nfunction isWelcomeMessage(payload: unknown): payload is WelcomeMessage {\n if (typeof payload !== 'object' || payload === null) {\n return false;\n }\n\n const candidate = payload as Record<string, unknown>;\n\n return (\n candidate.type === 'welcome' &&\n typeof candidate.version === 'string' &&\n Array.isArray(candidate.tools)\n );\n}\n"],"mappings":"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","names":["basename","z","z","basename","execFileCallback","readFile","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","readFile","basename","execFileCallback","readFile","readdir","stat","basename","dirname","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getRecord","readFile","collectFilesRecursively","stat","listProcesses","mergedMetadata","isErrnoException","basename","dirname","readdir","execFileCallback","readFile","stat","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","readFile","stat","listProcesses","isRecord","getString","parseProcessLine","isErrnoException","execFileCallback","readFile","readdir","stat","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","readFile","basename","getRecord","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","parseProcessLine","execFileCallback","readFile","readdir","stat","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","getRecord","extractToolInput","readFile","basename","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","parseProcessLine","execFileCallback","readFile","readdir","stat","join","dirname","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","readFile","dirname","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","getRecord","parseProcessLine","execFileCallback","stat","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","stat","isRecord","getString","getRecord","extractLooseString","listProcesses","getNumber","parseJsonRecord","extractFirstString","execFileCallback","readFile","readdir","stat","basename","join","promisify","watch","execFile","promisify","execFileCallback","join","watch","isRecord","getString","getNumber","getRecord","extractToolInput","readFile","basename","collectFilesRecursively","stat","listProcesses","readdir","isErrnoException","parseProcessLine","execFileCallback","readFile","readdir","stat","basename","dirname","extname","join","promisify","watch","pidCwd","execFile","promisify","execFileCallback","join","pidCwd","watch","isRecord","getNumber","collectFilesRecursively","stat","parseJsonRecord","dirname","getString","basename","readFile","readdir","extname","getRecord","execFileCallback","promisify","execFile","promisify","execFileCallback","isRecord","getString","getNumber","getRecord","listProcesses","execFile","join","promisify","promisify","execFile","join","readFile","basename","join","join","readFile","basename","basename","execFileCallback","basename","promisify","pidCwd","execFile","promisify","execFileCallback","basename","pidCwd","basename","resolve","z","z","readFile","homedir","dirname","join","dirname","join","homedir","readFile","resolve","once","createServer","createServer","once","resolve","createServer","once","createServer","once","resolve","join","z","z","join","resolve","getTimeout","resolve","getString","getNumber","getBoolean","isRecord","WebSocket","useEffect","useState","Box","getRecord","getString","extractLooseString","isRecord","Box","Text","Box","Text","jsx","jsxs","Box","Text","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","Text","jsx","Text","Fragment","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","jsx","jsxs","Box","Text","Box","Text","Spinner","jsx","jsxs","Text","Box","Spinner","Box","Text","jsx","jsxs","Box","Text","visibleStartIndex","useState","useState","useEffect","useState","useState","useEffect","jsx","jsxs","useState","useEffect","Box","useEffect","useState","WebSocket","jsx","useState","useEffect","WebSocket","parseSocketPayload","once","WebSocket","WebSocket","once","jsx","WebSocket"]}