reasonix 0.37.0 → 0.38.0

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.
Files changed (74) hide show
  1. package/README.md +1 -0
  2. package/README.zh-CN.md +1 -0
  3. package/dist/cli/{chat-7257YAPG.js → chat-FPEYKTMI.js} +13 -14
  4. package/dist/cli/{chunk-T52GAWPP.js → chunk-3VTV4WAH.js} +2 -2
  5. package/dist/cli/{chunk-MSKUP6PD.js → chunk-4PNXH2MH.js} +910 -659
  6. package/dist/cli/chunk-4PNXH2MH.js.map +1 -0
  7. package/dist/cli/{chunk-YER7WCHF.js → chunk-A63QT566.js} +24 -10
  8. package/dist/cli/chunk-A63QT566.js.map +1 -0
  9. package/dist/cli/{chunk-4Q3GRJIU.js → chunk-AATCLE5N.js} +2 -2
  10. package/dist/cli/{chunk-BHLHOS5Y.js → chunk-BW2HWSYH.js} +315 -5
  11. package/dist/cli/chunk-BW2HWSYH.js.map +1 -0
  12. package/dist/cli/{chunk-ZJR4QLXB.js → chunk-FB46F6H4.js} +2 -2
  13. package/dist/cli/{chunk-GKZJXYMY.js → chunk-FYKZB6TX.js} +415 -11
  14. package/dist/cli/chunk-FYKZB6TX.js.map +1 -0
  15. package/dist/cli/{chunk-XQIFIB3U.js → chunk-JOFZ6AW5.js} +2 -2
  16. package/dist/cli/{chunk-JGZKTAOH.js → chunk-LMNAMITH.js} +2 -2
  17. package/dist/cli/{chunk-S4GF3HPO.js → chunk-LY352GTC.js} +6 -4
  18. package/dist/cli/chunk-LY352GTC.js.map +1 -0
  19. package/dist/cli/{chunk-VF57YX2M.js → chunk-NYP2DDDV.js} +40 -1
  20. package/dist/cli/chunk-NYP2DDDV.js.map +1 -0
  21. package/dist/cli/{chunk-JULZ7JTO.js → chunk-T5U5JO7Q.js} +11 -8
  22. package/dist/cli/chunk-T5U5JO7Q.js.map +1 -0
  23. package/dist/cli/{chunk-SEFXUF24.js → chunk-YJKLNYCP.js} +113 -24
  24. package/dist/cli/chunk-YJKLNYCP.js.map +1 -0
  25. package/dist/cli/{code-64EG5IU2.js → code-GTE65OUT.js} +23 -17
  26. package/dist/cli/{code-64EG5IU2.js.map → code-GTE65OUT.js.map} +1 -1
  27. package/dist/cli/{commands-FE2UDFBC.js → commands-R4JWISND.js} +3 -4
  28. package/dist/cli/{commands-FE2UDFBC.js.map → commands-R4JWISND.js.map} +1 -1
  29. package/dist/cli/{commit-3IAGB22T.js → commit-TQ4DMUNS.js} +2 -3
  30. package/dist/cli/{commit-3IAGB22T.js.map → commit-TQ4DMUNS.js.map} +1 -1
  31. package/dist/cli/{doctor-BW5HSQDW.js → doctor-GGK2JKTA.js} +6 -7
  32. package/dist/cli/index.js +24 -25
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/{mcp-2RDEQST6.js → mcp-M7I23TQ7.js} +2 -3
  35. package/dist/cli/{mcp-2RDEQST6.js.map → mcp-M7I23TQ7.js.map} +1 -1
  36. package/dist/cli/{mcp-browse-VM5GLRBQ.js → mcp-browse-TWO7RYT4.js} +2 -3
  37. package/dist/cli/{mcp-browse-VM5GLRBQ.js.map → mcp-browse-TWO7RYT4.js.map} +1 -1
  38. package/dist/cli/{prompt-KGIUONO3.js → prompt-ODPFOKSH.js} +2 -2
  39. package/dist/cli/{replay-D7RT2DR7.js → replay-R3QRXPI2.js} +13 -9
  40. package/dist/cli/replay-R3QRXPI2.js.map +1 -0
  41. package/dist/cli/{run-RWCOA32G.js → run-WGSPYYOJ.js} +7 -8
  42. package/dist/cli/{run-RWCOA32G.js.map → run-WGSPYYOJ.js.map} +1 -1
  43. package/dist/cli/{server-6ZW4TQUP.js → server-IZPWQYG3.js} +8 -9
  44. package/dist/cli/{server-6ZW4TQUP.js.map → server-IZPWQYG3.js.map} +1 -1
  45. package/dist/cli/{sessions-5ISNWFMU.js → sessions-E4UH5JYL.js} +7 -8
  46. package/dist/cli/{sessions-5ISNWFMU.js.map → sessions-E4UH5JYL.js.map} +1 -1
  47. package/dist/cli/{setup-HJG23NKJ.js → setup-FTZNN3TZ.js} +60 -15
  48. package/dist/cli/setup-FTZNN3TZ.js.map +1 -0
  49. package/dist/cli/{version-BXAN7Q4V.js → version-MDVCFTKA.js} +7 -8
  50. package/dist/cli/{version-BXAN7Q4V.js.map → version-MDVCFTKA.js.map} +1 -1
  51. package/dist/index.d.ts +3 -0
  52. package/dist/index.js +568 -40
  53. package/dist/index.js.map +1 -1
  54. package/package.json +1 -1
  55. package/dist/cli/chunk-BHLHOS5Y.js.map +0 -1
  56. package/dist/cli/chunk-GKZJXYMY.js.map +0 -1
  57. package/dist/cli/chunk-JULZ7JTO.js.map +0 -1
  58. package/dist/cli/chunk-MSKUP6PD.js.map +0 -1
  59. package/dist/cli/chunk-S4GF3HPO.js.map +0 -1
  60. package/dist/cli/chunk-SEFXUF24.js.map +0 -1
  61. package/dist/cli/chunk-VF57YX2M.js.map +0 -1
  62. package/dist/cli/chunk-WUI3P4RA.js +0 -319
  63. package/dist/cli/chunk-WUI3P4RA.js.map +0 -1
  64. package/dist/cli/chunk-YER7WCHF.js.map +0 -1
  65. package/dist/cli/replay-D7RT2DR7.js.map +0 -1
  66. package/dist/cli/setup-HJG23NKJ.js.map +0 -1
  67. /package/dist/cli/{chat-7257YAPG.js.map → chat-FPEYKTMI.js.map} +0 -0
  68. /package/dist/cli/{chunk-T52GAWPP.js.map → chunk-3VTV4WAH.js.map} +0 -0
  69. /package/dist/cli/{chunk-4Q3GRJIU.js.map → chunk-AATCLE5N.js.map} +0 -0
  70. /package/dist/cli/{chunk-ZJR4QLXB.js.map → chunk-FB46F6H4.js.map} +0 -0
  71. /package/dist/cli/{chunk-XQIFIB3U.js.map → chunk-JOFZ6AW5.js.map} +0 -0
  72. /package/dist/cli/{chunk-JGZKTAOH.js.map → chunk-LMNAMITH.js.map} +0 -0
  73. /package/dist/cli/{doctor-BW5HSQDW.js.map → doctor-GGK2JKTA.js.map} +0 -0
  74. /package/dist/cli/{prompt-KGIUONO3.js.map → prompt-ODPFOKSH.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/tools/jobs.ts","../../src/tools/shell.ts","../../src/core/pause-gate.ts","../../src/tools/shell/exec.ts","../../src/tools/shell-chain.ts","../../src/tools/shell/parse.ts"],"sourcesContent":["/** Background process registry for never-exiting commands; ready-signal detection short-circuits the startup wait. */\n\nimport { type ChildProcess, type SpawnOptions, spawn } from \"node:child_process\";\nimport * as pathMod from \"node:path\";\nimport { detectShellOperator, prepareSpawn, tokenizeCommand } from \"./shell.js\";\n\n/** Kills the whole tree — `child.kill` only hits the direct child, leaving npm-spawned dev servers orphaned. */\nfunction killProcessTree(pid: number, signal: \"SIGTERM\" | \"SIGKILL\"): void {\n if (process.platform === \"win32\") {\n // taskkill: /T = tree, /F = force (TerminateProcess, no cleanup).\n // Graceful path still uses /F on Windows because there's no signal\n // in the POSIX sense — the closest equivalent is Ctrl+Break, which\n // is unreliable from another console. /F with /T is what most\n // process managers ship on Windows.\n const args = [\"/pid\", String(pid), \"/T\"];\n if (signal === \"SIGKILL\") args.push(\"/F\");\n try {\n const killer = spawn(\"taskkill\", args, {\n stdio: \"ignore\",\n windowsHide: true,\n });\n // Swallow ENOENT / EACCES — we did our best. Not awaiting is\n // intentional: taskkill can take a few hundred ms and the caller\n // already has its own deadline.\n killer.on(\"error\", () => {\n /* ignore */\n });\n } catch {\n /* ignore */\n }\n return;\n }\n // POSIX: negative pid signals the whole process group. Requires the\n // spawn to have been detached (which `start()` does below).\n try {\n process.kill(-pid, signal);\n return;\n } catch {\n /* group-kill failed — fall back to direct */\n }\n try {\n process.kill(pid, signal);\n } catch {\n /* ignore — already dead */\n }\n}\n\n/** Per-job output ring. Capped so a chatty dev server doesn't OOM. */\nconst DEFAULT_OUTPUT_CAP_BYTES = 64 * 1024; // 64 KB\n\n/** First match cuts startup wait short; conservative patterns — a false negative costs a real stall. */\nconst READY_SIGNALS: ReadonlyArray<RegExp> = [\n // HTTP server banners\n /\\blistening on\\b/i,\n /\\blocal:\\s+https?:\\/\\//i,\n /\\bhttps?:\\/\\/(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0)(?::\\d+)?\\b/i,\n /\\b(?:ready|server started|started server|app listening)\\b/i,\n // Bundlers / compilers\n /\\bcompiled successfully\\b/i,\n /\\bbuild complete(?:d)?\\b/i,\n /\\bwatching for (?:file )?changes\\b/i,\n /\\bready in \\d+/i,\n // Generic\n /\\bstartup (?:complete|finished)\\b/i,\n];\n\nexport interface JobStartOptions {\n /** Absolute path to cwd for the spawned child. */\n cwd: string;\n /** Capped at 30; ready-signal match short-circuits. Default 3. */\n waitSec?: number;\n /** Signal plumbed through from the calling tool's AbortSignal. */\n signal?: AbortSignal;\n /** Total per-job output buffer cap (bytes). Default 64 KB. */\n maxBufferBytes?: number;\n}\n\nexport interface JobStartResult {\n jobId: number;\n pid: number | null;\n /** True iff the child was still running at the point we returned. */\n stillRunning: boolean;\n /** True iff a READY_SIGNALS pattern matched during the wait window. */\n readyMatched: boolean;\n /** Preview of combined stdout+stderr accumulated during the wait. */\n preview: string;\n /** If the child exited during the wait, its exit code; else null. */\n exitCode: number | null;\n}\n\nexport interface JobRecord {\n id: number;\n command: string;\n pid: number | null;\n startedAt: number;\n /** Exit code once the process terminates; null while running. */\n exitCode: number | null;\n /** Combined stdout+stderr, ring-trimmed. */\n output: string;\n /** Counts all bytes the child wrote, not just what's still buffered in `output`. */\n totalBytesWritten: number;\n /** True iff the child is still alive. */\n running: boolean;\n /** Error from spawn() itself (ENOENT, etc.) once surfaced. */\n spawnError?: string;\n}\n\nexport class JobRegistry {\n private readonly jobs = new Map<number, InternalJob>();\n private nextId = 1;\n\n /** Resolves on (a) ready signal, (b) early exit, or (c) waitSec deadline — child keeps running regardless. */\n async start(command: string, opts: JobStartOptions): Promise<JobStartResult> {\n const trimmed = command.trim();\n if (!trimmed) throw new Error(\"run_background: empty command\");\n const op = detectShellOperator(trimmed);\n if (op !== null) {\n throw new Error(\n `run_background: shell operator \"${op}\" is not supported — spawn one process per background job. Compose via your orchestration, not the shell.`,\n );\n }\n const argv = tokenizeCommand(trimmed);\n if (argv.length === 0) throw new Error(\"run_background: empty command\");\n const waitMs = Math.max(0, Math.min(30, opts.waitSec ?? 3)) * 1000;\n const maxBytes = opts.maxBufferBytes ?? DEFAULT_OUTPUT_CAP_BYTES;\n\n const { bin, args, spawnOverrides } = prepareSpawn(argv);\n const spawnOpts: SpawnOptions = {\n cwd: pathMod.resolve(opts.cwd),\n shell: false,\n windowsHide: true,\n env: process.env,\n // POSIX: detach so the child becomes its own process-group leader.\n // Required for `process.kill(-pid, …)` later — without it a group\n // kill fails and we end up only signaling the wrapper, leaving\n // grandchildren (node → vite → esbuild …) orphaned.\n // Windows: detached would spawn a new console window; leave the\n // default and use taskkill /T for tree termination.\n detached: process.platform !== \"win32\",\n ...spawnOverrides,\n };\n\n let child: ChildProcess;\n try {\n child = spawn(bin, args, spawnOpts);\n } catch (err) {\n // Can't even spawn — record a dead job so the model sees the\n // failure in list_jobs, and return a synthetic result.\n const id = this.nextId++;\n const job: InternalJob = {\n id,\n command: trimmed,\n pid: null,\n startedAt: Date.now(),\n exitCode: null,\n output: `[spawn failed] ${(err as Error).message}`,\n totalBytesWritten: 0,\n running: false,\n spawnError: (err as Error).message,\n child: null,\n readyPromise: Promise.resolve(),\n signalReady: () => {},\n closedPromise: Promise.resolve(),\n signalClosed: () => {},\n outputWaiters: new Set(),\n };\n this.jobs.set(id, job);\n return {\n jobId: id,\n pid: null,\n stillRunning: false,\n readyMatched: false,\n preview: job.output,\n exitCode: null,\n };\n }\n\n const id = this.nextId++;\n let readyResolve: () => void = () => {};\n const readyPromise = new Promise<void>((res) => {\n readyResolve = res;\n });\n let closedResolve: () => void = () => {};\n const closedPromise = new Promise<void>((res) => {\n closedResolve = res;\n });\n const job: InternalJob = {\n id,\n command: trimmed,\n pid: child.pid ?? null,\n startedAt: Date.now(),\n exitCode: null,\n output: \"\",\n totalBytesWritten: 0,\n running: true,\n child,\n readyPromise,\n signalReady: readyResolve,\n closedPromise,\n signalClosed: closedResolve,\n outputWaiters: new Set(),\n };\n this.jobs.set(id, job);\n\n let readyMatched = false;\n // Sliding window for cross-chunk ready-signal matching. A banner\n // line might land split across two reads — we want the regex to\n // see it as one piece — but testing against the full `job.output`\n // (which can be tens of KB by the time the server is up) is\n // O(N²) when 9 regexes each run on a growing buffer per chunk.\n // 1KB is comfortably bigger than any banner line we look for and\n // bounds the per-chunk regex cost regardless of total output.\n let recentForReady = \"\";\n const READY_WINDOW = 1024;\n const onData = (chunk: Buffer | string) => {\n const s = chunk.toString();\n job.totalBytesWritten += s.length;\n job.output += s;\n if (job.output.length > maxBytes) {\n // Drop the oldest bytes, but keep a marker so the model can see\n // output was truncated. Trim on a rough line boundary to avoid\n // chopping a line mid-sentence.\n const overflow = job.output.length - maxBytes;\n const cut = job.output.indexOf(\"\\n\", overflow);\n const start = cut >= 0 ? cut + 1 : overflow;\n job.output = `[… older output dropped …]\\n${job.output.slice(start)}`;\n }\n if (!readyMatched) {\n recentForReady = (recentForReady + s).slice(-READY_WINDOW);\n for (const re of READY_SIGNALS) {\n if (re.test(recentForReady)) {\n readyMatched = true;\n job.signalReady();\n break;\n }\n }\n }\n if (job.outputWaiters.size > 0) {\n const waiters = [...job.outputWaiters];\n job.outputWaiters.clear();\n for (const wake of waiters) wake();\n }\n };\n child.stdout?.on(\"data\", onData);\n child.stderr?.on(\"data\", onData);\n child.on(\"error\", (err) => {\n job.running = false;\n job.spawnError = err.message;\n job.signalReady();\n job.signalClosed();\n });\n child.on(\"close\", (code) => {\n job.running = false;\n job.exitCode = code;\n job.signalReady();\n job.signalClosed();\n });\n\n const onAbort = () => this.stop(id, { graceMs: 100 });\n if (opts.signal?.aborted) {\n onAbort();\n } else {\n opts.signal?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n // Race: (a) ready signal, (b) child exit, (c) wait deadline.\n let timer: ReturnType<typeof setTimeout> | null = null;\n await Promise.race([\n readyPromise,\n new Promise<void>((res) => {\n timer = setTimeout(res, waitMs);\n }),\n ]);\n if (timer) clearTimeout(timer);\n\n return {\n jobId: id,\n pid: job.pid,\n stillRunning: job.running,\n readyMatched,\n preview: job.output,\n exitCode: job.exitCode,\n };\n }\n\n read(id: number, opts: { since?: number; tailLines?: number } = {}): JobReadResult | null {\n const job = this.jobs.get(id);\n if (!job) return null;\n const full = job.output;\n let slice = full;\n if (typeof opts.since === \"number\" && opts.since >= 0 && opts.since < full.length) {\n slice = full.slice(opts.since);\n }\n if (typeof opts.tailLines === \"number\" && opts.tailLines > 0) {\n const lines = slice.split(\"\\n\");\n const keep = lines.slice(Math.max(0, lines.length - opts.tailLines));\n slice = keep.join(\"\\n\");\n }\n return {\n output: slice,\n byteLength: full.length,\n running: job.running,\n exitCode: job.exitCode,\n command: job.command,\n pid: job.pid,\n spawnError: job.spawnError,\n };\n }\n\n async waitForJob(id: number, opts: { timeoutMs?: number } = {}): Promise<JobWaitResult | null> {\n const job = this.jobs.get(id);\n if (!job) return null;\n if (!job.running) {\n return {\n exited: true,\n exitCode: job.exitCode,\n latestOutput: job.output,\n };\n }\n\n const timeoutMs = Math.max(0, Math.min(30_000, opts.timeoutMs ?? 5_000));\n const startOutput = job.output;\n let wakeOutput: (() => void) | null = null;\n const outputPromise = new Promise<void>((resolve) => {\n wakeOutput = resolve;\n job.outputWaiters.add(resolve);\n });\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n await Promise.race([\n job.closedPromise,\n outputPromise,\n new Promise<void>((resolve) => {\n timer = setTimeout(resolve, timeoutMs);\n }),\n ]);\n if (timer) clearTimeout(timer);\n if (wakeOutput) job.outputWaiters.delete(wakeOutput);\n\n return {\n exited: !job.running,\n exitCode: job.exitCode,\n latestOutput: latestOutputSince(startOutput, job.output),\n };\n }\n\n /** SIGTERM, wait graceMs, then SIGKILL. Idempotent on already-exited jobs. */\n async stop(id: number, opts: { graceMs?: number } = {}): Promise<JobRecord | null> {\n const job = this.jobs.get(id);\n if (!job) return null;\n if (!job.running || !job.child) return snapshot(job);\n const graceMs = Math.max(0, opts.graceMs ?? 2000);\n // Tree kill — reaches grandchildren (vite, esbuild, etc.) instead\n // of just the npm/cmd.exe wrapper that our direct child represents.\n // Falls back to child.kill() only when we somehow don't have a pid.\n if (job.pid !== null) {\n killProcessTree(job.pid, \"SIGTERM\");\n } else {\n try {\n job.child.kill(\"SIGTERM\");\n } catch {\n /* already dead — fall through */\n }\n }\n // closedPromise (not readyPromise) — readyPromise can have fired at\n // startup on a ready-signal regex match, which would short-circuit\n // this race even though the process is still alive.\n await Promise.race([job.closedPromise, new Promise<void>((res) => setTimeout(res, graceMs))]);\n if (job.running) {\n if (job.pid !== null) {\n killProcessTree(job.pid, \"SIGKILL\");\n } else {\n try {\n job.child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n // Wait for the actual close handler — a fixed timer can return\n // before Node's `close` event fires under load (Windows taskkill\n // /T /F on a three-level tree can take ~1s to propagate).\n await Promise.race([job.closedPromise, new Promise<void>((res) => setTimeout(res, 5000))]);\n }\n return snapshot(job);\n }\n\n list(): JobRecord[] {\n return [...this.jobs.values()].map(snapshot);\n }\n\n async shutdown(deadlineMs = 5000): Promise<void> {\n const start = Date.now();\n const runningJobs = [...this.jobs.values()].filter((j) => j.running && j.child);\n if (runningJobs.length === 0) return;\n\n for (const job of runningJobs) {\n if (job.pid !== null) killProcessTree(job.pid, \"SIGTERM\");\n else\n try {\n job.child?.kill(\"SIGTERM\");\n } catch {\n /* ignore */\n }\n }\n const allClose = Promise.all(runningJobs.map((j) => j.readyPromise));\n const elapsed = () => Date.now() - start;\n // Grace window: give well-behaved apps time to clean up, capped at\n // half the deadline so we always leave room for a SIGKILL pass +\n // reap confirmation.\n const graceMs = Math.min(1500, Math.max(0, deadlineMs / 2));\n await Promise.race([allClose, new Promise<void>((res) => setTimeout(res, graceMs))]);\n // Force-kill everything still alive.\n for (const job of runningJobs) {\n if (!job.running) continue;\n if (job.pid !== null) killProcessTree(job.pid, \"SIGKILL\");\n else\n try {\n job.child?.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n // Wait for close events post-SIGKILL. taskkill /T on Windows is\n // async — without this final wait, shutdown() can return while\n // grandchildren are still mid-teardown, which is what \"runningCount\n // non-zero after shutdown\" looks like.\n const remaining = Math.max(800, deadlineMs - elapsed());\n await Promise.race([allClose, new Promise<void>((res) => setTimeout(res, remaining))]);\n }\n\n /** Count of still-running jobs — drives the TUI status-bar indicator. */\n runningCount(): number {\n let n = 0;\n for (const job of this.jobs.values()) if (job.running) n++;\n return n;\n }\n}\n\ninterface InternalJob extends JobRecord {\n /** Underlying Node child process. Null only on spawn failure. */\n child: ChildProcess | null;\n /** Resolved when ready-signal fires OR the child exits. */\n readyPromise: Promise<void>;\n /** Fires readyPromise — called by ready-signal OR close/error handlers. */\n signalReady: () => void;\n /** Resolves only on close/error — never on ready-signal. Used by stop() to wait for actual exit. */\n closedPromise: Promise<void>;\n signalClosed: () => void;\n /** One-shot waiters for \"some new output arrived\". Cleared after every wake. */\n outputWaiters: Set<() => void>;\n}\n\nexport interface JobReadResult {\n output: string;\n /** Total bytes ever in the buffer (pre-slice). Caller passes back as `since`. */\n byteLength: number;\n running: boolean;\n exitCode: number | null;\n command: string;\n pid: number | null;\n spawnError?: string;\n}\n\nexport interface JobWaitResult {\n exited: boolean;\n exitCode: number | null;\n latestOutput: string;\n}\n\nfunction snapshot(job: InternalJob): JobRecord {\n return {\n id: job.id,\n command: job.command,\n pid: job.pid,\n startedAt: job.startedAt,\n exitCode: job.exitCode,\n output: job.output,\n totalBytesWritten: job.totalBytesWritten,\n running: job.running,\n spawnError: job.spawnError,\n };\n}\n\nfunction latestOutputSince(before: string, after: string): string {\n if (!before) return after;\n if (after.startsWith(before)) return after.slice(before.length);\n return after;\n}\n","/** cwd pinned to root; non-allowlisted commands throw to a UI confirm gate; spawn is `shell: false`, tokenized argv only. */\n\nimport * as pathMod from \"node:path\";\nimport { addProjectShellAllowed } from \"../config.js\";\nimport { pauseGate } from \"../core/pause-gate.js\";\nimport type { ToolRegistry } from \"../tools.js\";\nimport { JobRegistry } from \"./jobs.js\";\nimport {\n DEFAULT_MAX_OUTPUT_CHARS,\n DEFAULT_TIMEOUT_SEC,\n type RunCommandResult,\n runCommand,\n} from \"./shell/exec.js\";\nimport { isCommandAllowed } from \"./shell/parse.js\";\n\nexport {\n BUILTIN_ALLOWLIST,\n detectShellOperator,\n isAllowed,\n isCommandAllowed,\n isDqEscape,\n tokenizeCommand,\n} from \"./shell/parse.js\";\nexport type { ResolveExecutableOptions, RunCommandResult } from \"./shell/exec.js\";\nexport {\n injectPowerShellUtf8,\n killProcessTree,\n prepareSpawn,\n quoteForCmdExe,\n resolveExecutable,\n runCommand,\n smartDecodeOutput,\n withUtf8Codepage,\n} from \"./shell/exec.js\";\n\nexport interface ShellToolsOptions {\n /** Directory to run commands in. Must be an absolute path. */\n rootDir: string;\n /** Seconds before an individual command is killed. Default: 60. */\n timeoutSec?: number;\n maxOutputChars?: number;\n /** Getter form is load-bearing — newly-persisted \"always allow\" prefixes MUST take effect mid-session. */\n extraAllowed?: readonly string[] | (() => readonly string[]);\n /** Getter form lets `editMode === \"yolo\"` flip mid-session without re-registering tools. */\n allowAll?: boolean | (() => boolean);\n jobs?: JobRegistry;\n}\n\n/** Error thrown by `run_command` when the command isn't allowlisted. */\nexport class NeedsConfirmationError extends Error {\n readonly command: string;\n constructor(command: string) {\n super(\n `run_command: \"${command}\" needs the user's approval before it runs. STOP calling tools now — the TUI has already prompted the user to press y (run) or n (deny). Wait for their next message; it will either be the command's output (if they approved) or an instruction to continue without it (if they denied). Don't retry the command or call other shell commands in the meantime.`,\n );\n this.name = \"NeedsConfirmationError\";\n this.command = command;\n }\n}\n\nexport function registerShellTools(registry: ToolRegistry, opts: ShellToolsOptions): ToolRegistry {\n const rootDir = pathMod.resolve(opts.rootDir);\n const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC;\n const maxOutputChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;\n const jobs = opts.jobs ?? new JobRegistry();\n // Resolved on every dispatch so newly-persisted \"always allow\"\n // prefixes take effect inside the session that added them, not just\n // on the next launch. Static arrays are wrapped into a constant\n // getter so the call site below is uniform.\n const getExtraAllowed: () => readonly string[] =\n typeof opts.extraAllowed === \"function\"\n ? opts.extraAllowed\n : (() => {\n const snapshot = opts.extraAllowed ?? [];\n return () => snapshot;\n })();\n // Resolve dynamically so the TUI can flip yolo mode mid-session and\n // have the registry pick it up on the next dispatch. Static booleans\n // are wrapped into a thunk for uniformity.\n const isAllowAll: () => boolean =\n typeof opts.allowAll === \"function\" ? opts.allowAll : () => opts.allowAll === true;\n\n registry.register({\n name: \"run_command\",\n description:\n \"Run a shell command in the project root and return its combined stdout+stderr.\\n\\nConstraints (read these before the first call):\\n• Chain operators `|`, `||`, `&&`, `;` ARE supported — parsed natively, no shell invoked, so semantics are identical on Windows / macOS / Linux. Each chain segment is allowlist-checked individually: `git status | grep main` runs if both halves are allowed.\\n• File redirects ARE supported: `>` truncate, `>>` append, `<` stdin from file, `2>` / `2>>` stderr to file, `2>&1` merge stderr→stdout, `&>` both to file. Targets resolve relative to the project root. At most one redirect per fd per segment.\\n• Background `&`, heredoc `<<`, command substitution `$(…)`, subshells `(…)`, and process substitution `<(…)` are NOT supported. Wrap a literal `&` arg in quotes; for input use a `<` file or the binary's own --input flag.\\n• Env-var expansion `$VAR` is NOT performed — `$VAR` is passed as a literal string. Use the binary's own --env flag or substitute the value yourself.\\n• `cd` DOES NOT PERSIST between calls — each call spawns a fresh process rooted at the project. `cd` also does not persist within parsed chains like `cd dir && command`. Use a command-native cwd flag instead: `npm --prefix <dir> run <script>`, `npm --prefix <dir> exec -- <bin>`, `git -C <dir> ...`, `cargo -C <dir> ...`, `pytest <dir>/tests`.\\n• Glob patterns (`*.ts`) are passed through as literal arguments — no shell expansion. Use `grep -r`, `rg`, `find -name`, etc.\\n• Avoid commands with unbounded output (`netstat -ano`, `find /`, etc.) — they waste tokens. Filter at source: `netstat -ano -p TCP`, `find src -name '*.ts'`, `grep -c`, `wc -l`.\\n\\nCommon read-only inspection and test/lint/typecheck commands run immediately; anything that could mutate state, install dependencies, or touch the network is refused until the user confirms it in the TUI. Prefer this over asking the user to run a command manually — after edits, run the project's tests to verify.\",\n // Plan-mode gate: allow allowlisted commands through (git status,\n // cargo check, ls, grep …) so the model can actually investigate\n // during planning. Anything that would otherwise trigger a\n // confirmation prompt is treated as \"not read-only\" and bounced.\n readOnlyCheck: (args: { command?: unknown }) => {\n if (isAllowAll()) return true;\n const cmd = typeof args?.command === \"string\" ? args.command.trim() : \"\";\n if (!cmd) return false;\n return isCommandAllowed(cmd, getExtraAllowed());\n },\n parameters: {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description:\n 'Full command line. POSIX-ish quoting. Chain operators `|`, `||`, `&&`, `;` and file redirects `>` / `>>` / `<` / `2>` / `2>>` / `2>&1` / `&>` work natively (no shell). Background `&`, heredoc `<<`, env-var expansion `$VAR`, and command substitution `$(…)` are rejected (or passed through as literal in the case of `$VAR`). To pass an operator character as a literal argument (e.g. a regex), wrap it in quotes: `grep \"a|b\" file.txt`.',\n },\n timeoutSec: {\n type: \"integer\",\n description: `Override the default ${timeoutSec}s timeout for a single command.`,\n },\n },\n required: [\"command\"],\n },\n fn: async (args: { command: string; timeoutSec?: number }, ctx) => {\n const cmd = args.command.trim();\n if (!cmd) throw new Error(\"run_command: empty command\");\n if (!isAllowAll() && !isCommandAllowed(cmd, getExtraAllowed())) {\n const gate = ctx?.confirmationGate ?? pauseGate;\n const choice = await gate.ask({ kind: \"run_command\", payload: { command: cmd } });\n if (choice.type === \"deny\") {\n throw new Error(\n `user denied: ${cmd}${choice.denyContext ? ` — ${choice.denyContext}` : \"\"}`,\n );\n }\n if (choice.type === \"always_allow\") {\n addProjectShellAllowed(rootDir, choice.prefix);\n }\n // \"run_once\" — fall through and execute\n }\n const effectiveTimeout = Math.max(1, Math.min(600, args.timeoutSec ?? timeoutSec));\n const result = await runCommand(cmd, {\n cwd: rootDir,\n timeoutSec: effectiveTimeout,\n maxOutputChars,\n signal: ctx?.signal,\n });\n return formatCommandResult(cmd, result);\n },\n });\n\n registry.register({\n name: \"run_background\",\n description:\n \"Spawn a long-running process (dev server, watcher, any command that doesn't naturally exit) and detach. Waits up to `waitSec` seconds for startup (or until the output matches a readiness signal like 'Local:', 'listening on', 'compiled successfully'), then returns the job id + startup preview. The process keeps running; call `job_output` to tail its logs, `stop_job` to kill it, `list_jobs` to see all running jobs.\\n\\nSame shell constraints as run_command: NO `&&` / `||` / `|` / `;` / `>` / `<` / `2>&1`, `cd` doesn't persist. Dev servers that need a subdirectory: use the tool's own --prefix / --cwd flag. For Vite specifically, `--prefix` on npm only tells npm where package.json is; vite's server root still defaults to process cwd, so pass `vite <project-dir>` or configure via `vite.config.ts` root.\\n\\nUSE THIS — not `run_command` — for: npm/yarn/pnpm run dev, uvicorn / flask run, go run, cargo watch, tsc --watch, webpack serve, anything with 'dev' / 'serve' / 'watch' in the name.\",\n parameters: {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description:\n \"Full command line. Same quoting rules as run_command (no pipes / redirects / chaining).\",\n },\n waitSec: {\n type: \"integer\",\n description:\n \"Max seconds to wait for startup before returning. 0..30, default 3. A ready-signal match short-circuits this.\",\n },\n },\n required: [\"command\"],\n },\n fn: async (args: { command: string; waitSec?: number }, ctx) => {\n const cmd = args.command.trim();\n if (!cmd) throw new Error(\"run_background: empty command\");\n if (!isAllowAll() && !isCommandAllowed(cmd, getExtraAllowed())) {\n const gate = ctx?.confirmationGate ?? pauseGate;\n const choice = await gate.ask({ kind: \"run_background\", payload: { command: cmd } });\n if (choice.type === \"deny\") {\n throw new Error(\n `user denied: ${cmd}${choice.denyContext ? ` — ${choice.denyContext}` : \"\"}`,\n );\n }\n if (choice.type === \"always_allow\") {\n addProjectShellAllowed(rootDir, choice.prefix);\n }\n // \"run_once\" — fall through and execute\n }\n const result = await jobs.start(cmd, {\n cwd: rootDir,\n waitSec: args.waitSec,\n signal: ctx?.signal,\n });\n return formatJobStart(result);\n },\n });\n\n registry.register({\n name: \"job_output\",\n description:\n \"Read the latest output of a background job started with `run_background`. By default returns the tail of the buffer (last 80 lines). Pass `since` (the `byteLength` from a previous call) to stream only new content incrementally. Tells you whether the job is still running, so you can stop polling when it's done.\",\n readOnly: true,\n parallelSafe: true,\n stormExempt: true,\n parameters: {\n type: \"object\",\n properties: {\n jobId: { type: \"integer\", description: \"Job id returned by run_background.\" },\n since: {\n type: \"integer\",\n description:\n \"Return only output written past this byte offset (for incremental polling).\",\n },\n tailLines: {\n type: \"integer\",\n description: \"Cap the returned slice to the last N lines. Default 80, 0 = unlimited.\",\n },\n },\n required: [\"jobId\"],\n },\n fn: async (args: { jobId: number; since?: number; tailLines?: number }) => {\n const out = jobs.read(args.jobId, {\n since: args.since,\n tailLines: args.tailLines ?? 80,\n });\n if (!out) return `job ${args.jobId}: not found (use list_jobs)`;\n return formatJobRead(args.jobId, out);\n },\n });\n\n registry.register({\n name: \"wait_for_job\",\n description:\n \"Block until a background job exits or produces new output, bounded by `timeoutMs`. Use this instead of polling `job_output` with identical args when you're intentionally waiting for state to change. Returns JSON with `exited`, `exitCode`, and `latestOutput`.\",\n readOnly: true,\n parameters: {\n type: \"object\",\n properties: {\n jobId: { type: \"integer\", description: \"Job id returned by run_background.\" },\n timeoutMs: {\n type: \"integer\",\n description:\n \"Max time to block before returning if nothing changes. Clamped to 0..30000. Default 5000.\",\n },\n },\n required: [\"jobId\"],\n },\n fn: async (args: { jobId: number; timeoutMs?: number }) => {\n const out = await jobs.waitForJob(args.jobId, { timeoutMs: args.timeoutMs });\n if (!out) return `job ${args.jobId}: not found (use list_jobs)`;\n return {\n jobId: args.jobId,\n exited: out.exited,\n exitCode: out.exitCode,\n latestOutput: out.latestOutput,\n };\n },\n });\n\n registry.register({\n name: \"stop_job\",\n description:\n \"Stop a background job started with `run_background`. SIGTERM first; SIGKILL after a short grace period if it doesn't exit cleanly. Returns the final output + exit code. Safe to call on an already-exited job.\",\n parameters: {\n type: \"object\",\n properties: {\n jobId: { type: \"integer\" },\n },\n required: [\"jobId\"],\n },\n fn: async (args: { jobId: number }) => {\n const rec = await jobs.stop(args.jobId);\n if (!rec) return `job ${args.jobId}: not found`;\n return formatJobStop(rec);\n },\n });\n\n registry.register({\n name: \"list_jobs\",\n description:\n \"List every background job started this session — running and exited — with id, command, pid, status. Use when you've lost track of which job_id corresponds to which process, or to see what's still alive.\",\n readOnly: true,\n parallelSafe: true,\n stormExempt: true,\n parameters: { type: \"object\", properties: {} },\n fn: async () => {\n const all = jobs.list();\n if (all.length === 0) return \"(no background jobs started this session)\";\n return all.map(formatJobRow).join(\"\\n\");\n },\n });\n\n return registry;\n}\n\nfunction formatJobStart(r: import(\"./jobs.js\").JobStartResult): string {\n const header = r.stillRunning\n ? `[job ${r.jobId} started · pid ${r.pid ?? \"?\"} · ${r.readyMatched ? \"READY signal matched\" : \"running (no ready signal yet)\"}]`\n : r.exitCode !== null\n ? `[job ${r.jobId} exited during startup · exit ${r.exitCode}]`\n : `[job ${r.jobId} failed to start]`;\n return r.preview ? `${header}\\n${r.preview}` : header;\n}\n\nfunction formatJobRead(jobId: number, r: import(\"./jobs.js\").JobReadResult): string {\n const status = r.running\n ? `running · pid ${r.pid ?? \"?\"}`\n : r.exitCode !== null\n ? `exited ${r.exitCode}`\n : r.spawnError\n ? `failed (${r.spawnError})`\n : \"stopped\";\n const header = `[job ${jobId} · ${status} · byteLength=${r.byteLength}]\\n$ ${r.command}`;\n return r.output ? `${header}\\n${r.output}` : header;\n}\n\nfunction formatJobStop(r: import(\"./jobs.js\").JobRecord): string {\n const running = r.running\n ? \"still running (SIGKILL may be pending)\"\n : `exit ${r.exitCode ?? \"?\"}`;\n const tail = tailLines(r.output, 40);\n const header = `[job ${r.id} stopped · ${running}]\\n$ ${r.command}`;\n return tail ? `${header}\\n${tail}` : header;\n}\n\nfunction formatJobRow(r: import(\"./jobs.js\").JobRecord): string {\n const age = ((Date.now() - r.startedAt) / 1000).toFixed(1);\n const state = r.running\n ? `running · pid ${r.pid ?? \"?\"}`\n : r.exitCode !== null\n ? `exit ${r.exitCode}`\n : r.spawnError\n ? \"failed\"\n : \"stopped\";\n return ` ${String(r.id).padStart(3)} ${state.padEnd(24)} ${age}s ago $ ${r.command}`;\n}\n\nfunction tailLines(s: string, n: number): string {\n if (!s) return \"\";\n const lines = s.split(\"\\n\");\n if (lines.length <= n) return s;\n const dropped = lines.length - n;\n return [`[… ${dropped} earlier lines …]`, ...lines.slice(-n)].join(\"\\n\");\n}\n\nexport function formatCommandResult(cmd: string, r: RunCommandResult): string {\n const header = r.timedOut\n ? `$ ${cmd}\\n[killed after timeout]`\n : `$ ${cmd}\\n[exit ${r.exitCode ?? \"?\"}]`;\n return r.output ? `${header}\\n${r.output}` : header;\n}\n","/** Generic pause gate — bridges tool functions and the App's modals via Promises. */\n// Tools call gate.ask(kind, payload) and await the result; the App subscribes\n// with gate.on() to show the right modal, then calls gate.resolve() on user pick.\n\nexport type ConfirmationChoice =\n | { type: \"deny\"; denyContext?: string }\n | { type: \"run_once\" }\n | { type: \"always_allow\"; prefix: string };\n\nexport type PlanVerdict =\n | { type: \"approve\"; feedback?: string }\n | { type: \"refine\"; feedback?: string }\n | { type: \"cancel\"; feedback?: string };\n\nexport type CheckpointVerdict =\n | { type: \"continue\" }\n | { type: \"revise\"; feedback?: string }\n | { type: \"stop\" };\n\nexport type RevisionVerdict = { type: \"accepted\" } | { type: \"rejected\" } | { type: \"cancelled\" };\n\nexport type ChoiceVerdict =\n | { type: \"pick\"; optionId: string }\n | { type: \"text\"; text: string }\n | { type: \"cancel\" };\n\nexport type ToolConfirmationAuditEvent =\n | {\n type: \"tool.confirm.allow\";\n kind: \"run_command\" | \"run_background\";\n payload: { command: string };\n }\n | {\n type: \"tool.confirm.deny\";\n kind: \"run_command\" | \"run_background\";\n payload: { command: string };\n denyContext?: string;\n }\n | {\n type: \"tool.confirm.always_allow\";\n kind: \"run_command\" | \"run_background\";\n payload: { command: string };\n prefix: string;\n };\n\ninterface PauseResponseMap {\n run_command: ConfirmationChoice;\n run_background: ConfirmationChoice;\n plan_proposed: PlanVerdict;\n plan_checkpoint: CheckpointVerdict;\n plan_revision: RevisionVerdict;\n choice: ChoiceVerdict;\n}\n\ntype PauseKind = keyof PauseResponseMap;\n\ninterface PausePayloadMap {\n run_command: { command: string };\n run_background: { command: string };\n plan_proposed: { plan: string; steps?: unknown[]; summary?: string };\n plan_checkpoint: { stepId: string; title?: string; result: string; notes?: string };\n plan_revision: { reason: string; remainingSteps: unknown[]; summary?: string };\n choice: { question: string; options: unknown[]; allowCustom: boolean };\n}\n\nexport type PauseRequest = {\n id: number;\n kind: PauseKind;\n payload: unknown;\n};\n\ntype GateListener = (request: PauseRequest) => void;\ntype AuditListener = (event: ToolConfirmationAuditEvent) => void;\n\n/** Named options for PauseGate.ask() — makes it obvious which field is kind vs payload. */\nexport interface PauseAskOpts<K extends PauseKind = PauseKind> {\n kind: K;\n payload: PausePayloadMap[K];\n}\n\nexport class PauseGate {\n private _nextId = 0;\n private _pending = new Map<number, { resolve: (data: unknown) => void; request: PauseRequest }>();\n private _listeners: Set<GateListener> = new Set();\n private _auditListener: AuditListener | null = null;\n\n /** Block until the user responds. Takes a named options object so the\n * kind and payload fields don't get confused at the call site. */\n ask<K extends PauseKind>(opts: PauseAskOpts<K>): Promise<PauseResponseMap[K]> {\n const { kind, payload } = opts;\n if (this._listeners.size === 0) {\n throw new Error(\n `${kind}: no confirmation listener registered — cannot prompt the user. This tool can only be used inside an interactive Reasonix session.`,\n );\n }\n return new Promise((resolve) => {\n const id = this._nextId++;\n const request: PauseRequest = { id, kind, payload };\n this._pending.set(id, { resolve: resolve as (d: unknown) => void, request });\n for (const fn of this._listeners) {\n try {\n fn(request);\n } catch {\n /* listener error shouldn't break the gate */\n }\n }\n });\n }\n\n /** Resolve a pending request. Called by the App's modal callback. */\n resolve(id: number, data: unknown): void {\n const p = this._pending.get(id);\n if (!p) return;\n this._pending.delete(id);\n this.emitAuditEvent(p.request, data);\n p.resolve(data);\n }\n\n /** Safe-cancel every outstanding request — frees stranded tool fns on Esc / /new. */\n cancelAll(): void {\n const ids = [...this._pending.keys()];\n for (const id of ids) {\n const p = this._pending.get(id);\n if (!p) continue;\n this._pending.delete(id);\n p.resolve(safeCancelVerdict(p.request.kind));\n }\n }\n\n setAuditListener(fn: AuditListener | null): void {\n this._auditListener = fn;\n }\n\n /** Subscribe to new pause requests. Returns an unsubscribe function. */\n on(fn: GateListener): () => void {\n this._listeners.add(fn);\n return () => {\n this._listeners.delete(fn);\n };\n }\n\n /** Current pending request, if any (polling fallback). */\n get current(): PauseRequest | null {\n for (const [, p] of this._pending) return p.request;\n return null;\n }\n\n private emitAuditEvent(request: PauseRequest, data: unknown): void {\n if (!this._auditListener) return;\n if (request.kind !== \"run_command\" && request.kind !== \"run_background\") return;\n if (!data || typeof data !== \"object\") return;\n const choice = data as Partial<ConfirmationChoice>;\n try {\n switch (choice.type) {\n case \"run_once\":\n this._auditListener({\n type: \"tool.confirm.allow\",\n kind: request.kind,\n payload: request.payload as { command: string },\n });\n break;\n case \"deny\":\n this._auditListener({\n type: \"tool.confirm.deny\",\n kind: request.kind,\n payload: request.payload as { command: string },\n denyContext: choice.denyContext,\n });\n break;\n case \"always_allow\":\n if (typeof choice.prefix !== \"string\") return;\n this._auditListener({\n type: \"tool.confirm.always_allow\",\n kind: request.kind,\n payload: request.payload as { command: string },\n prefix: choice.prefix,\n });\n break;\n default:\n break;\n }\n } catch {\n /* audit path must never break the gate */\n }\n }\n}\n\nfunction safeCancelVerdict(kind: PauseKind): unknown {\n switch (kind) {\n case \"run_command\":\n case \"run_background\":\n return { type: \"deny\" };\n case \"plan_proposed\":\n return { type: \"cancel\" };\n case \"plan_checkpoint\":\n return { type: \"stop\" };\n case \"plan_revision\":\n return { type: \"cancelled\" };\n case \"choice\":\n return { type: \"cancel\" };\n }\n}\n\n/** Singleton shared between tools and the App. */\nexport const pauseGate = new PauseGate();\n","import { type ChildProcess, type SpawnOptions, spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, statSync } from \"node:fs\";\nimport * as pathMod from \"node:path\";\nimport { parseCommandChain, runChain } from \"../shell-chain.js\";\nimport { tokenizeCommand } from \"./parse.js\";\n\nexport const DEFAULT_TIMEOUT_SEC = 60;\nexport const DEFAULT_MAX_OUTPUT_CHARS = 32_000;\n\n/** Kill child + descendants. Windows: taskkill /T /F. Unix: SIGKILL the process group when detached, else fall back to SIGKILL on the leader. */\nexport function killProcessTree(child: ChildProcess): void {\n if (!child.pid || child.killed) return;\n if (process.platform === \"win32\") {\n try {\n spawnSync(\"taskkill\", [\"/pid\", String(child.pid), \"/T\", \"/F\"], {\n stdio: \"ignore\",\n windowsHide: true,\n });\n return;\n } catch {\n /* fall through to SIGKILL */\n }\n }\n try {\n process.kill(-child.pid, \"SIGKILL\");\n return;\n } catch {\n /* not a process group leader — fall through */\n }\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* already gone */\n }\n}\n\nexport interface RunCommandResult {\n exitCode: number | null;\n /** Combined stdout+stderr, truncated to `maxOutputChars` with a marker. */\n output: string;\n /** True when the process was killed for exceeding `timeoutSec`. */\n timedOut: boolean;\n}\n\nexport async function runCommand(\n cmd: string,\n opts: {\n cwd: string;\n timeoutSec?: number;\n maxOutputChars?: number;\n signal?: AbortSignal;\n },\n): Promise<RunCommandResult> {\n const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC;\n const maxChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;\n const argv = tokenizeCommand(cmd);\n if (argv.length === 0) throw new Error(\"run_command: empty command\");\n const chain = parseCommandChain(cmd);\n if (chain !== null) {\n return await runChain(chain, {\n cwd: opts.cwd,\n timeoutSec,\n maxOutputChars: maxChars,\n signal: opts.signal,\n });\n }\n const timeoutMs = timeoutSec * 1000;\n const normalizedEnv = normalizeWindowsEnvVars(process.env);\n\n const spawnOpts: SpawnOptions = {\n cwd: opts.cwd,\n shell: false, // no shell-expansion — see header comment\n windowsHide: true,\n // PYTHONIOENCODING + PYTHONUTF8 force any spawned Python child\n // (run_command running `python script.py`, etc.) to emit UTF-8\n // on stdout/stderr. Without this, Chinese-Windows defaults\n // Python's stdout encoder to GBK and `print(\"…\")` raises\n // UnicodeEncodeError on emoji / non-GBK chars — the model then\n // sees a Python traceback instead of the script's real output\n // and goes around in circles trying to fix the wrong problem.\n // Harmless on non-Python processes (env vars they don't read).\n env: { ...normalizedEnv, PYTHONIOENCODING: \"utf-8\", PYTHONUTF8: \"1\" },\n };\n\n // Windows: two layered fixes on top of shell:false —\n // 1. Resolve bare command names via PATH × PATHEXT (CreateProcess\n // ignores PATHEXT, so `npm` alone misses `npm.cmd`).\n // 2. Node 21.7.3+ (CVE-2024-27980) refuses to spawn `.cmd`/`.bat`\n // directly even with shell:false and safe args — throws\n // EINVAL at invocation time. Wrap those via `cmd.exe /d /s /c`\n // with verbatim args + manual quoting, so shell metacharacters\n // in arguments stay literal.\n // Unix path is unchanged.\n const { bin, args, spawnOverrides } = prepareSpawn(argv, { env: normalizedEnv });\n const effectiveSpawnOpts = { ...spawnOpts, ...spawnOverrides };\n\n return await new Promise<RunCommandResult>((resolve, reject) => {\n let child: import(\"node:child_process\").ChildProcess;\n try {\n child = spawn(bin, args, effectiveSpawnOpts);\n } catch (err) {\n reject(err);\n return;\n }\n // Collect raw Buffer chunks rather than decoding incrementally —\n // a multi-byte sequence can land split across chunks, and a naïve\n // chunk.toString() corrupts it before the second half arrives.\n // We decode once at close time, where smartDecodeOutput can also\n // sniff non-UTF-8 codepages cleanly. The byte cap mirrors the\n // prior char cap (2× maxChars worth) so a chatty process can't\n // OOM us.\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n const byteCap = maxChars * 2 * 4; // worst-case 4 bytes/char for utf-8/gbk\n let timedOut = false;\n let aborted = false;\n const killChildTree = () => killProcessTree(child);\n const killTimer = setTimeout(() => {\n timedOut = true;\n killChildTree();\n }, timeoutMs);\n const onAbort = () => {\n aborted = true;\n killChildTree();\n };\n // Check synchronously first — if the signal aborted before listener attach\n // (parent loop was already cancelled), addEventListener with `once:true`\n // never fires, child runs unbounded.\n if (opts.signal?.aborted) {\n onAbort();\n } else {\n opts.signal?.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n const onData = (chunk: Buffer | string) => {\n const b = typeof chunk === \"string\" ? Buffer.from(chunk) : chunk;\n if (totalBytes >= byteCap) return;\n const remaining = byteCap - totalBytes;\n if (b.length > remaining) {\n chunks.push(b.subarray(0, remaining));\n totalBytes = byteCap;\n } else {\n chunks.push(b);\n totalBytes += b.length;\n }\n };\n child.stdout?.on(\"data\", onData);\n child.stderr?.on(\"data\", onData);\n child.on(\"error\", (err) => {\n clearTimeout(killTimer);\n opts.signal?.removeEventListener(\"abort\", onAbort);\n reject(err);\n });\n child.on(\"close\", (code) => {\n clearTimeout(killTimer);\n opts.signal?.removeEventListener(\"abort\", onAbort);\n const merged = Buffer.concat(chunks);\n const buf = smartDecodeOutput(merged);\n const output =\n buf.length > maxChars\n ? `${buf.slice(0, maxChars)}\\n\\n[… truncated ${buf.length - maxChars} chars …]`\n : buf;\n resolve({ exitCode: code, output, timedOut });\n });\n });\n}\n\n/** GBK fallback on Windows — cmd.exe's localized error DLL and native EXE stderr ignore chcp 65001. */\nexport function smartDecodeOutput(buf: Buffer): string {\n if (buf.length === 0) return \"\";\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(buf);\n } catch {\n // Fall through to platform-specific fallback.\n }\n if (process.platform === \"win32\") {\n try {\n // TextDecoder supports gbk / gb18030 in Node 18+ via the WHATWG\n // Encoding spec. gb18030 is the modern superset; falling back\n // to it covers GBK byte sequences plus the rare 4-byte CJK\n // characters that appear in newer system messages.\n return new TextDecoder(\"gb18030\").decode(buf);\n } catch {\n // Decoder unavailable in this build — fall through.\n }\n }\n // Last resort: lossy UTF-8 with replacement chars. The model still\n // gets \"something happened\" with the structural exit-code marker\n // intact, which is more useful than throwing away the entire output.\n return buf.toString(\"utf8\");\n}\n\nexport interface ResolveExecutableOptions {\n platform?: NodeJS.Platform;\n env?: { PATH?: string; PATHEXT?: string };\n isFile?: (path: string) => boolean;\n pathDelimiter?: string;\n}\n\n/** CreateProcess ignores PATHEXT — bare `npm` fails ENOENT under `shell:false` without this resolver. */\nexport function resolveExecutable(cmd: string, opts: ResolveExecutableOptions = {}): string {\n const platform = opts.platform ?? process.platform;\n if (platform !== \"win32\") return cmd;\n if (!cmd) return cmd;\n // Already a path fragment — spawn handles these natively.\n if (cmd.includes(\"/\") || cmd.includes(\"\\\\\") || pathMod.isAbsolute(cmd)) return cmd;\n // If the model wrote `npm.cmd` explicitly, respect that verbatim.\n if (pathMod.extname(cmd)) return cmd;\n\n const env = opts.env ?? process.env;\n const pathExt = (getEnvCaseInsensitive(env, \"PATHEXT\") ?? \".COM;.EXE;.BAT;.CMD\")\n .split(\";\")\n .map((e) => e.trim())\n .filter(Boolean);\n const delimiter = opts.pathDelimiter ?? (platform === \"win32\" ? \";\" : pathMod.delimiter);\n const pathDirs = (getEnvCaseInsensitive(env, \"PATH\") ?? \"\").split(delimiter).filter(Boolean);\n const isFile = opts.isFile ?? defaultIsFile;\n\n for (const dir of pathDirs) {\n for (const ext of pathExt) {\n // Force win32 join so CI tests that pass `platform: \"win32\"`\n // from a Linux runner get backslash-joined paths; the real-\n // Windows runtime path lands here too and gets the correct\n // separator regardless of where pathMod defaults.\n const full = pathMod.win32.join(dir, cmd + ext);\n if (isFile(full)) return full;\n }\n }\n return cmd;\n}\n\nexport function normalizeWindowsEnvVars(\n env: NodeJS.ProcessEnv,\n opts: { platform?: NodeJS.Platform } = {},\n): NodeJS.ProcessEnv {\n const platform = opts.platform ?? process.platform;\n if (platform !== \"win32\") return { ...env };\n\n const out: NodeJS.ProcessEnv = {};\n const pathValues: string[] = [];\n const pathExtValues: string[] = [];\n\n for (const [key, value] of Object.entries(env)) {\n const lower = key.toLowerCase();\n if (lower === \"path\") {\n if (typeof value === \"string\") pathValues.push(value);\n continue;\n }\n if (lower === \"pathext\") {\n if (typeof value === \"string\") pathExtValues.push(value);\n continue;\n }\n out[key] = value;\n }\n\n if (pathValues.length > 0) out.Path = mergeWindowsPathLike(pathValues, \";\");\n if (pathExtValues.length > 0) out.PATHEXT = mergeWindowsPathLike(pathExtValues, \";\");\n\n return out;\n}\n\nfunction getEnvCaseInsensitive(\n env: Record<string, string | undefined>,\n key: string,\n): string | undefined {\n const exact = env[key];\n if (exact !== undefined) return exact;\n const target = key.toLowerCase();\n for (const [candidate, value] of Object.entries(env)) {\n if (candidate.toLowerCase() === target) return value;\n }\n return undefined;\n}\n\nfunction mergeWindowsPathLike(values: readonly string[], delimiter: string): string {\n const seen = new Set<string>();\n const merged: string[] = [];\n\n for (const value of values) {\n for (const part of value.split(delimiter)) {\n const entry = part.trim();\n if (!entry) continue;\n const normalized = entry.toLowerCase();\n if (seen.has(normalized)) continue;\n seen.add(normalized);\n merged.push(entry);\n }\n }\n\n return merged.join(delimiter);\n}\n\nfunction defaultIsFile(full: string): boolean {\n try {\n return existsSync(full) && statSync(full).isFile();\n } catch {\n return false;\n }\n}\n\n/** Windows workarounds: PATHEXT lookup + CVE-2024-27980 prohibition on direct `.cmd`/`.bat` spawn. */\nexport function prepareSpawn(\n argv: readonly string[],\n opts: ResolveExecutableOptions = {},\n): { bin: string; args: string[]; spawnOverrides: SpawnOptions } {\n const head = argv[0] ?? \"\";\n const tail = argv.slice(1);\n const platform = opts.platform ?? process.platform;\n const resolved = resolveExecutable(head, opts);\n\n if (platform !== \"win32\") {\n return { bin: resolved, args: [...tail], spawnOverrides: {} };\n }\n\n // `.cmd` / `.bat` wrappers require cmd.exe on post-CVE Node.\n if (/\\.(cmd|bat)$/i.test(resolved)) {\n const cmdline = [resolved, ...tail].map(quoteForCmdExe).join(\" \");\n return {\n bin: \"cmd.exe\",\n args: [\"/d\", \"/s\", \"/c\", withUtf8Codepage(cmdline)],\n // windowsVerbatimArguments prevents Node from re-quoting the /c\n // payload — we've already composed an exact cmd.exe command\n // line. Without this Node wraps our already-quoted string in\n // another round of quotes and cmd.exe can't parse it.\n spawnOverrides: { windowsVerbatimArguments: true },\n };\n }\n\n // Bare command names that PATH × PATHEXT couldn't resolve to an\n // on-disk file — these are almost always cmd.exe built-ins (`dir`,\n // `echo`, `type`, `ver`, `vol`, `where`, `help`, …) which don't\n // exist as standalone executables. Direct spawn crashes with ENOENT;\n // routing through cmd.exe lets the built-in resolve, and if it's\n // genuinely unknown the user gets the standard \"'foo' is not\n // recognized\" message instead of a raw spawn failure.\n if (isBareWindowsName(resolved) && resolved === head) {\n const cmdline = [head, ...tail].map(quoteForCmdExe).join(\" \");\n return {\n bin: \"cmd.exe\",\n args: [\"/d\", \"/s\", \"/c\", withUtf8Codepage(cmdline)],\n spawnOverrides: { windowsVerbatimArguments: true },\n };\n }\n\n // PowerShell variants: chcp 65001 doesn't help here because PowerShell\n // sets its own [Console]::OutputEncoding at startup — usually system\n // codepage (CP936/CP932/CP949 on CJK Windows) or UTF-16. The result\n // is mojibake when our `chunk.toString()` UTF-8-decodes its stdout.\n // Inject a UTF-8 setup prelude into the `-Command` (or `-c`) arg so\n // any output produced thereafter is UTF-8.\n if (isPowerShellExe(resolved)) {\n const patched = injectPowerShellUtf8(tail);\n if (patched) {\n return { bin: resolved, args: patched, spawnOverrides: {} };\n }\n }\n\n return { bin: resolved, args: [...tail], spawnOverrides: {} };\n}\n\n/** Resolved bin path looks like Windows PowerShell or PowerShell Core. */\nfunction isPowerShellExe(resolved: string): boolean {\n return /(?:^|[\\\\/])(?:powershell|pwsh)(?:\\.exe)?$/i.test(resolved);\n}\n\n/** Targets `-Command` only — PowerShell quoting is finicky enough that wrapping script-file mode could break it. */\nexport function injectPowerShellUtf8(args: readonly string[]): string[] | null {\n const prelude =\n \"[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;$OutputEncoding=[System.Text.Encoding]::UTF8;\";\n for (let i = 0; i < args.length; i++) {\n const a = args[i] ?? \"\";\n if (/^-(?:Command|c)$/i.test(a) && i + 1 < args.length) {\n const out = [...args];\n out[i + 1] = `${prelude}${args[i + 1] ?? \"\"}`;\n return out;\n }\n }\n return null;\n}\n\n/** Single `&` (not `&&`) so the command still runs on Win7 where chcp can return non-zero. */\nexport function withUtf8Codepage(cmdline: string): string {\n return `chcp 65001 >nul & ${cmdline}`;\n}\n\nfunction isBareWindowsName(s: string): boolean {\n if (!s) return false;\n if (s.includes(\"/\") || s.includes(\"\\\\\")) return false;\n if (pathMod.isAbsolute(s)) return false;\n if (pathMod.extname(s)) return false;\n return true;\n}\n\n/** Doubles embedded quotes per cmd.exe's `\"\"` escape rule; bare alnum passes through unquoted. */\nexport function quoteForCmdExe(arg: string): string {\n if (arg === \"\") return '\"\"';\n if (!/[\\s\"&|<>^%(),;!]/.test(arg)) return arg;\n return `\"${arg.replace(/\"/g, '\"\"')}\"`;\n}\n","/** Parse + spawn `cmd1 | cmd2 && cmd3 > out` ourselves — never invoke a shell, sidestep PS5.1's `&&` parse error and codepage drift. */\n\nimport { type ChildProcess, type SpawnOptions, spawn } from \"node:child_process\";\nimport { closeSync, openSync } from \"node:fs\";\nimport * as pathMod from \"node:path\";\nimport { isDqEscape, killProcessTree, prepareSpawn, smartDecodeOutput } from \"./shell.js\";\n\nexport type ChainOp = \"|\" | \"||\" | \"&&\" | \";\";\n\nexport type RedirectKind = \">\" | \">>\" | \"<\" | \"2>\" | \"2>>\" | \"2>&1\" | \"&>\";\n\nexport interface Redirect {\n kind: RedirectKind;\n /** File path resolved against the chain's cwd; empty for `2>&1`. */\n target: string;\n}\n\nexport interface ChainSegment {\n argv: string[];\n redirects: Redirect[];\n}\n\nexport interface CommandChain {\n segments: ChainSegment[];\n /** length === segments.length - 1 */\n ops: ChainOp[];\n}\n\nexport class UnsupportedSyntaxError extends Error {\n constructor(detail: string) {\n super(`run_command: ${detail}`);\n this.name = \"UnsupportedSyntaxError\";\n }\n}\n\n/** Whitespace-bounded splitter — chain ops only count when they begin a token, so `--flag=1&2` stays literal. */\nfunction splitOnChainOps(cmd: string): { segs: string[]; ops: ChainOp[] } {\n const segs: string[] = [];\n const ops: ChainOp[] = [];\n let segStart = 0;\n let i = 0;\n let quote: '\"' | \"'\" | null = null;\n let atTokenStart = true;\n while (i < cmd.length) {\n const ch = cmd[i]!;\n if (quote) {\n if (ch === quote) quote = null;\n else if (quote === '\"' && isDqEscape(ch, cmd[i + 1])) i++;\n i++;\n atTokenStart = false;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n i++;\n atTokenStart = false;\n continue;\n }\n if (ch === \" \" || ch === \"\\t\") {\n i++;\n atTokenStart = true;\n continue;\n }\n if (atTokenStart) {\n let op: ChainOp | null = null;\n let opLen = 0;\n const next = cmd[i + 1];\n if (ch === \"|\" && next === \"|\") {\n op = \"||\";\n opLen = 2;\n } else if (ch === \"&\" && next === \"&\") {\n op = \"&&\";\n opLen = 2;\n } else if (ch === \"|\") {\n op = \"|\";\n opLen = 1;\n } else if (ch === \";\") {\n op = \";\";\n opLen = 1;\n }\n if (op !== null) {\n segs.push(cmd.slice(segStart, i));\n ops.push(op);\n i += opLen;\n segStart = i;\n atTokenStart = true;\n continue;\n }\n }\n i++;\n atTokenStart = false;\n }\n segs.push(cmd.slice(segStart));\n return { segs, ops };\n}\n\n/** Single-pass parser: extract argv + trailing/inline redirects from one segment string. */\nfunction parseSegment(segStr: string): ChainSegment {\n const argv: string[] = [];\n const redirects: Redirect[] = [];\n let cur = \"\";\n let curHasContent = false;\n let pending: RedirectKind | null = null;\n let quote: '\"' | \"'\" | null = null;\n const flush = () => {\n if (!curHasContent && cur.length === 0) return;\n if (pending) {\n redirects.push({ kind: pending, target: cur });\n pending = null;\n } else {\n argv.push(cur);\n }\n cur = \"\";\n curHasContent = false;\n };\n let i = 0;\n while (i < segStr.length) {\n const ch = segStr[i]!;\n if (quote) {\n if (ch === quote) {\n quote = null;\n } else if (quote === '\"' && isDqEscape(ch, segStr[i + 1])) {\n cur += segStr[++i] ?? \"\";\n curHasContent = true;\n } else {\n cur += ch;\n curHasContent = true;\n }\n i++;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n curHasContent = true;\n i++;\n continue;\n }\n if (ch === \" \" || ch === \"\\t\") {\n flush();\n i++;\n continue;\n }\n if (cur.length === 0 && !curHasContent) {\n const remaining = segStr.slice(i);\n let matched: { op: RedirectKind; len: number } | null = null;\n if (remaining.startsWith(\"2>&1\")) matched = { op: \"2>&1\", len: 4 };\n else if (remaining.startsWith(\"&>\")) matched = { op: \"&>\", len: 2 };\n else if (remaining.startsWith(\"2>>\")) matched = { op: \"2>>\", len: 3 };\n else if (remaining.startsWith(\"2>\")) matched = { op: \"2>\", len: 2 };\n else if (remaining.startsWith(\">>\")) matched = { op: \">>\", len: 2 };\n else if (remaining.startsWith(\">\")) matched = { op: \">\", len: 1 };\n else if (remaining.startsWith(\"<<\")) {\n throw new UnsupportedSyntaxError(\n 'shell operator \"<<\" is not supported — heredoc / here-string is not implemented; pass input via a \"<\" file or the binary\\'s --input flag',\n );\n } else if (remaining.startsWith(\"<\")) matched = { op: \"<\", len: 1 };\n if (matched) {\n if (pending !== null) {\n throw new UnsupportedSyntaxError(\n `redirect \"${pending}\" is missing a target file before \"${matched.op}\"`,\n );\n }\n if (matched.op === \"2>&1\") {\n redirects.push({ kind: \"2>&1\", target: \"\" });\n } else {\n pending = matched.op;\n }\n i += matched.len;\n continue;\n }\n if (ch === \"&\") {\n throw new UnsupportedSyntaxError(\n 'shell operator \"&\" is not supported — background runs need run_background, not run_command. Wrap a literal `&` arg in quotes.',\n );\n }\n }\n cur += ch;\n curHasContent = true;\n i++;\n }\n if (quote) throw new Error(`unclosed ${quote} in command`);\n flush();\n if (pending) throw new UnsupportedSyntaxError(`redirect \"${pending}\" is missing a target file`);\n if (argv.length === 0 && redirects.length > 0) {\n throw new UnsupportedSyntaxError(\n \"redirect without a command — segment must have at least one program argument\",\n );\n }\n validateRedirectFds(redirects);\n return { argv, redirects };\n}\n\n/** stdin (`<`) ≤1, stdout (`>`/`>>`/`&>`) ≤1, stderr (`2>`/`2>>`/`&>`/`2>&1`) ≤1; reject conflicts. */\nfunction validateRedirectFds(redirects: readonly Redirect[]): void {\n let stdin = 0;\n let stdout = 0;\n let stderr = 0;\n for (const r of redirects) {\n if (r.kind === \"<\") stdin++;\n else if (r.kind === \">\" || r.kind === \">>\") stdout++;\n else if (r.kind === \"2>\" || r.kind === \"2>>\" || r.kind === \"2>&1\") stderr++;\n else if (r.kind === \"&>\") {\n stdout++;\n stderr++;\n }\n }\n if (stdin > 1) throw new UnsupportedSyntaxError(\"multiple `<` stdin redirects in one segment\");\n if (stdout > 1)\n throw new UnsupportedSyntaxError(\n \"multiple stdout redirects in one segment (`>` / `>>` / `&>` conflict)\",\n );\n if (stderr > 1)\n throw new UnsupportedSyntaxError(\n \"multiple stderr redirects in one segment (`2>` / `2>>` / `&>` / `2>&1` conflict)\",\n );\n}\n\n/** Returns null on plain commands without redirects (caller takes the simple path). */\nexport function parseCommandChain(cmd: string): CommandChain | null {\n const { segs, ops } = splitOnChainOps(cmd);\n const segments: ChainSegment[] = [];\n for (let i = 0; i < segs.length; i++) {\n const trimmed = segs[i]!.trim();\n if (trimmed.length === 0) {\n const op = i === 0 ? ops[0]! : ops[i - 1]!;\n throw new UnsupportedSyntaxError(\n i === 0\n ? `empty segment before \"${op}\"`\n : i === segs.length - 1\n ? `chain ends with \"${op}\"`\n : `empty segment between \"${ops[i - 1]}\" and \"${ops[i]}\"`,\n );\n }\n segments.push(parseSegment(trimmed));\n }\n // Reject `cd` inside parsed chains — the executor cannot carry cwd\n // changes between segments, and silently running the wrong directory\n // is worse than rejecting early with clear guidance.\n for (const seg of segments) {\n const cmdName = seg.argv[0] ?? \"\";\n if (cmdName.toLowerCase() === \"cd\") {\n throw new UnsupportedSyntaxError(\n \"cd in parsed command chains does not change cwd for later segments. Use a command-native cwd flag instead, such as `npm --prefix <dir> run <script>`, `git -C <dir> ...`, or `cargo -C <dir> ...`.\",\n );\n }\n }\n\n if (ops.length === 0 && segments[0]!.redirects.length === 0) return null;\n return { segments, ops };\n}\n\n/** Each segment must individually clear the allowlist for the chain to auto-run. */\nexport function chainAllowed(\n chain: CommandChain,\n isAllowed: (segmentCmd: string) => boolean,\n): boolean {\n for (const seg of chain.segments) {\n if (!isAllowed(seg.argv.join(\" \"))) return false;\n }\n return true;\n}\n\nexport interface ChainResult {\n exitCode: number | null;\n output: string;\n timedOut: boolean;\n}\n\ninterface ChainGroup {\n segments: ChainSegment[];\n /** Op connecting the PREVIOUS group to THIS one (`||`, `&&`, `;`); null on the first group. */\n opBefore: Exclude<ChainOp, \"|\"> | null;\n}\n\n/** Pipe groups are runs of segments joined by `|`; sequential ops (`||`, `&&`, `;`) split them. */\nfunction groupChain(chain: CommandChain): ChainGroup[] {\n const groups: ChainGroup[] = [{ segments: [chain.segments[0]!], opBefore: null }];\n for (let i = 0; i < chain.ops.length; i++) {\n const op = chain.ops[i]!;\n const next = chain.segments[i + 1]!;\n if (op === \"|\") {\n groups[groups.length - 1]!.segments.push(next);\n } else {\n groups.push({ segments: [next], opBefore: op });\n }\n }\n return groups;\n}\n\nexport interface RunChainOptions {\n cwd: string;\n timeoutSec: number;\n maxOutputChars: number;\n signal?: AbortSignal;\n}\n\nexport async function runChain(chain: CommandChain, opts: RunChainOptions): Promise<ChainResult> {\n const groups = groupChain(chain);\n const buf = new OutputBuffer(opts.maxOutputChars * 2 * 4);\n const deadline = Date.now() + opts.timeoutSec * 1000;\n let lastExit: number | null = 0;\n let timedOut = false;\n for (const group of groups) {\n if (group.opBefore === \"&&\" && lastExit !== 0) continue;\n if (group.opBefore === \"||\" && lastExit === 0) continue;\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) {\n timedOut = true;\n break;\n }\n const result = await runPipeGroup(group.segments, {\n cwd: opts.cwd,\n timeoutMs: remainingMs,\n buf,\n signal: opts.signal,\n });\n lastExit = result.exitCode;\n if (result.timedOut) {\n timedOut = true;\n break;\n }\n if (opts.signal?.aborted) break;\n }\n const output = buf.toString();\n const truncated =\n output.length > opts.maxOutputChars\n ? `${output.slice(0, opts.maxOutputChars)}\\n\\n[… truncated ${output.length - opts.maxOutputChars} chars …]`\n : output;\n return { exitCode: lastExit, output: truncated, timedOut };\n}\n\ninterface PipeGroupResult {\n exitCode: number | null;\n timedOut: boolean;\n}\n\ninterface PipeGroupOptions {\n cwd: string;\n timeoutMs: number;\n buf: OutputBuffer;\n signal?: AbortSignal;\n}\n\ninterface SegmentStdio {\n /** Input fd for `<` redirect, or null when reading from prev pipe / nothing. */\n stdinFd: number | null;\n /** Output fd for `>`/`>>`/`&>` redirect, or null when writing to pipe / our buffer. */\n stdoutFd: number | null;\n /** Output fd for `2>`/`2>>`/`&>` redirect, or null when default. */\n stderrFd: number | null;\n mergeStderrToStdout: boolean;\n toClose: number[];\n}\n\nfunction openRedirects(redirects: readonly Redirect[], cwd: string): SegmentStdio {\n let stdinFd: number | null = null;\n let stdoutFd: number | null = null;\n let stderrFd: number | null = null;\n let mergeStderrToStdout = false;\n let bothFd: number | null = null;\n const toClose: number[] = [];\n const open = (target: string, flags: \"r\" | \"w\" | \"a\"): number => {\n const resolved = pathMod.resolve(cwd, target);\n const fd = openSync(resolved, flags);\n toClose.push(fd);\n return fd;\n };\n for (const r of redirects) {\n if (r.kind === \"<\") stdinFd = open(r.target, \"r\");\n else if (r.kind === \">\") stdoutFd = open(r.target, \"w\");\n else if (r.kind === \">>\") stdoutFd = open(r.target, \"a\");\n else if (r.kind === \"2>\") stderrFd = open(r.target, \"w\");\n else if (r.kind === \"2>>\") stderrFd = open(r.target, \"a\");\n else if (r.kind === \"&>\") {\n bothFd = open(r.target, \"w\");\n stdoutFd = bothFd;\n stderrFd = bothFd;\n } else if (r.kind === \"2>&1\") {\n mergeStderrToStdout = true;\n }\n }\n return { stdinFd, stdoutFd, stderrFd, mergeStderrToStdout, toClose };\n}\n\nasync function runPipeGroup(\n segments: ChainSegment[],\n opts: PipeGroupOptions,\n): Promise<PipeGroupResult> {\n const env = { ...process.env, PYTHONIOENCODING: \"utf-8\", PYTHONUTF8: \"1\" };\n const children: ChildProcess[] = [];\n const allFds: number[] = [];\n let timedOut = false;\n const killAll = () => {\n for (const c of children) killProcessTree(c);\n };\n const killTimer = setTimeout(() => {\n timedOut = true;\n killAll();\n }, opts.timeoutMs);\n const onAbort = () => killAll();\n if (opts.signal?.aborted) {\n onAbort();\n } else {\n opts.signal?.addEventListener(\"abort\", onAbort, { once: true });\n }\n try {\n for (let i = 0; i < segments.length; i++) {\n const isFirst = i === 0;\n const isLast = i === segments.length - 1;\n const seg = segments[i]!;\n const io = openRedirects(seg.redirects, opts.cwd);\n allFds.push(...io.toClose);\n const { bin, args, spawnOverrides } = prepareSpawn(seg.argv);\n const stdoutSpec = io.stdoutFd !== null ? io.stdoutFd : \"pipe\";\n const stderrSpec =\n io.stderrFd !== null ? io.stderrFd : io.mergeStderrToStdout ? stdoutSpec : \"pipe\";\n const stdinSpec = io.stdinFd !== null ? io.stdinFd : isFirst ? \"ignore\" : \"pipe\";\n const spawnOpts: SpawnOptions = {\n cwd: opts.cwd,\n shell: false,\n windowsHide: true,\n env,\n stdio: [stdinSpec, stdoutSpec, stderrSpec],\n ...spawnOverrides,\n };\n let child: ChildProcess;\n try {\n child = spawn(bin, args, spawnOpts);\n } catch (err) {\n for (const fd of allFds) tryClose(fd);\n killAll();\n clearTimeout(killTimer);\n opts.signal?.removeEventListener(\"abort\", onAbort);\n throw err;\n }\n children.push(child);\n if (!isFirst && io.stdinFd === null) {\n const prev = children[i - 1]!;\n prev.stdout?.on(\"error\", () => {});\n child.stdin?.on(\"error\", () => {});\n const prevMergesStderr =\n segments[i - 1]!.redirects.some((r) => r.kind === \"2>&1\") && !!prev.stderr;\n if (prevMergesStderr && prev.stderr) {\n prev.stderr.on(\"error\", () => {});\n let openSources = 2;\n const closeIfDone = () => {\n if (--openSources === 0) child.stdin?.end();\n };\n prev.stdout?.pipe(child.stdin!, { end: false });\n prev.stderr.pipe(child.stdin!, { end: false });\n prev.stdout?.once(\"end\", closeIfDone);\n prev.stderr.once(\"end\", closeIfDone);\n } else {\n prev.stdout?.pipe(child.stdin!);\n }\n }\n if (child.stderr && io.stderrFd === null && !(io.mergeStderrToStdout && !isLast)) {\n child.stderr.on(\"data\", (chunk: Buffer | string) => opts.buf.push(toBuf(chunk)));\n }\n if (isLast && child.stdout && io.stdoutFd === null) {\n child.stdout.on(\"data\", (chunk: Buffer | string) => opts.buf.push(toBuf(chunk)));\n if (io.mergeStderrToStdout && child.stderr && io.stderrFd === null) {\n child.stderr.removeAllListeners(\"data\");\n child.stderr.on(\"data\", (chunk: Buffer | string) => opts.buf.push(toBuf(chunk)));\n }\n }\n }\n const exits = await Promise.all(\n children.map(\n (c) =>\n new Promise<number | null>((resolve) => {\n c.once(\"error\", () => resolve(null));\n c.once(\"close\", (code) => resolve(code));\n }),\n ),\n );\n return { exitCode: exits[exits.length - 1] ?? null, timedOut };\n } finally {\n for (const fd of allFds) tryClose(fd);\n clearTimeout(killTimer);\n opts.signal?.removeEventListener(\"abort\", onAbort);\n }\n}\n\nfunction tryClose(fd: number): void {\n try {\n closeSync(fd);\n } catch {\n /* already closed by spawn handover or kernel */\n }\n}\n\nfunction toBuf(chunk: Buffer | string): Buffer {\n return typeof chunk === \"string\" ? Buffer.from(chunk) : chunk;\n}\n\nclass OutputBuffer {\n private chunks: Buffer[] = [];\n private bytes = 0;\n constructor(private readonly cap: number) {}\n push(b: Buffer): void {\n if (this.bytes >= this.cap) return;\n const remaining = this.cap - this.bytes;\n if (b.length > remaining) {\n this.chunks.push(b.subarray(0, remaining));\n this.bytes = this.cap;\n } else {\n this.chunks.push(b);\n this.bytes += b.length;\n }\n }\n toString(): string {\n return smartDecodeOutput(Buffer.concat(this.chunks));\n }\n}\n","import { type CommandChain, chainAllowed, parseCommandChain } from \"../shell-chain.js\";\n\n/** Read-only reports + test runners whose failure mode is \"exit 1 with output\". */\nexport const BUILTIN_ALLOWLIST: ReadonlyArray<string> = [\n // Repo inspection\n \"git status\",\n \"git diff\",\n \"git log\",\n \"git show\",\n \"git blame\",\n \"git branch\",\n \"git remote\",\n \"git rev-parse\",\n \"git config --get\",\n // Filesystem inspection\n \"ls\",\n \"pwd\",\n \"cat\",\n \"head\",\n \"tail\",\n \"wc\",\n \"file\",\n \"tree\",\n \"find\",\n \"grep\",\n \"rg\",\n // Language version probes\n \"node --version\",\n \"node -v\",\n \"npm --version\",\n \"npx --version\",\n \"python --version\",\n \"python3 --version\",\n \"cargo --version\",\n \"go version\",\n \"rustc --version\",\n \"deno --version\",\n \"bun --version\",\n // Test runners (non-destructive by convention)\n \"npm test\",\n \"npm run test\",\n \"npx vitest run\",\n \"npx vitest\",\n \"npx jest\",\n \"pytest\",\n \"python -m pytest\",\n \"cargo test\",\n \"cargo check\",\n \"cargo clippy\",\n \"go test\",\n \"go vet\",\n \"deno test\",\n \"bun test\",\n // Linters / typecheckers (read-only by convention)\n \"npm run lint\",\n \"npm run typecheck\",\n \"npx tsc --noEmit\",\n \"npx biome check\",\n \"npx eslint\",\n \"npx prettier --check\",\n \"ruff\",\n \"mypy\",\n];\n\n/** Inside `\"…\"` only `\\\"` and `\\\\` are escapes — `\\X` otherwise stays literal so Windows paths like `\"C:\\Users\\foo\\.bar\"` survive tokenization. */\nexport function isDqEscape(prev: string, next: string | undefined): boolean {\n return prev === \"\\\\\" && (next === '\"' || next === \"\\\\\");\n}\n\n/** No env / glob / backtick / `$(…)` expansion — prevents bypass of allowlist via concatenation. */\nexport function tokenizeCommand(cmd: string): string[] {\n const out: string[] = [];\n let cur = \"\";\n let quote: '\"' | \"'\" | null = null;\n for (let i = 0; i < cmd.length; i++) {\n const ch = cmd[i]!;\n if (quote) {\n if (ch === quote) {\n quote = null;\n } else if (quote === '\"' && isDqEscape(ch, cmd[i + 1])) {\n cur += cmd[++i];\n } else {\n cur += ch;\n }\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n continue;\n }\n if (ch === \" \" || ch === \"\\t\") {\n if (cur.length > 0) {\n out.push(cur);\n cur = \"\";\n }\n continue;\n }\n cur += ch;\n }\n if (quote) throw new Error(`unclosed ${quote} in command`);\n if (cur.length > 0) out.push(cur);\n return out;\n}\n\n/** Up-front detection — without it, `dir | findstr foo` quotes `|` literal and pipe silently fails. */\nexport function detectShellOperator(cmd: string): string | null {\n const opPrefix = /^(?:2>&1|&>|\\|{1,2}|&{1,2}|2>{1,2}|>{1,2}|<{1,2})/;\n let cur = \"\";\n let curQuoted = false;\n let quote: '\"' | \"'\" | null = null;\n const check = (): string | null => {\n if (cur.length === 0 && !curQuoted) return null;\n if (!curQuoted) {\n const m = opPrefix.exec(cur);\n if (m) return m[0] ?? null;\n }\n return null;\n };\n for (let i = 0; i < cmd.length; i++) {\n const ch = cmd[i]!;\n if (quote) {\n if (ch === quote) {\n quote = null;\n } else if (quote === '\"' && isDqEscape(ch, cmd[i + 1])) {\n cur += cmd[++i];\n curQuoted = true;\n } else {\n cur += ch;\n curQuoted = true;\n }\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n curQuoted = true;\n continue;\n }\n if (ch === \" \" || ch === \"\\t\") {\n const op = check();\n if (op) return op;\n cur = \"\";\n curQuoted = false;\n continue;\n }\n cur += ch;\n }\n if (quote) return null; // let tokenizeCommand throw the unclosed-quote error\n return check();\n}\n\n/** Per-prefix demotion: an otherwise-allowlisted match falls back to the confirm gate when one of these tokens appears in the tail. Issue #257: `git branch -D` skipped review. Each token also matches its `--flag=value` form. */\nconst RISKY_ARGS: Readonly<Record<string, ReadonlyArray<string>>> = {\n // Branch / remote mutation\n \"git branch\": [\"-d\", \"-D\", \"--delete\", \"-m\", \"-M\", \"--move\", \"-c\", \"-C\", \"--copy\", \"--force\"],\n \"git remote\": [\"add\", \"remove\", \"rm\", \"rename\", \"set-url\", \"set-head\", \"prune\"],\n // `--output` writes to an arbitrary path; `--ext-diff` invokes user-config'd external programs.\n \"git diff\": [\"--output\", \"--ext-diff\"],\n \"git log\": [\"--output\"],\n \"git show\": [\"--output\"],\n // `-exec*` / `-ok*` are RCE; `-delete` and `-fprint*` / `-fls` write to arbitrary paths.\n find: [\n \"-delete\",\n \"-exec\",\n \"-execdir\",\n \"-ok\",\n \"-okdir\",\n \"-fprint\",\n \"-fprint0\",\n \"-fprintf\",\n \"-fls\",\n ],\n // `-o FILE` writes the tree to an arbitrary path.\n tree: [\"-o\"],\n // Auto-fix mutates source files.\n \"npx eslint\": [\"--fix\", \"--fix-dry-run\"],\n \"npx biome check\": [\"--write\", \"--apply\", \"--apply-unsafe\"],\n ruff: [\"--fix\", \"--unsafe-fixes\", \"format\"],\n};\n\nfunction tailHasRisky(tail: readonly string[], risky: readonly string[]): boolean {\n for (const a of tail) {\n for (const r of risky) {\n if (a === r) return true;\n if (a.startsWith(`${r}=`)) return true;\n }\n }\n return false;\n}\n\n/** Allowlist match on leading argv tokens; demoted by `RISKY_ARGS` when a destructive flag appears in the tail. */\nexport function isAllowed(cmd: string, extra: readonly string[] = []): boolean {\n let argv: string[];\n try {\n argv = tokenizeCommand(cmd);\n } catch {\n return false;\n }\n if (argv.length === 0) return false;\n\n const allowlist = [...BUILTIN_ALLOWLIST, ...extra];\n for (const prefix of allowlist) {\n const prefixTokens = prefix.split(\" \");\n if (argv.length < prefixTokens.length) continue;\n let match = true;\n for (let i = 0; i < prefixTokens.length; i++) {\n if (argv[i] !== prefixTokens[i]) {\n match = false;\n break;\n }\n }\n if (!match) continue;\n\n const risky = RISKY_ARGS[prefix];\n if (risky && tailHasRisky(argv.slice(prefixTokens.length), risky)) return false;\n return true;\n }\n return false;\n}\n\n/** For chain commands, every segment must individually clear the allowlist. */\nexport function isCommandAllowed(cmd: string, extra: readonly string[] = []): boolean {\n let chain: CommandChain | null;\n try {\n chain = parseCommandChain(cmd);\n } catch {\n return false;\n }\n if (chain === null) return isAllowed(cmd, extra);\n return chainAllowed(chain, (seg) => isAllowed(seg, extra));\n}\n"],"mappings":"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","names":["spawn","pathMod","pathMod","resolve","spawn","pathMod","isAllowed","resolve","resolve","spawn","delimiter","snapshot","killProcessTree","spawn","id","job","resolve"]}