reasonix 0.48.1 → 0.49.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 (123) hide show
  1. package/dashboard/dist/app.js +123 -16
  2. package/dashboard/dist/app.js.map +1 -1
  3. package/dist/cli/{acp-QJGGHQLA.js → acp-WFQIC6SO.js} +18 -18
  4. package/dist/cli/chat-D32JGNVH.js +51 -0
  5. package/dist/cli/{chunk-TIJ4ZHD6.js → chunk-23ZPCIPR.js} +12 -9
  6. package/dist/cli/chunk-23ZPCIPR.js.map +1 -0
  7. package/dist/cli/{chunk-TKVXTQ3T.js → chunk-3ZZXQ3CZ.js} +27 -27
  8. package/dist/cli/chunk-3ZZXQ3CZ.js.map +1 -0
  9. package/dist/cli/{chunk-H2F4LDNH.js → chunk-7AST3QQ3.js} +2 -2
  10. package/dist/cli/{chunk-XMR2VCGT.js → chunk-7JTKBJ2G.js} +3 -3
  11. package/dist/cli/{chunk-X53B3JIX.js → chunk-7X4JJOO7.js} +2 -61
  12. package/dist/cli/{chunk-X53B3JIX.js.map → chunk-7X4JJOO7.js.map} +1 -1
  13. package/dist/cli/{chunk-WKOXKCF3.js → chunk-ASOLXV67.js} +3 -3
  14. package/dist/cli/{chunk-43ROGEX2.js → chunk-AWEULQG6.js} +10 -9
  15. package/dist/cli/{chunk-43ROGEX2.js.map → chunk-AWEULQG6.js.map} +1 -1
  16. package/dist/cli/{chunk-5AW6NIHU.js → chunk-DFX5ZH5L.js} +2 -2
  17. package/dist/cli/{chunk-4E2BHJU4.js → chunk-GNS7BAT2.js} +2 -2
  18. package/dist/cli/{chunk-5U5LMMFF.js → chunk-J2IHQGPQ.js} +12 -6
  19. package/dist/cli/chunk-J2IHQGPQ.js.map +1 -0
  20. package/dist/cli/{chunk-O3AGYTG2.js → chunk-JGTX4RRQ.js} +3 -3
  21. package/dist/cli/{chunk-SLAFMXAZ.js → chunk-JNTMOX7G.js} +2 -2
  22. package/dist/cli/{chunk-RCLS63KE.js → chunk-MGTBP7GG.js} +2 -2
  23. package/dist/cli/{chunk-JFBGSWQB.js → chunk-MQWO32ZD.js} +323 -159
  24. package/dist/cli/chunk-MQWO32ZD.js.map +1 -0
  25. package/dist/cli/{chunk-FD7SNDWW.js → chunk-O5LIHAMP.js} +8 -4
  26. package/dist/cli/chunk-O5LIHAMP.js.map +1 -0
  27. package/dist/cli/{chunk-PJIQIYTV.js → chunk-PB3MAFEI.js} +3 -3
  28. package/dist/cli/{chunk-NQZ5U37J.js → chunk-PEMG6CUB.js} +2 -2
  29. package/dist/cli/{chunk-KH5JIJJD.js → chunk-PXBQ6IZ7.js} +3 -3
  30. package/dist/cli/{chunk-J2TQAWOM.js → chunk-Q46B3Z7H.js} +25 -10
  31. package/dist/cli/{chunk-J2TQAWOM.js.map → chunk-Q46B3Z7H.js.map} +1 -1
  32. package/dist/cli/{chunk-DABAOQSV.js → chunk-QF32ROX2.js} +1260 -1754
  33. package/dist/cli/chunk-QF32ROX2.js.map +1 -0
  34. package/dist/cli/{chunk-IKSYVBBZ.js → chunk-QX5TWXRZ.js} +2 -2
  35. package/dist/cli/{chunk-R7U44O3Y.js → chunk-TAIKVL35.js} +2 -2
  36. package/dist/cli/{chunk-B5CZL2SE.js → chunk-TEDWJKEI.js} +4 -9
  37. package/dist/cli/chunk-TEDWJKEI.js.map +1 -0
  38. package/dist/cli/{chunk-EO6RPTJG.js → chunk-U5XQDCK7.js} +5 -5
  39. package/dist/cli/{chunk-SWUMD2LX.js → chunk-W46ZMNKO.js} +3 -3
  40. package/dist/cli/{chunk-FPME5QOO.js → chunk-WMTMMSXU.js} +166 -5
  41. package/dist/cli/chunk-WMTMMSXU.js.map +1 -0
  42. package/dist/cli/{chunk-PIC5HJRD.js → chunk-YEF7C4XI.js} +154 -86
  43. package/dist/cli/chunk-YEF7C4XI.js.map +1 -0
  44. package/dist/cli/{chunk-3FULTFRB.js → chunk-ZAEJWKXB.js} +2 -2
  45. package/dist/cli/chunk-ZWHSHFDP.js +6173 -0
  46. package/dist/cli/chunk-ZWHSHFDP.js.map +1 -0
  47. package/dist/cli/{code-OKA5YPOH.js → code-R4IHI7SR.js} +30 -30
  48. package/dist/cli/{commands-3U6PUVSS.js → commands-DRHFCYMO.js} +4 -4
  49. package/dist/cli/{commit-HFB7SRBU.js → commit-AG5KB4YP.js} +3 -3
  50. package/dist/cli/{desktop-G7UMW3CJ.js → desktop-JGL6GORA.js} +19 -19
  51. package/dist/cli/{diff-PGXW4YZD.js → diff-4Z7ETWZO.js} +9 -9
  52. package/dist/cli/{doctor-WWJFLVCB.js → doctor-VA3RHQLB.js} +9 -9
  53. package/dist/cli/index.js +37 -36
  54. package/dist/cli/index.js.map +1 -1
  55. package/dist/cli/{mcp-Y3VKIK3T.js → mcp-LZO4HXFA.js} +34 -23
  56. package/dist/cli/mcp-LZO4HXFA.js.map +1 -0
  57. package/dist/cli/{mcp-browse-4IN2QIFR.js → mcp-browse-C3GXVMYZ.js} +3 -3
  58. package/dist/cli/{mcp-inspect-BUXFXDHB.js → mcp-inspect-ZMYUNFDS.js} +2 -2
  59. package/dist/cli/{prompt-US57R6BA.js → prompt-MC3U5KRP.js} +5 -5
  60. package/dist/cli/{prune-sessions-SEWX7GP6.js → prune-sessions-OEPFH4N6.js} +11 -7
  61. package/dist/cli/prune-sessions-OEPFH4N6.js.map +1 -0
  62. package/dist/cli/{replay-EQJMZRB3.js → replay-4TP7ZUMZ.js} +10 -10
  63. package/dist/cli/{run-KVEI66TR.js → run-6MXQYBOE.js} +16 -15
  64. package/dist/cli/run-6MXQYBOE.js.map +1 -0
  65. package/dist/cli/{server-D6C4GHWN.js → server-Z3IMJNNI.js} +63 -12
  66. package/dist/cli/server-Z3IMJNNI.js.map +1 -0
  67. package/dist/cli/{sessions-TGVS2RQZ.js → sessions-NXQ5SAV7.js} +18 -18
  68. package/dist/cli/sessions-NXQ5SAV7.js.map +1 -0
  69. package/dist/cli/{setup-WLKX6GGG.js → setup-LHZELI6I.js} +6 -6
  70. package/dist/cli/{stats-TCD7Q6MB.js → stats-SUIJ3QWY.js} +6 -6
  71. package/dist/cli/{version-BCWWS2OU.js → version-BIFONEUB.js} +13 -13
  72. package/dist/index.d.ts +63 -15
  73. package/dist/index.js +855 -360
  74. package/dist/index.js.map +1 -1
  75. package/package.json +2 -1
  76. package/dist/cli/chat-ZXF227MP.js +0 -51
  77. package/dist/cli/chunk-5U5LMMFF.js.map +0 -1
  78. package/dist/cli/chunk-6FRNXWDZ.js +0 -2265
  79. package/dist/cli/chunk-6FRNXWDZ.js.map +0 -1
  80. package/dist/cli/chunk-B5CZL2SE.js.map +0 -1
  81. package/dist/cli/chunk-DABAOQSV.js.map +0 -1
  82. package/dist/cli/chunk-FD7SNDWW.js.map +0 -1
  83. package/dist/cli/chunk-FPME5QOO.js.map +0 -1
  84. package/dist/cli/chunk-JFBGSWQB.js.map +0 -1
  85. package/dist/cli/chunk-PIC5HJRD.js.map +0 -1
  86. package/dist/cli/chunk-TIJ4ZHD6.js.map +0 -1
  87. package/dist/cli/chunk-TKVXTQ3T.js.map +0 -1
  88. package/dist/cli/mcp-Y3VKIK3T.js.map +0 -1
  89. package/dist/cli/prune-sessions-SEWX7GP6.js.map +0 -1
  90. package/dist/cli/run-KVEI66TR.js.map +0 -1
  91. package/dist/cli/server-D6C4GHWN.js.map +0 -1
  92. package/dist/cli/sessions-TGVS2RQZ.js.map +0 -1
  93. /package/dist/cli/{acp-QJGGHQLA.js.map → acp-WFQIC6SO.js.map} +0 -0
  94. /package/dist/cli/{chat-ZXF227MP.js.map → chat-D32JGNVH.js.map} +0 -0
  95. /package/dist/cli/{chunk-H2F4LDNH.js.map → chunk-7AST3QQ3.js.map} +0 -0
  96. /package/dist/cli/{chunk-XMR2VCGT.js.map → chunk-7JTKBJ2G.js.map} +0 -0
  97. /package/dist/cli/{chunk-WKOXKCF3.js.map → chunk-ASOLXV67.js.map} +0 -0
  98. /package/dist/cli/{chunk-5AW6NIHU.js.map → chunk-DFX5ZH5L.js.map} +0 -0
  99. /package/dist/cli/{chunk-4E2BHJU4.js.map → chunk-GNS7BAT2.js.map} +0 -0
  100. /package/dist/cli/{chunk-O3AGYTG2.js.map → chunk-JGTX4RRQ.js.map} +0 -0
  101. /package/dist/cli/{chunk-SLAFMXAZ.js.map → chunk-JNTMOX7G.js.map} +0 -0
  102. /package/dist/cli/{chunk-RCLS63KE.js.map → chunk-MGTBP7GG.js.map} +0 -0
  103. /package/dist/cli/{chunk-PJIQIYTV.js.map → chunk-PB3MAFEI.js.map} +0 -0
  104. /package/dist/cli/{chunk-NQZ5U37J.js.map → chunk-PEMG6CUB.js.map} +0 -0
  105. /package/dist/cli/{chunk-KH5JIJJD.js.map → chunk-PXBQ6IZ7.js.map} +0 -0
  106. /package/dist/cli/{chunk-IKSYVBBZ.js.map → chunk-QX5TWXRZ.js.map} +0 -0
  107. /package/dist/cli/{chunk-R7U44O3Y.js.map → chunk-TAIKVL35.js.map} +0 -0
  108. /package/dist/cli/{chunk-EO6RPTJG.js.map → chunk-U5XQDCK7.js.map} +0 -0
  109. /package/dist/cli/{chunk-SWUMD2LX.js.map → chunk-W46ZMNKO.js.map} +0 -0
  110. /package/dist/cli/{chunk-3FULTFRB.js.map → chunk-ZAEJWKXB.js.map} +0 -0
  111. /package/dist/cli/{code-OKA5YPOH.js.map → code-R4IHI7SR.js.map} +0 -0
  112. /package/dist/cli/{commands-3U6PUVSS.js.map → commands-DRHFCYMO.js.map} +0 -0
  113. /package/dist/cli/{commit-HFB7SRBU.js.map → commit-AG5KB4YP.js.map} +0 -0
  114. /package/dist/cli/{desktop-G7UMW3CJ.js.map → desktop-JGL6GORA.js.map} +0 -0
  115. /package/dist/cli/{diff-PGXW4YZD.js.map → diff-4Z7ETWZO.js.map} +0 -0
  116. /package/dist/cli/{doctor-WWJFLVCB.js.map → doctor-VA3RHQLB.js.map} +0 -0
  117. /package/dist/cli/{mcp-browse-4IN2QIFR.js.map → mcp-browse-C3GXVMYZ.js.map} +0 -0
  118. /package/dist/cli/{mcp-inspect-BUXFXDHB.js.map → mcp-inspect-ZMYUNFDS.js.map} +0 -0
  119. /package/dist/cli/{prompt-US57R6BA.js.map → prompt-MC3U5KRP.js.map} +0 -0
  120. /package/dist/cli/{replay-EQJMZRB3.js.map → replay-4TP7ZUMZ.js.map} +0 -0
  121. /package/dist/cli/{setup-WLKX6GGG.js.map → setup-LHZELI6I.js.map} +0 -0
  122. /package/dist/cli/{stats-TCD7Q6MB.js.map → stats-SUIJ3QWY.js.map} +0 -0
  123. /package/dist/cli/{version-BCWWS2OU.js.map → version-BIFONEUB.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/core/pause-gate.ts","../../packages/core-utils/src/derive-prefix.ts","../../packages/core-utils/src/approval-prompt.ts","../../packages/core-utils/src/tildeify.ts","../../packages/core-utils/src/tool-kind.ts","../../src/tools/jobs.ts","../../src/tools/shell.ts","../../src/tools/shell/exec.ts","../../src/tools/shell-chain.ts","../../src/tools/shell/parse.ts","../../src/tools/fs/edit.ts"],"sourcesContent":["/** 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\nimport type {\n CheckpointVerdict,\n ChoiceVerdict,\n ConfirmationChoice,\n PlanVerdict,\n RevisionVerdict,\n} from \"@reasonix/core-utils\";\n\nexport type { ConfirmationChoice, PlanVerdict, CheckpointVerdict, RevisionVerdict, ChoiceVerdict };\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 path_access: 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; cwd?: string; timeoutSec?: number };\n run_background: { command: string; cwd?: string; waitSec?: number };\n path_access: {\n /** Absolute path the tool wants to touch. */\n path: string;\n /** Why we're being asked — read leaks content, write mutates files. */\n intent: \"read\" | \"write\";\n /** The filesystem tool calling in — surfaced so users can see what's about to happen. */\n toolName: string;\n /** Sandbox root the path is escaping — surfaced for context. */\n sandboxRoot: string;\n /** Directory prefix that would be persisted if the user picks \"always allow\". */\n allowPrefix: string;\n };\n plan_proposed: { plan: string; steps?: unknown[]; summary?: string };\n plan_checkpoint: {\n stepId: string;\n title?: string;\n result: string;\n notes?: string;\n completion?: unknown;\n };\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 /** Cancel one pending request — used by multi-tab hosts that need per-scope abort. */\n cancel(id: number): boolean {\n const p = this._pending.get(id);\n if (!p) return false;\n this._pending.delete(id);\n p.resolve(safeCancelVerdict(p.request.kind));\n return true;\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 case \"path_access\":\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","/** First two tokens for known wrappers (`npm install`, `git commit`, …); else first token only.\n * Used by the \"always allow\" permission gate so that `npm test` and `npm run build`\n * share one prefix, while `cargo` and `ls` stay single-token.\n *\n * This function is duplicated in ≥2 build targets (CLI + Desktop), so it lives\n * in `@reasonix/core-utils` to prevent drift like issue #1180. */\nexport function derivePrefix(command: string): string {\n const tokens = command.trim().split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return \"\";\n if (tokens.length === 1) return tokens[0]!;\n const first = tokens[0]!;\n const TWO_TOKEN_WRAPPERS = new Set([\n \"npm\",\n \"npx\",\n \"pnpm\",\n \"yarn\",\n \"bun\",\n \"git\",\n \"cargo\",\n \"go\",\n \"docker\",\n \"kubectl\",\n \"python\",\n \"python3\",\n \"deno\",\n \"pip\",\n \"pip3\",\n \"make\",\n \"rake\",\n \"bundle\",\n \"gem\",\n ]);\n return TWO_TOKEN_WRAPPERS.has(first) ? `${first} ${tokens[1]}` : first;\n}\n","/** Unified UI description for PauseGate permission prompts.\n *\n * Every surface (CLI TUI, Desktop, Dashboard, ACP) converts a PauseGate\n * PauseRequest into this structure for rendering, then maps the user's\n * selection back through resolveApprovalPrompt() into the verdict shape\n * PauseGate expects.\n *\n * This is the single source of truth for:\n * - title / subtitle / preview / meta assembly\n * - option list ordering and IDs\n * - tone selection\n * - derivePrefix computation for \"always allow\"\n */\n\nimport { derivePrefix } from \"./derive-prefix.js\";\nimport type {\n CheckpointVerdict,\n ChoiceVerdict,\n ConfirmationChoice,\n PlanVerdict,\n RevisionVerdict,\n} from \"./permission-types.js\";\n\nexport type ApprovalPromptKind =\n | \"shell\"\n | \"path\"\n | \"plan\"\n | \"checkpoint\"\n | \"revision\"\n | \"choice\";\n\nexport type ApprovalTone = \"warn\" | \"error\" | \"info\" | \"accent\";\n\nexport interface ApprovalAction {\n id: string;\n label: string;\n kind: \"allow_once\" | \"allow_always\" | \"reject\" | \"custom\";\n /** If present, selecting this action requires secondary input (e.g., deny reason). */\n secondaryInput?: { hint: string; required: boolean };\n}\n\nexport interface ApprovalPrompt {\n id: number;\n kind: ApprovalPromptKind;\n tone: ApprovalTone;\n title: string;\n subtitle?: string;\n preview?: string;\n meta?: Record<string, string>;\n actions: ApprovalAction[];\n /** Opaque data consumed by resolveApprovalPrompt (e.g. prefix for always_allow). */\n data?: Record<string, unknown>;\n}\n\n/** Convert any PauseRequest-like input into a platform-agnostic UI description.\n * Labels are English fallbacks so the ACP surface (which has no i18n layer)\n * can render immediately. CLI and Desktop may override labels with their\n * own translation systems if desired.\n */\nexport function toApprovalPrompt(req: {\n id: number;\n kind: string;\n payload: unknown;\n}): ApprovalPrompt {\n const payload = req.payload as Record<string, unknown>;\n switch (req.kind) {\n case \"run_command\":\n return shellPrompt(req.id, payload, false);\n case \"run_background\":\n return shellPrompt(req.id, payload, true);\n case \"path_access\":\n return pathPrompt(req.id, payload);\n case \"plan_proposed\":\n return planPrompt(req.id, payload);\n case \"plan_checkpoint\":\n return checkpointPrompt(req.id, payload);\n case \"plan_revision\":\n return revisionPrompt(req.id, payload);\n case \"choice\":\n return choicePrompt(req.id, payload);\n default:\n // Defensive: unknown kinds render as a generic warn prompt with a\n // single dismiss action so the gate never hangs.\n return {\n id: req.id,\n kind: \"shell\",\n tone: \"warn\",\n title: \"Unrecognized request\",\n subtitle: String(req.kind),\n actions: [{ id: \"deny\", label: \"Dismiss\", kind: \"reject\" }],\n };\n }\n}\n\nfunction shellPrompt(\n id: number,\n payload: Record<string, unknown>,\n isBackground: boolean,\n): ApprovalPrompt {\n const command = String(payload.command ?? \"\");\n const cwd = payload.cwd ? String(payload.cwd) : undefined;\n const timeoutSec =\n !isBackground && typeof payload.timeoutSec === \"number\"\n ? payload.timeoutSec\n : undefined;\n const waitSec =\n isBackground && typeof payload.waitSec === \"number\"\n ? payload.waitSec\n : undefined;\n const prefix = derivePrefix(command);\n\n const meta: Record<string, string> = {};\n if (cwd) meta.cwd = cwd;\n if (timeoutSec !== undefined) meta.timeout = `${timeoutSec}s`;\n if (waitSec !== undefined) meta.wait = `${waitSec}s`;\n\n return {\n id,\n kind: \"shell\",\n tone: \"warn\",\n title: isBackground ? \"Run background command\" : \"Run command\",\n subtitle: command,\n preview: command,\n meta: Object.keys(meta).length > 0 ? meta : undefined,\n actions: [\n {\n id: \"run_once\",\n label: \"Run once\",\n kind: \"allow_once\",\n },\n {\n id: \"always_allow\",\n label: `Always allow — ${prefix}`,\n kind: \"allow_always\",\n },\n {\n id: \"deny\",\n label: \"Deny\",\n kind: \"reject\",\n secondaryInput: {\n hint: \"Reason for denial (optional)\",\n required: false,\n },\n },\n ],\n data: { prefix },\n };\n}\n\nfunction pathPrompt(\n id: number,\n payload: Record<string, unknown>,\n): ApprovalPrompt {\n const path = String(payload.path ?? \"\");\n const intent = payload.intent === \"write\" ? \"write\" : \"read\";\n const toolName = String(payload.toolName ?? \"\");\n const sandboxRoot = String(payload.sandboxRoot ?? \"\");\n const allowPrefix = String(payload.allowPrefix ?? \"\");\n\n const meta: Record<string, string> = {};\n if (sandboxRoot) meta.sandboxRoot = sandboxRoot;\n\n return {\n id,\n kind: \"path\",\n tone: \"warn\",\n title: `Access path — ${intent}`,\n subtitle: path,\n preview: `${toolName} → ${path}`,\n meta: Object.keys(meta).length > 0 ? meta : undefined,\n actions: [\n {\n id: \"run_once\",\n label: intent === \"write\" ? \"Allow write\" : \"Allow read\",\n kind: \"allow_once\",\n },\n {\n id: \"always_allow\",\n label: `Always allow — ${allowPrefix}`,\n kind: \"allow_always\",\n },\n {\n id: \"deny\",\n label: \"Deny\",\n kind: \"reject\",\n secondaryInput: {\n hint: \"Reason for denial (optional)\",\n required: false,\n },\n },\n ],\n data: { prefix: allowPrefix, intent },\n };\n}\n\nfunction planPrompt(\n id: number,\n payload: Record<string, unknown>,\n): ApprovalPrompt {\n const plan = String(payload.plan ?? \"\");\n const summary = payload.summary ? String(payload.summary) : undefined;\n const steps = Array.isArray(payload.steps) ? payload.steps : [];\n const subtitle = summary ?? (plan.length > 80 ? `${plan.slice(0, 80)}…` : plan);\n\n const meta: Record<string, string> = {};\n if (steps.length > 0) meta.steps = String(steps.length);\n\n return {\n id,\n kind: \"plan\",\n tone: \"accent\",\n title: \"Approve plan\",\n subtitle,\n preview: plan,\n meta: Object.keys(meta).length > 0 ? meta : undefined,\n actions: [\n { id: \"approve\", label: \"Approve\", kind: \"allow_once\" },\n { id: \"refine\", label: \"Refine\", kind: \"custom\" },\n { id: \"cancel\", label: \"Cancel\", kind: \"reject\" },\n ],\n };\n}\n\nfunction checkpointPrompt(\n id: number,\n payload: Record<string, unknown>,\n): ApprovalPrompt {\n const titleText = String(payload.title ?? \"step complete\");\n const result = String(payload.result ?? \"\");\n const notes = payload.notes ? String(payload.notes) : undefined;\n const completed =\n typeof payload.completed === \"number\" ? payload.completed : 0;\n const total = typeof payload.total === \"number\" ? payload.total : 0;\n\n const meta: Record<string, string> = {};\n if (total > 0) meta.progress = `${completed}/${total}`;\n\n let preview = result;\n if (notes) preview += `\\n${notes}`;\n\n return {\n id,\n kind: \"checkpoint\",\n tone: \"info\",\n title: `Checkpoint — ${titleText}`,\n subtitle: result,\n preview: preview || undefined,\n meta: Object.keys(meta).length > 0 ? meta : undefined,\n actions: [\n { id: \"continue\", label: \"Continue\", kind: \"allow_once\" },\n { id: \"revise\", label: \"Revise\", kind: \"custom\" },\n { id: \"stop\", label: \"Stop\", kind: \"reject\" },\n ],\n };\n}\n\nfunction revisionPrompt(\n id: number,\n payload: Record<string, unknown>,\n): ApprovalPrompt {\n const reason = String(payload.reason ?? \"\");\n const remainingSteps = Array.isArray(payload.remainingSteps)\n ? payload.remainingSteps\n : [];\n const summary = payload.summary ? String(payload.summary) : undefined;\n const subtitle = summary ?? (reason.length > 80 ? `${reason.slice(0, 80)}…` : reason);\n\n const meta: Record<string, string> = {};\n if (remainingSteps.length > 0) meta.steps = String(remainingSteps.length);\n\n return {\n id,\n kind: \"revision\",\n tone: \"warn\",\n title: \"Approve plan revision\",\n subtitle,\n preview: reason,\n meta: Object.keys(meta).length > 0 ? meta : undefined,\n actions: [\n { id: \"accept\", label: \"Accept\", kind: \"allow_once\" },\n { id: \"reject\", label: \"Keep original\", kind: \"reject\" },\n ],\n };\n}\n\nfunction choicePrompt(\n id: number,\n payload: Record<string, unknown>,\n): ApprovalPrompt {\n const question = String(payload.question ?? \"Choose an option\");\n const rawOptions = Array.isArray(payload.options) ? payload.options : [];\n const allowCustom = payload.allowCustom === true;\n\n const actions: ApprovalAction[] = rawOptions.map((o: unknown) => {\n const opt = o as Record<string, unknown>;\n const optId = String(opt.id ?? \"\");\n const optTitle = String(opt.title ?? optId);\n return { id: optId, label: optTitle, kind: \"custom\" };\n });\n\n actions.push({ id: \"cancel\", label: \"Cancel\", kind: \"reject\" });\n\n return {\n id,\n kind: \"choice\",\n tone: \"info\",\n title: question,\n actions,\n data: allowCustom ? { allowCustom: true } : undefined,\n };\n}\n\n/** Convert a user's action selection into the verdict PauseGate expects.\n * The returned shape is a union; callers should narrow by prompt.kind.\n */\nexport function resolveApprovalPrompt(\n prompt: ApprovalPrompt,\n actionId: string,\n secondaryInput?: string,\n):\n | ConfirmationChoice\n | PlanVerdict\n | CheckpointVerdict\n | RevisionVerdict\n | ChoiceVerdict {\n const action = prompt.actions.find((a) => a.id === actionId);\n\n // Fallback when the action is missing or unrecognised — return the safest\n // default for the prompt kind so the gate never hangs.\n if (!action) {\n return safeDefaultForKind(prompt.kind);\n }\n\n switch (prompt.kind) {\n case \"shell\":\n case \"path\": {\n if (action.kind === \"reject\") {\n return { type: \"deny\", denyContext: secondaryInput };\n }\n if (action.kind === \"allow_always\") {\n return {\n type: \"always_allow\",\n prefix: String(prompt.data?.prefix ?? \"\"),\n };\n }\n return { type: \"run_once\" };\n }\n case \"plan\": {\n if (action.id === \"approve\") return { type: \"approve\" };\n if (action.id === \"refine\") return { type: \"refine\" };\n return { type: \"cancel\" };\n }\n case \"checkpoint\": {\n if (action.id === \"continue\") return { type: \"continue\" };\n if (action.id === \"revise\") return { type: \"revise\" };\n return { type: \"stop\" };\n }\n case \"revision\": {\n if (action.id === \"accept\") return { type: \"accepted\" };\n return { type: \"rejected\" };\n }\n case \"choice\": {\n if (action.kind === \"reject\") return { type: \"cancel\" };\n return { type: \"pick\", optionId: action.id };\n }\n }\n}\n\nfunction safeDefaultForKind(\n kind: ApprovalPromptKind,\n):\n | ConfirmationChoice\n | PlanVerdict\n | CheckpointVerdict\n | RevisionVerdict\n | ChoiceVerdict {\n switch (kind) {\n case \"shell\":\n case \"path\":\n return { type: \"deny\" };\n case \"plan\":\n return { type: \"cancel\" };\n case \"checkpoint\":\n return { type: \"stop\" };\n case \"revision\":\n return { type: \"rejected\" };\n case \"choice\":\n return { type: \"cancel\" };\n }\n}\n","import { homedir } from \"node:os\";\n\n/** Replace the user's home directory with `~` for display purposes.\n * Mirrors the shell's `~` expansion in reverse. */\nexport function tildeify(p: string): string {\n const home = homedir();\n if (!home) return p;\n const normalized = home.replace(/[\\\\/]+$/, \"\");\n if (p === normalized) return \"~\";\n if (p.startsWith(`${normalized}/`)) return `~/${p.slice(normalized.length + 1).replace(/^[\\\\/]+/, \"\")}`;\n if (p.startsWith(`${normalized}\\\\`)) return `~\\\\${p.slice(normalized.length + 1).replace(/^[\\\\/]+/, \"\")}`;\n return p;\n}\n","/** Tool classification used by ACP dispatch and Dashboard cards to assign\n * consistent icons / colours without hard-coding tool names in the UI layer. */\n\nconst READ_TOOLS = new Set([\n \"read_file\",\n \"list_directory\",\n \"directory_tree\",\n \"get_file_info\",\n \"glob\",\n]);\n\nconst EDIT_TOOLS = new Set([\n \"write_file\",\n \"edit_file\",\n \"multi_edit\",\n \"create_directory\",\n \"delete_file\",\n \"delete_directory\",\n \"move_file\",\n \"copy_file\",\n]);\n\nconst SEARCH_TOOLS = new Set([\"search_content\", \"search_files\"]);\nconst EXECUTE_TOOLS = new Set([\"run_command\", \"run_background\"]);\n\nexport type AcpToolKind = \"read\" | \"edit\" | \"search\" | \"execute\" | \"other\";\n\nexport function toolKindFor(name: string): AcpToolKind {\n if (READ_TOOLS.has(name)) return \"read\";\n if (EDIT_TOOLS.has(name)) return \"edit\";\n if (SEARCH_TOOLS.has(name)) return \"search\";\n if (EXECUTE_TOOLS.has(name)) return \"execute\";\n return \"other\";\n}\n","/** 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 // `exit` fires when the process is dead; `close` waits for stdio drain too.\n // On Windows + Node ≥ 24, drained stdio can lag 5–10s behind taskkill /T /F,\n // so we settle `running`/`closedPromise` on the earlier event. `close` is\n // still wired for the no-exit fallback (spawn error before any process exists).\n const settleClosed = (code: number | null) => {\n if (!job.running && job.exitCode !== null) return;\n job.running = false;\n job.exitCode = code;\n job.signalReady();\n job.signalClosed();\n };\n child.on(\"exit\", settleClosed);\n child.on(\"close\", settleClosed);\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(\n id: number,\n opts: { timeoutMs?: number; waitFor?: \"exit\" | \"output-or-exit\" } = {},\n ): 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(300_000, opts.timeoutMs ?? 5_000));\n const waitFor = opts.waitFor ?? \"exit\";\n const startOutput = job.output;\n\n const racers: Promise<void>[] = [job.closedPromise];\n let wakeOutput: (() => void) | null = null;\n if (waitFor === \"output-or-exit\") {\n racers.push(\n new Promise<void>((resolve) => {\n wakeOutput = resolve;\n job.outputWaiters.add(resolve);\n }),\n );\n }\n let timer: ReturnType<typeof setTimeout> | null = null;\n racers.push(\n new Promise<void>((resolve) => {\n timer = setTimeout(resolve, timeoutMs);\n }),\n );\n await Promise.race(racers);\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 // Node ≥ 24 on Windows sometimes never fires `close` after taskkill /T /F\n // (the OS handle lingers even though the process is dead). We issued the\n // kill; trust it and settle the record so callers don't see ghost-running.\n if (job.running) {\n job.running = false;\n job.signalClosed();\n }\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 // Same Node ≥ 24 Windows fallback as `stop()`: settle any job whose `close`\n // event never arrived after taskkill /T /F — the kill is synchronous, the\n // notification isn't.\n for (const job of runningJobs) {\n if (job.running) {\n job.running = false;\n job.signalClosed();\n }\n }\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 hasSensitivePathArgs,\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 /** Fired after `run_background` / `stop_job` mutate the registry — used by the desktop popover for near-real-time updates without polling. */\n onJobsChanged?: () => void;\n sensitivePaths?: { prefixes?: readonly string[]; patterns?: readonly string[] };\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; returns combined stdout+stderr. Allowlisted read-only / test / lint / typecheck commands run immediately; mutating / network / install commands gate on user confirmation.\\n\\nNo real shell — argv parsed natively for cross-platform parity:\\n• Supported: chains `|`/`||`/`&&`/`;` (each segment allowlist-checked) and file redirects `>`/`>>`/`<`/`2>`/`2>>`/`2>&1`/`&>`.\\n• Rejected: background `&`, heredoc `<<`, `$(…)`, subshells, `$VAR` expansion, glob expansion. Quote operator chars as literals (`grep \"a|b\" file`).\\n• `cd` does NOT persist — between calls OR within a chain. Use `npm --prefix <dir>`, `git -C <dir>`, `cargo -C <dir>` instead.\\n• Filter at source — `grep -c` / `wc -l` / narrower paths over unbounded dumps.',\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(), rootDir, opts.sensitivePaths);\n },\n parameters: {\n type: \"object\",\n properties: {\n command: {\n type: \"string\",\n description:\n \"Full command line. Quoting + chain/redirect rules per the top-level description.\",\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 const effectiveTimeout = Math.max(1, Math.min(600, args.timeoutSec ?? timeoutSec));\n if (\n !isAllowAll() &&\n !isCommandAllowed(cmd, getExtraAllowed(), rootDir, opts.sensitivePaths)\n ) {\n const gate = ctx?.confirmationGate ?? pauseGate;\n const choice = await gate.ask({\n kind: \"run_command\",\n payload: { command: cmd, cwd: rootDir, timeoutSec: effectiveTimeout },\n });\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 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 and detach. Waits up to `waitSec` for startup or a readiness signal ('Local:', 'listening on', 'compiled successfully'), then returns job id + startup preview. Companion tools: `job_output`, `wait_for_job`, `stop_job`, `list_jobs`. Single process only — no chains/redirects. Use `cwd` (not `cd X && cmd`) for subdirs.\\n\\nUSE THIS — not run_command — for: dev servers / watchers (`npm dev`, `uvicorn`, `tsc --watch`, anything with dev/serve/watch in the name) AND one-shot long jobs (large `curl`, `pip install`, `cargo build`, `docker build`). Pair with `wait_for_job` for server-side blocking — one tool call regardless of duration.\",\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 cwd: {\n type: \"string\",\n description:\n \"Working directory for the spawn. Workspace-relative or absolute. Defaults to the workspace root. Must resolve inside the workspace — paths escaping the root are rejected.\",\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; cwd?: string; waitSec?: number }, ctx) => {\n const cmd = args.command.trim();\n if (!cmd) throw new Error(\"run_background: empty command\");\n const cwd = resolveCwdInsideRoot(rootDir, args.cwd);\n if (\n !isAllowAll() &&\n !isCommandAllowed(cmd, getExtraAllowed(), rootDir, opts.sensitivePaths)\n ) {\n const gate = ctx?.confirmationGate ?? pauseGate;\n const choice = await gate.ask({\n kind: \"run_background\",\n payload: { command: cmd, cwd, waitSec: args.waitSec },\n });\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,\n waitSec: args.waitSec,\n signal: ctx?.signal,\n });\n opts.onJobsChanged?.();\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 server-side until a background job finishes (or, opt-in, until it produces new output), bounded by `timeoutMs`. Costs ONE tool call regardless of how long the wait runs — use this instead of polling `job_output` in a loop. Returns JSON with `exited`, `exitCode`, and `latestOutput`.\\n\\n`waitFor` controls the wake condition:\\n- `'exit'` (default) — only wake on the job exiting (or the timeout). Right for downloads, installs, builds, anything one-shot. Chatty progress bars do NOT wake the wait.\\n- `'output-or-exit'` — also wake whenever the job writes a new line. Right for tailing a dev server / watcher and reacting to a specific log line.\\n\\nFor a download or install, set `timeoutMs` to the slowest reasonable end-to-end (e.g. 300_000 for a 5-min wheel install).\",\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 timeoutMs: {\n type: \"integer\",\n description:\n \"Max time to block before returning if the wake condition hasn't fired. Clamped to 0..300000. Default 5000.\",\n },\n waitFor: {\n type: \"string\",\n enum: [\"exit\", \"output-or-exit\"],\n description:\n \"Wake condition. 'exit' = only on job exit (right for downloads / installs / builds). 'output-or-exit' = also on any new output (right for tailing a dev server). Default 'exit'.\",\n },\n },\n required: [\"jobId\"],\n },\n fn: async (args: {\n jobId: number;\n timeoutMs?: number;\n waitFor?: \"exit\" | \"output-or-exit\";\n }) => {\n const out = await jobs.waitForJob(args.jobId, {\n timeoutMs: args.timeoutMs,\n waitFor: args.waitFor,\n });\n if (!out) return `job ${args.jobId}: not found (use list_jobs)`;\n if (out.exited) opts.onJobsChanged?.();\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 opts.onJobsChanged?.();\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 resolveCwdInsideRoot(rootDir: string, raw: string | undefined): string {\n const root = pathMod.resolve(rootDir);\n if (!raw || !raw.trim()) return root;\n const resolved = pathMod.resolve(root, raw);\n const rel = pathMod.relative(root, resolved);\n if (rel.startsWith(\"..\") || pathMod.isAbsolute(rel)) {\n throw new Error(\n `run_background: cwd \"${raw}\" resolves outside the workspace root (${root}). Pass a workspace-relative path.`,\n );\n }\n return resolved;\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","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,\n windowsHide: true,\n // POSIX: detach so the child becomes its own process-group leader.\n // Required for `process.kill(-pid, …)` in killProcessTree to\n // terminate the whole subtree (child + grandchildren) instead of\n // only the leader — without this grandchildren like npm→node→esbuild\n // become orphaned.\n // Windows: detached would spawn a new console window; leave the\n // default and use taskkill /T for tree termination (see killProcessTree).\n detached: process.platform !== \"win32\",\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 { devNull } from \"node:os\";\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\n/** Models reach for `2>nul` (Windows) and `2>/dev/null` (POSIX) interchangeably; without this the parser materializes a real `<cwd>/nul` file. */\nfunction isNullDeviceAlias(target: string): boolean {\n const lower = target.toLowerCase();\n if (lower === \"/dev/null\") return true;\n if (process.platform === \"win32\" && lower === \"nul\") return true;\n return false;\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 = isNullDeviceAlias(target) ? devNull : 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 // POSIX: detach so the child becomes its own process-group leader,\n // allowing killProcessTree's neg-pid kill to terminate the whole\n // pipe chain subtree instead of just the direct child.\n detached: process.platform !== \"win32\",\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 { homedir } from \"node:os\";\nimport * as pathMod from \"node:path\";\nimport { 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/** Issue #259 — default sensitive-path prefixes (tilde-relative). Matching a path argument against these\n * demotes an otherwise-allowlisted command back to the confirm gate, preventing the agent from\n * silently reading credentials / keys and piping them into the LLM context. */\nconst DEFAULT_SENSITIVE_PREFIXES: ReadonlyArray<string> = [\n \"~/.ssh\",\n \"~/.aws\",\n \"~/.gnupg\",\n \"~/.kube\",\n \"/etc/shadow\",\n \"/etc/sudoers\",\n];\n\n/** Issue #259 — filename patterns (case-insensitive basename match). */\nconst DEFAULT_SENSITIVE_PATTERNS: ReadonlyArray<string> = [\n \"*.env\",\n \"*.env.*\",\n \"*.key\",\n \"*.pem\",\n \"id_rsa*\",\n \"id_ed25519*\",\n \"*credentials*\",\n \"*secret*\",\n];\n\n/** Resolve `~` to `homedir()` and normalize. Non-path-like tokens (flags, URLs, env vars) are skipped. */\nfunction resolveSensitivePath(token: string, projectRoot: string): string | null {\n if (!token || token.startsWith(\"-\") || token.includes(\"://\") || token.startsWith(\"$\"))\n return null;\n let expanded = token;\n if (expanded.startsWith(\"~\")) {\n expanded = pathMod.join(homedir(), expanded.slice(1));\n }\n return pathMod.resolve(projectRoot, expanded);\n}\n\nfunction expandPrefix(prefix: string): string {\n if (prefix.startsWith(\"~\")) return pathMod.join(homedir(), prefix.slice(1));\n return pathMod.resolve(prefix);\n}\n\n/** Ensure prefix matches only at directory boundaries (not mid-segment). */\nfunction pathStartsWithPrefix(normalized: string, prefix: string): boolean {\n return normalized === prefix || normalized.startsWith(`${prefix}${pathMod.sep}`);\n}\n\n/** Glob-style match: `*.env` matches `foo.env`, `id_rsa*` matches `id_rsa_old`. */\nfunction matchesGlob(name: string, pattern: string): boolean {\n const regex = new RegExp(\n `^${pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\")}$`,\n \"i\",\n );\n return regex.test(name);\n}\n\n/** Check whether a command's path-like arguments touch sensitive locations. */\nexport function hasSensitivePathArgs(\n argv: readonly string[],\n projectRoot: string,\n extraPrefixes: readonly string[] = [],\n extraPatterns: readonly string[] = [],\n): boolean {\n const prefixes = [...DEFAULT_SENSITIVE_PREFIXES, ...extraPrefixes].map(expandPrefix);\n const patterns = [...DEFAULT_SENSITIVE_PATTERNS, ...extraPatterns];\n for (const token of argv) {\n const resolved = resolveSensitivePath(token, projectRoot);\n if (!resolved) continue;\n const normalized = pathMod.normalize(resolved);\n for (const pfx of prefixes) {\n if (pathStartsWithPrefix(normalized, pfx)) return true;\n }\n const base = pathMod.basename(normalized);\n for (const pat of patterns) {\n if (matchesGlob(base, pat)) 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,\n * or by `SENSITIVE_PATHS` when a path argument targets a sensitive location (#259). */\nexport function isAllowed(\n cmd: string,\n extra: readonly string[] = [],\n projectRoot?: string,\n sensitivePathConfig?: { prefixes?: readonly string[]; patterns?: readonly string[] },\n): 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 if (\n projectRoot &&\n hasSensitivePathArgs(\n argv,\n projectRoot,\n sensitivePathConfig?.prefixes,\n sensitivePathConfig?.patterns,\n )\n )\n 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(\n cmd: string,\n extra: readonly string[] = [],\n projectRoot?: string,\n sensitivePathConfig?: { prefixes?: readonly string[]; patterns?: readonly string[] },\n): 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, projectRoot, sensitivePathConfig);\n return chainAllowed(chain, (seg) => isAllowed(seg, extra, projectRoot, sensitivePathConfig));\n}\n\nexport { derivePrefix } from \"@reasonix/core-utils\";\n","import { promises as fs } from \"node:fs\";\nimport * as pathMod from \"node:path\";\n\nfunction displayRel(rootDir: string, full: string): string {\n return pathMod.relative(rootDir, full).replaceAll(\"\\\\\", \"/\");\n}\n\nexport async function applyEdit(\n rootDir: string,\n abs: string,\n args: { search: string; replace: string },\n): Promise<string> {\n if (args.search.length === 0) {\n throw new Error(\"edit_file: search cannot be empty\");\n }\n const before = await fs.readFile(abs, \"utf8\");\n const le = before.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const adaptedSearch = args.search.replace(/\\r?\\n/g, le);\n const adaptedReplace = args.replace.replace(/\\r?\\n/g, le);\n const firstIdx = before.indexOf(adaptedSearch);\n if (firstIdx < 0) {\n throw new Error(`edit_file: search text not found in ${displayRel(rootDir, abs)}`);\n }\n const nextIdx = before.indexOf(adaptedSearch, firstIdx + 1);\n if (nextIdx >= 0) {\n throw new Error(\n `edit_file: search text appears multiple times in ${displayRel(rootDir, abs)} — include more context to disambiguate`,\n );\n }\n const after =\n before.slice(0, firstIdx) + adaptedReplace + before.slice(firstIdx + adaptedSearch.length);\n await fs.writeFile(abs, after, \"utf8\");\n const rel = displayRel(rootDir, abs);\n const header = `edited ${rel} (${adaptedSearch.length}→${adaptedReplace.length} chars)`;\n const startLine = before.slice(0, firstIdx).split(/\\r?\\n/).length;\n const diff = renderEditDiff(adaptedSearch, adaptedReplace, startLine);\n return `${header}\\n${diff}`;\n}\n\nexport interface MultiEditEntry {\n abs: string;\n search: string;\n replace: string;\n}\n\nexport async function applyMultiEdit(\n rootDir: string,\n edits: ReadonlyArray<MultiEditEntry>,\n): Promise<string> {\n if (edits.length === 0) {\n throw new Error(\"multi_edit: edits must contain at least one entry\");\n }\n type FileState = {\n before: string;\n buf: string;\n le: string;\n hunks: string[];\n deltaChars: number;\n touched: number;\n };\n const filesByPath = new Map<string, FileState>();\n\n for (let i = 0; i < edits.length; i++) {\n const e = edits[i]!;\n if (typeof e.abs !== \"string\" || e.abs.length === 0) {\n throw new Error(`multi_edit: edit #${i + 1} requires a string \\`path\\` (no edits applied)`);\n }\n if (typeof e.search !== \"string\") {\n throw new Error(`multi_edit: edit #${i + 1} requires a string \\`search\\` (no edits applied)`);\n }\n if (typeof e.replace !== \"string\") {\n throw new Error(\n `multi_edit: edit #${i + 1} requires a string \\`replace\\` (no edits applied)`,\n );\n }\n const rel = displayRel(rootDir, e.abs);\n if (e.search.length === 0) {\n throw new Error(\n `multi_edit: edit #${i + 1} (${rel}) search cannot be empty (no edits applied)`,\n );\n }\n let state = filesByPath.get(e.abs);\n if (!state) {\n let before: string;\n try {\n before = await fs.readFile(e.abs, \"utf8\");\n } catch (err) {\n throw new Error(\n `multi_edit: edit #${i + 1} cannot read ${rel}: ${(err as Error).message} (no edits applied)`,\n );\n }\n const le = before.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n state = { before, buf: before, le, hunks: [], deltaChars: 0, touched: 0 };\n filesByPath.set(e.abs, state);\n }\n const adaptedSearch = e.search.replace(/\\r?\\n/g, state.le);\n const adaptedReplace = e.replace.replace(/\\r?\\n/g, state.le);\n const firstIdx = state.buf.indexOf(adaptedSearch);\n if (firstIdx < 0) {\n throw new Error(\n `multi_edit: edit #${i + 1} search text not found in ${rel} — no edits applied`,\n );\n }\n const nextIdx = state.buf.indexOf(adaptedSearch, firstIdx + 1);\n if (nextIdx >= 0) {\n throw new Error(\n `multi_edit: edit #${i + 1} search text appears multiple times in ${rel} — include more context to disambiguate (no edits applied)`,\n );\n }\n const startLine = state.buf.slice(0, firstIdx).split(/\\r?\\n/).length;\n state.buf =\n state.buf.slice(0, firstIdx) +\n adaptedReplace +\n state.buf.slice(firstIdx + adaptedSearch.length);\n state.hunks.push(`# ${rel}\\n${renderEditDiff(adaptedSearch, adaptedReplace, startLine)}`);\n state.deltaChars += adaptedReplace.length - adaptedSearch.length;\n state.touched++;\n }\n\n // Push to `attempted` BEFORE writeFile so a write that truncates or\n // partially-writes before failing is also rolled back.\n const attempted: Array<{ abs: string; before: string }> = [];\n try {\n for (const [abs, state] of filesByPath) {\n attempted.push({ abs, before: state.before });\n await fs.writeFile(abs, state.buf, \"utf8\");\n }\n } catch (writeErr) {\n const rollbackFailures: string[] = [];\n for (const item of [...attempted].reverse()) {\n try {\n await fs.writeFile(item.abs, item.before, \"utf8\");\n } catch (restoreErr) {\n rollbackFailures.push(`${displayRel(rootDir, item.abs)}: ${(restoreErr as Error).message}`);\n }\n }\n if (rollbackFailures.length > 0) {\n throw new Error(\n `multi_edit: write failed after partial application: ${(writeErr as Error).message}; rollback failed for ${rollbackFailures.join(\"; \")}`,\n );\n }\n throw new Error(\n `multi_edit: write failed: ${(writeErr as Error).message}; rolled back all files that may have been modified`,\n );\n }\n\n const fileCount = filesByPath.size;\n const editCount = edits.length;\n let totalDelta = 0;\n const allHunks: string[] = [];\n for (const state of filesByPath.values()) {\n totalDelta += state.deltaChars;\n allHunks.push(...state.hunks);\n }\n const sign = totalDelta >= 0 ? \"+\" : \"\";\n const editNoun = editCount === 1 ? \"edit\" : \"edits\";\n const fileNoun = fileCount === 1 ? \"file\" : \"files\";\n const header = `multi_edit: applied ${editCount} ${editNoun} across ${fileCount} ${fileNoun} (${sign}${totalDelta} chars)`;\n return `${header}\\n${allHunks.join(\"\\n\")}`;\n}\n\nfunction renderEditDiff(search: string, replace: string, startLine: number): string {\n const a = search.split(/\\r?\\n/);\n const b = replace.split(/\\r?\\n/);\n const diff = lineDiff(a, b);\n const hunk = `@@ -${startLine},${a.length} +${startLine},${b.length} @@`;\n const body = diff.map((d) => `${d.op === \" \" ? \" \" : d.op} ${d.line}`).join(\"\\n\");\n return `${hunk}\\n${body}`;\n}\n\nexport function lineDiff(\n a: readonly string[],\n b: readonly string[],\n): Array<{ op: \"-\" | \"+\" | \" \"; line: string }> {\n const n = a.length;\n const m = b.length;\n // dp[i][j] = LCS length of a[0..i) and b[0..j).\n const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));\n for (let i = 1; i <= n; i++) {\n for (let j = 1; j <= m; j++) {\n if (a[i - 1] === b[j - 1]) dp[i]![j] = dp[i - 1]![j - 1]! + 1;\n else dp[i]![j] = Math.max(dp[i - 1]![j]!, dp[i]![j - 1]!);\n }\n }\n // Backtrack to recover the op sequence.\n const out: Array<{ op: \"-\" | \"+\" | \" \"; line: string }> = [];\n let i = n;\n let j = m;\n while (i > 0 && j > 0) {\n if (a[i - 1] === b[j - 1]) {\n out.unshift({ op: \" \", line: a[i - 1]! });\n i--;\n j--;\n } else if ((dp[i - 1]![j] ?? 0) > (dp[i]![j - 1] ?? 0)) {\n out.unshift({ op: \"-\", line: a[i - 1]! });\n i--;\n } else {\n // Tie-break goes here (strictly less or equal): take the\n // insertion first during backtrack so the final forward order\n // renders removals BEFORE additions for a substitution —\n // matches git-diff convention of `- old / + new`.\n out.unshift({ op: \"+\", line: b[j - 1]! });\n j--;\n }\n }\n while (i > 0) {\n out.unshift({ op: \"-\", line: a[i - 1]! });\n i--;\n }\n while (j > 0) {\n out.unshift({ op: \"+\", line: b[j - 1]! });\n j--;\n }\n return out;\n}\n"],"mappings":"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","names":["resolve","spawn","pathMod","pathMod","spawn","pathMod","isAllowed","resolve","homedir","pathMod","homedir","resolve","spawn","delimiter","snapshot","killProcessTree","spawn","id","job","resolve","pathMod","i","j"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/code/checkpoints.ts","../../src/code/plan-store.ts","../../src/cli/ui/slash/commands.ts"],"sourcesContent":["/** One file per checkpoint (not jsonl) so delete/restore is cheap and a corrupt snapshot only loses itself. */\n\nimport { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\n\n/** One file's state at the time of snapshot. `content === null` → didn't exist. */\nexport interface CheckpointFile {\n path: string;\n content: string | null;\n}\n\nexport interface Checkpoint {\n id: string;\n /** User-given name, or `auto-<reason>` for system-created snapshots. */\n name: string;\n /** Absolute workspace root the snapshot belongs to. */\n rootDir: string;\n createdAt: number;\n source: \"manual\" | \"auto-session-start\" | \"auto-pre-restore\";\n files: CheckpointFile[];\n /** Total bytes of file content captured (sum of `content?.length`). */\n bytes: number;\n}\n\nexport interface CheckpointMeta {\n id: string;\n name: string;\n createdAt: number;\n source: Checkpoint[\"source\"];\n fileCount: number;\n bytes: number;\n}\n\n/** Sanitize a directory path into a safe filesystem name for the store. */\nfunction sanitizeRoot(rootDir: string): string {\n return resolve(rootDir)\n .replace(/[\\\\/:]+/g, \"_\")\n .replace(/^_+/, \"\");\n}\n\nfunction storeRoot(rootDir: string): string {\n return join(homedir(), \".reasonix\", \"sessions\", sanitizeRoot(rootDir), \"checkpoints\");\n}\n\nfunction indexPath(rootDir: string): string {\n return join(storeRoot(rootDir), \"index.json\");\n}\n\nfunction snapshotPath(rootDir: string, id: string): string {\n return join(storeRoot(rootDir), `${id}.json`);\n}\n\n/** Load the index of checkpoint metadata for a workspace. Empty when missing. */\nexport function listCheckpoints(rootDir: string): CheckpointMeta[] {\n const path = indexPath(rootDir);\n if (!existsSync(path)) return [];\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed)) return [];\n // Defensive: filter out malformed entries rather than throwing on\n // a single bad row. A stale entry is annoying; a thrown listCheckpoints\n // would break /checkpoint list entirely.\n return parsed.filter(\n (m): m is CheckpointMeta =>\n typeof m === \"object\" &&\n m !== null &&\n typeof m.id === \"string\" &&\n typeof m.name === \"string\" &&\n typeof m.createdAt === \"number\" &&\n typeof m.source === \"string\" &&\n typeof m.fileCount === \"number\" &&\n typeof m.bytes === \"number\",\n );\n } catch {\n return [];\n }\n}\n\nfunction writeIndex(rootDir: string, items: CheckpointMeta[]): void {\n const path = indexPath(rootDir);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(items, null, 2), \"utf8\");\n}\n\n/** Read a single checkpoint by id. Returns null when missing or corrupt. */\nexport function loadCheckpoint(rootDir: string, id: string): Checkpoint | null {\n const path = snapshotPath(rootDir, id);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && Array.isArray(parsed.files)) {\n return parsed as Checkpoint;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nexport interface CreateCheckpointOptions {\n rootDir: string;\n name: string;\n source?: Checkpoint[\"source\"];\n paths: readonly string[];\n}\n\n/** Missing files recorded as `content: null` so restore knows to delete; ID has random suffix to avoid same-ms collision. */\nexport function createCheckpoint(opts: CreateCheckpointOptions): CheckpointMeta {\n const absRoot = resolve(opts.rootDir);\n const id = `cp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;\n const files: CheckpointFile[] = [];\n let bytes = 0;\n const seen = new Set<string>();\n for (const p of opts.paths) {\n if (seen.has(p)) continue;\n seen.add(p);\n const abs = resolve(absRoot, p);\n // Path-escape guard. A snapshot of `../../../etc/passwd` is not\n // something we want — refuse silently rather than abort the whole\n // checkpoint.\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep}`)) continue;\n const rel = relative(absRoot, abs).split(sep).join(\"/\");\n if (existsSync(abs)) {\n try {\n const content = readFileSync(abs, \"utf8\");\n files.push({ path: rel, content });\n bytes += content.length;\n } catch {\n // Unreadable (binary, perms) — record as null so restore knows\n // to delete on revert. Wrong for binary files but consistent.\n files.push({ path: rel, content: null });\n }\n } else {\n files.push({ path: rel, content: null });\n }\n }\n\n const checkpoint: Checkpoint = {\n id,\n name: opts.name,\n rootDir: absRoot,\n createdAt: Date.now(),\n source: opts.source ?? \"manual\",\n files,\n bytes,\n };\n const cpPath = snapshotPath(absRoot, id);\n mkdirSync(dirname(cpPath), { recursive: true });\n writeFileSync(cpPath, JSON.stringify(checkpoint), \"utf8\");\n\n const meta: CheckpointMeta = {\n id,\n name: opts.name,\n createdAt: checkpoint.createdAt,\n source: checkpoint.source,\n fileCount: files.length,\n bytes,\n };\n const items = listCheckpoints(absRoot);\n items.push(meta);\n writeIndex(absRoot, items);\n return meta;\n}\n\n/** Most-recent name wins on collision. */\nexport function findCheckpoint(rootDir: string, idOrName: string): CheckpointMeta | null {\n const items = listCheckpoints(rootDir);\n // Prefer exact id match, then most-recent name match.\n const byId = items.find((m) => m.id === idOrName);\n if (byId) return byId;\n const byName = [...items].reverse().find((m) => m.name === idOrName);\n return byName ?? null;\n}\n\nexport interface RestoreResult {\n /** Files we wrote back to disk. */\n restored: string[];\n /** Files we removed (snapshot had `content: null`, file existed). */\n removed: string[];\n /** Files we couldn't touch (errors), with the reason. */\n skipped: Array<{ path: string; reason: string }>;\n}\n\n/** Path-escape rechecked against live `rootDir` since snapshot's may differ (project moved). */\nexport function restoreCheckpoint(rootDir: string, id: string): RestoreResult {\n const cp = loadCheckpoint(rootDir, id);\n const absRoot = resolve(rootDir);\n const result: RestoreResult = { restored: [], removed: [], skipped: [] };\n if (!cp) {\n result.skipped.push({ path: \"(checkpoint)\", reason: `not found: ${id}` });\n return result;\n }\n for (const f of cp.files) {\n const abs = resolve(absRoot, f.path);\n if (abs !== absRoot && !abs.startsWith(`${absRoot}${sep}`)) {\n result.skipped.push({ path: f.path, reason: \"path escapes rootDir\" });\n continue;\n }\n try {\n if (f.content === null) {\n if (existsSync(abs)) {\n rmSync(abs);\n result.removed.push(f.path);\n }\n } else {\n mkdirSync(dirname(abs), { recursive: true });\n writeFileSync(abs, f.content, \"utf8\");\n result.restored.push(f.path);\n }\n } catch (err) {\n result.skipped.push({ path: f.path, reason: (err as Error).message });\n }\n }\n return result;\n}\n\nexport function deleteCheckpoint(rootDir: string, id: string): boolean {\n const cpPath = snapshotPath(rootDir, id);\n let removed = false;\n if (existsSync(cpPath)) {\n try {\n rmSync(cpPath);\n removed = true;\n } catch {\n return false;\n }\n }\n const items = listCheckpoints(rootDir);\n const next = items.filter((m) => m.id !== id);\n if (next.length !== items.length) {\n writeIndex(rootDir, next);\n removed = true;\n }\n return removed;\n}\n\n/** Format ms-timestamp diff as human-readable relative age. */\nexport function fmtAgo(ms: number): string {\n const now = Date.now();\n const diff = Math.max(0, now - ms);\n const s = Math.floor(diff / 1000);\n if (s < 60) return `${s}s ago`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ago`;\n const h = Math.floor(m / 60);\n if (h < 24) return `${h}h ago`;\n const d = Math.floor(h / 24);\n return `${d}d ago`;\n}\n","/** Persists structured plan state alongside the JSONL log; markdown body lives in the log (it was a tool result) and replays on resume. */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { sanitizeName, sessionsDir } from \"../memory/session.js\";\nimport type { PlanStep, StepCompletion, StepEvidence } from \"../tools/plan.js\";\n\nexport interface PlanStateOnDisk {\n /** File format version — bump when shape changes. */\n version: 1 | 2;\n steps: PlanStep[];\n completedStepIds: string[];\n stepCompletions?: Record<string, StepCompletion>;\n /** ISO8601 timestamp of the last write. */\n updatedAt: string;\n body?: string;\n summary?: string;\n}\n\nexport function planStatePath(sessionName: string): string {\n return join(sessionsDir(), `${sanitizeName(sessionName)}.plan.json`);\n}\n\nexport function loadPlanState(sessionName: string): PlanStateOnDisk | null {\n const path = planStatePath(sessionName);\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (!parsed || typeof parsed !== \"object\") return null;\n if (parsed.version !== 1 && parsed.version !== 2) return null;\n if (!Array.isArray(parsed.steps)) return null;\n if (!Array.isArray(parsed.completedStepIds)) return null;\n if (typeof parsed.updatedAt !== \"string\") return null;\n // Defensive: filter out any malformed step entries so a partially\n // corrupted file still yields a usable subset.\n const steps: PlanStep[] = [];\n for (const s of parsed.steps) {\n if (!s || typeof s !== \"object\") continue;\n const e = s as unknown as Record<string, unknown>;\n if (typeof e.id !== \"string\" || !e.id) continue;\n if (typeof e.title !== \"string\" || !e.title) continue;\n if (typeof e.action !== \"string\" || !e.action) continue;\n const step: PlanStep = { id: e.id, title: e.title, action: e.action };\n if (e.risk === \"low\" || e.risk === \"med\" || e.risk === \"high\") step.risk = e.risk;\n const targets = stringList(e.targets);\n if (targets) step.targets = targets;\n if (typeof e.acceptance === \"string\" && e.acceptance.trim()) {\n step.acceptance = e.acceptance.trim();\n }\n const verification = stringList(e.verification);\n if (verification) step.verification = verification;\n steps.push(step);\n }\n if (steps.length === 0) return null;\n const completedStepIds = parsed.completedStepIds.filter(\n (id): id is string => typeof id === \"string\" && id.length > 0,\n );\n const stepCompletions = sanitizeStepCompletions(parsed.stepCompletions);\n const out: PlanStateOnDisk = {\n version: parsed.version,\n steps,\n completedStepIds,\n updatedAt: parsed.updatedAt,\n };\n if (stepCompletions) out.stepCompletions = stepCompletions;\n if (typeof parsed.body === \"string\" && parsed.body) out.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) out.summary = parsed.summary;\n return out;\n } catch {\n return null;\n }\n}\n\n/** Best-effort: write failure logs to stderr instead of crashing the TUI. */\nexport function savePlanState(\n sessionName: string,\n steps: PlanStep[],\n completedStepIds: Iterable<string>,\n extras?: {\n body?: string;\n summary?: string;\n stepCompletions?: ReadonlyMap<string, StepCompletion> | Record<string, StepCompletion>;\n },\n): void {\n const path = planStatePath(sessionName);\n try {\n mkdirSync(dirname(path), { recursive: true });\n const state: PlanStateOnDisk = {\n version: 2,\n steps,\n completedStepIds: [...completedStepIds],\n updatedAt: new Date().toISOString(),\n };\n const stepCompletions = normalizeStepCompletionsForWrite(extras?.stepCompletions);\n if (stepCompletions) state.stepCompletions = stepCompletions;\n if (extras?.body) state.body = extras.body;\n if (extras?.summary) state.summary = extras.summary;\n writeFileSync(path, `${JSON.stringify(state, null, 2)}\\n`, \"utf8\");\n } catch (err) {\n process.stderr.write(\n `▸ plan-store: failed to save plan for \"${sessionName}\": ${(err as Error).message}\\n`,\n );\n }\n}\n\n/** Remove the persisted plan, if any. Used on cancel / clean reset. */\nexport function clearPlanState(sessionName: string): void {\n const path = planStatePath(sessionName);\n try {\n if (existsSync(path)) unlinkSync(path);\n } catch {\n /* nothing to do — leftover file is harmless, will be overwritten next save */\n }\n}\n\n/** Random suffix avoids same-millisecond collision; `:`/`.` swapped for Windows-safe filenames. */\nexport function archivePlanState(sessionName: string): string | null {\n const active = planStatePath(sessionName);\n if (!existsSync(active)) return null;\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const suffix = Math.random().toString(36).slice(2, 6);\n const archive = join(\n sessionsDir(),\n `${sanitizeName(sessionName)}.plan.${stamp}-${suffix}.done.json`,\n );\n try {\n renameSync(active, archive);\n return archive;\n } catch (err) {\n process.stderr.write(\n `▸ plan-store: failed to archive plan for \"${sessionName}\": ${(err as Error).message}\\n`,\n );\n return null;\n }\n}\n\nexport interface PlanArchiveSummary {\n path: string;\n completedAt: string;\n steps: PlanStep[];\n completedStepIds: string[];\n stepCompletions?: Record<string, StepCompletion>;\n /** Markdown body, when the archive carried it. */\n body?: string;\n /** One-line human-friendly title, when supplied. */\n summary?: string;\n}\n\nexport function listPlanArchives(sessionName: string): PlanArchiveSummary[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n const prefix = `${sanitizeName(sessionName)}.plan.`;\n const suffix = \".done.json\";\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n const summaries: PlanArchiveSummary[] = [];\n for (const name of entries) {\n if (!name.startsWith(prefix) || !name.endsWith(suffix)) continue;\n const full = join(dir, name);\n try {\n const raw = readFileSync(full, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (parsed.version !== 1 && parsed.version !== 2) continue;\n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) continue;\n const steps = parsed.steps.filter(\n (s): s is PlanStep =>\n !!s &&\n typeof s === \"object\" &&\n typeof (s as PlanStep).id === \"string\" &&\n typeof (s as PlanStep).title === \"string\" &&\n typeof (s as PlanStep).action === \"string\",\n );\n if (steps.length === 0) continue;\n const completedStepIds = Array.isArray(parsed.completedStepIds)\n ? parsed.completedStepIds.filter((id): id is string => typeof id === \"string\" && !!id)\n : [];\n // Prefer the file's own updatedAt; fall back to mtime if missing\n // or unparseable so a hand-edited archive still sorts sensibly.\n let completedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : \"\";\n if (!completedAt || Number.isNaN(Date.parse(completedAt))) {\n try {\n completedAt = statSync(full).mtime.toISOString();\n } catch {\n completedAt = new Date(0).toISOString();\n }\n }\n const entry: PlanArchiveSummary = { path: full, completedAt, steps, completedStepIds };\n const stepCompletions = sanitizeStepCompletions(parsed.stepCompletions);\n if (stepCompletions) entry.stepCompletions = stepCompletions;\n if (typeof parsed.body === \"string\" && parsed.body) entry.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) entry.summary = parsed.summary;\n summaries.push(entry);\n } catch {\n // Skip the corrupt archive entirely.\n }\n }\n summaries.sort((a, b) => b.completedAt.localeCompare(a.completedAt));\n return summaries;\n}\n\nexport interface PlanArchiveWithSession extends PlanArchiveSummary {\n sessionName: string;\n}\n\n/** Cross-session enumeration in a single dir scan — used by the dashboard plans panel where the per-session loop was O(N×M) and timed out for users with hundreds of sessions. */\nexport function listAllPlanArchives(): PlanArchiveWithSession[] {\n const dir = sessionsDir();\n if (!existsSync(dir)) return [];\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n const out: PlanArchiveWithSession[] = [];\n const suffix = \".done.json\";\n const planMarker = \".plan.\";\n for (const name of entries) {\n if (!name.endsWith(suffix)) continue;\n const planIdx = name.indexOf(planMarker);\n if (planIdx < 0) continue;\n const sessionName = name.slice(0, planIdx);\n if (!sessionName) continue;\n const full = join(dir, name);\n try {\n const raw = readFileSync(full, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<PlanStateOnDisk>;\n if (parsed.version !== 1 && parsed.version !== 2) continue;\n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) continue;\n const steps = parsed.steps.filter(\n (s): s is PlanStep =>\n !!s &&\n typeof s === \"object\" &&\n typeof (s as PlanStep).id === \"string\" &&\n typeof (s as PlanStep).title === \"string\" &&\n typeof (s as PlanStep).action === \"string\",\n );\n if (steps.length === 0) continue;\n const completedStepIds = Array.isArray(parsed.completedStepIds)\n ? parsed.completedStepIds.filter((id): id is string => typeof id === \"string\" && !!id)\n : [];\n let completedAt = typeof parsed.updatedAt === \"string\" ? parsed.updatedAt : \"\";\n if (!completedAt || Number.isNaN(Date.parse(completedAt))) {\n try {\n completedAt = statSync(full).mtime.toISOString();\n } catch {\n completedAt = new Date(0).toISOString();\n }\n }\n const entry: PlanArchiveWithSession = {\n sessionName,\n path: full,\n completedAt,\n steps,\n completedStepIds,\n };\n const stepCompletions = sanitizeStepCompletions(parsed.stepCompletions);\n if (stepCompletions) entry.stepCompletions = stepCompletions;\n if (typeof parsed.body === \"string\" && parsed.body) entry.body = parsed.body;\n if (typeof parsed.summary === \"string\" && parsed.summary) entry.summary = parsed.summary;\n out.push(entry);\n } catch {\n // Skip the corrupt archive entirely.\n }\n }\n out.sort((a, b) => b.completedAt.localeCompare(a.completedAt));\n return out;\n}\n\nfunction stringList(raw: unknown): string[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out = raw\n .map((entry) => (typeof entry === \"string\" ? entry.trim() : \"\"))\n .filter((entry) => entry.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\nfunction normalizeStepCompletionsForWrite(\n raw: ReadonlyMap<string, StepCompletion> | Record<string, StepCompletion> | undefined,\n): Record<string, StepCompletion> | undefined {\n if (!raw) return undefined;\n const entries =\n raw instanceof Map\n ? [...raw.entries()]\n : (Object.entries(raw) as Array<[string, StepCompletion]>);\n const out: Record<string, StepCompletion> = {};\n for (const [key, value] of entries) {\n const completion = sanitizeStepCompletion(value, key);\n if (completion) out[completion.stepId] = completion;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction sanitizeStepCompletions(raw: unknown): Record<string, StepCompletion> | undefined {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n const out: Record<string, StepCompletion> = {};\n for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {\n const completion = sanitizeStepCompletion(value, key);\n if (completion) out[completion.stepId] = completion;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction sanitizeStepCompletion(raw: unknown, fallbackStepId?: string): StepCompletion | undefined {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n const entry = raw as Record<string, unknown>;\n const stepId =\n typeof entry.stepId === \"string\" && entry.stepId.trim()\n ? entry.stepId.trim()\n : fallbackStepId?.trim();\n const result = typeof entry.result === \"string\" ? entry.result.trim() : \"\";\n if (!stepId || !result) return undefined;\n const completion: StepCompletion = { kind: \"step_completed\", stepId, result };\n if (typeof entry.title === \"string\" && entry.title.trim()) completion.title = entry.title.trim();\n if (typeof entry.notes === \"string\" && entry.notes.trim()) completion.notes = entry.notes.trim();\n const evidence = sanitizeEvidenceList(entry.evidence);\n if (evidence) completion.evidence = evidence;\n return completion;\n}\n\nfunction sanitizeEvidenceList(raw: unknown): StepEvidence[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: StepEvidence[] = [];\n for (const item of raw) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n const entry = item as Record<string, unknown>;\n const kind = entry.kind;\n if (kind !== \"verification\" && kind !== \"diff\" && kind !== \"checkpoint\" && kind !== \"manual\") {\n continue;\n }\n const summary = typeof entry.summary === \"string\" ? entry.summary.trim() : \"\";\n if (!summary) continue;\n const evidence: StepEvidence = { kind, summary };\n if (typeof entry.command === \"string\" && entry.command.trim()) {\n evidence.command = entry.command.trim();\n }\n const paths = stringList(entry.paths);\n if (paths) evidence.paths = paths;\n out.push(evidence);\n }\n return out.length > 0 ? out : undefined;\n}\n\n/** Falls back to raw ISO string past a week — \"47 days ago\" misleads more than it helps. */\nexport function relativeTime(updatedAt: string, now: number = Date.now()): string {\n const t = Date.parse(updatedAt);\n if (Number.isNaN(t)) return updatedAt;\n const diffMs = Math.max(0, now - t);\n const sec = Math.floor(diffMs / 1000);\n if (sec < 60) return `${sec}s ago`;\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.floor(hr / 24);\n if (day < 7) return `${day}d ago`;\n return updatedAt.slice(0, 10);\n}\n","import type { SlashArgContext, SlashCommandSpec, SlashGroup } from \"./types.js\";\n\nexport const SLASH_GROUP_ORDER = [\n \"setup\",\n \"info\",\n \"chat\",\n \"extend\",\n \"session\",\n \"code\",\n \"jobs\",\n \"advanced\",\n] as const satisfies readonly SlashGroup[];\n\nexport const SLASH_GROUP_LABEL: Record<SlashGroup, string> = {\n setup: \"SETUP\",\n info: \"INFO\",\n chat: \"CHAT\",\n extend: \"EXTEND\",\n session: \"SESSION\",\n code: \"CODE\",\n jobs: \"JOBS\",\n advanced: \"ADVANCED\",\n};\n\nconst SLASH_GROUP_RANK = new Map<SlashGroup, number>(\n SLASH_GROUP_ORDER.map((group, index) => [group, index]),\n);\n\nexport function orderSlashCommandsByGroup<T extends Pick<SlashCommandSpec, \"group\">>(\n commands: readonly T[],\n): T[] {\n return commands\n .map((command, index) => ({ command, index }))\n .sort((a, b) => {\n const groupDiff =\n SLASH_GROUP_RANK.get(a.command.group)! - SLASH_GROUP_RANK.get(b.command.group)!;\n if (groupDiff !== 0) return groupDiff;\n return a.index - b.index;\n })\n .map((entry) => entry.command);\n}\n\nexport const SLASH_COMMANDS: readonly SlashCommandSpec[] = [\n { cmd: \"help\", group: \"chat\", summary: \"show the full command reference\", aliases: [\"?\"] },\n {\n cmd: \"new\",\n group: \"chat\",\n summary: \"start a fresh conversation (clear context + scrollback)\",\n aliases: [\"reset\", \"clear\"],\n },\n { cmd: \"retry\", group: \"chat\", summary: \"truncate & resend your last message (fresh sample)\" },\n {\n cmd: \"compact\",\n group: \"chat\",\n summary:\n \"fold older turns into a summary message (cache-safe). Auto-fires at 50% ctx; this is the manual trigger.\",\n },\n {\n cmd: \"stop\",\n group: \"chat\",\n summary: \"abort the current model turn (typed alternative to Esc)\",\n },\n {\n cmd: \"btw\",\n group: \"chat\",\n argsHint: \"<question>\",\n summary:\n \"ask a quick side question — answered from a blank slate, never added to the conversation context\",\n },\n\n {\n cmd: \"preset\",\n group: \"setup\",\n argsHint: \"<auto|flash|pro>\",\n summary: \"model bundle — auto escalates flash → pro, flash/pro lock. Bare opens picker.\",\n argCompleter: [\"auto\", \"flash\", \"pro\"],\n },\n {\n cmd: \"model\",\n group: \"setup\",\n argsHint: \"<id>\",\n summary: \"switch DeepSeek model id. Bare opens picker.\",\n argCompleter: \"models\",\n },\n {\n cmd: \"language\",\n group: \"setup\",\n argsHint: \"<EN|zh-CN>\",\n summary: \"switch the runtime language\",\n argCompleter: [\"EN\", \"zh-CN\"],\n aliases: [\"lang\"],\n },\n {\n cmd: \"theme\",\n group: \"setup\",\n argsHint: \"[auto|default|dark|light|tokyo-night|github-dark|github-light|high-contrast]\",\n summary: \"show or persist the terminal theme preference. Bare opens picker.\",\n argCompleter: [\n \"auto\",\n \"default\",\n \"dark\",\n \"light\",\n \"tokyo-night\",\n \"github-dark\",\n \"github-light\",\n \"high-contrast\",\n ],\n },\n\n { cmd: \"status\", group: \"info\", summary: \"current model, flags, context, session\" },\n {\n cmd: \"cost\",\n group: \"info\",\n argsHint: \"[text]\",\n summary:\n \"bare → last turn's spend (Usage card); with text → estimate cost of sending it next (worst-case + likely-cache)\",\n },\n {\n cmd: \"context\",\n group: \"info\",\n summary: \"show context-window breakdown (system / tools / log / input)\",\n },\n {\n cmd: \"stats\",\n group: \"info\",\n summary:\n \"cross-session cost dashboard (today / week / month / all-time · cache hit · vs Claude)\",\n },\n {\n cmd: \"doctor\",\n group: \"info\",\n summary: \"health check (api / config / api-reach / index / hooks / project)\",\n },\n {\n cmd: \"keys\",\n group: \"info\",\n summary: \"keyboard + mouse + copy/paste reference\",\n },\n {\n cmd: \"copy\",\n group: \"chat\",\n summary: \"vim/tmux-style copy mode — j/k navigate, v select, y yank to clipboard\",\n },\n {\n cmd: \"feedback\",\n group: \"info\",\n summary: \"open a GitHub issue with diagnostic info copied to clipboard\",\n },\n {\n cmd: \"about\",\n group: \"info\",\n summary: \"project info — version, website, repo, license\",\n },\n\n { cmd: \"sessions\", group: \"session\", summary: \"list saved sessions (current marked with ▸)\" },\n {\n cmd: \"title\",\n group: \"session\",\n summary: \"ask the model to rename this session from the conversation\",\n aliases: [\"retitle\"],\n },\n\n { cmd: \"mcp\", group: \"extend\", summary: \"list MCP servers + tools attached to this session\" },\n {\n cmd: \"resource\",\n group: \"extend\",\n argsHint: \"[uri]\",\n summary: \"browse + read MCP resources (no arg → list URIs; <uri> → fetch contents)\",\n argCompleter: \"mcp-resources\",\n },\n {\n cmd: \"prompt\",\n group: \"extend\",\n argsHint: \"[name]\",\n summary: \"browse + fetch MCP prompts (no arg → list names; <name> → render prompt)\",\n argCompleter: \"mcp-prompts\",\n },\n {\n cmd: \"memory\",\n group: \"extend\",\n argsHint: \"[list|show <name>|forget <name>|clear <scope> confirm]\",\n summary: \"show / manage pinned memory (REASONIX.md + ~/.reasonix/memory)\",\n },\n {\n cmd: \"skill\",\n group: \"extend\",\n argsHint:\n \"[list|paths|paths add <path>|paths remove <path|N>|show <name>|new <name>|<name> [args]]\",\n summary: \"list / run / scaffold skills (project + custom + global + builtin)\",\n argCompleter: \"skills\",\n },\n {\n cmd: \"qq\",\n group: \"extend\",\n argsHint: \"<connect|status|disconnect>\",\n summary: \"connect, inspect, or disconnect the QQ channel\",\n argCompleter: [\"connect\", \"status\", \"disconnect\"],\n },\n\n {\n cmd: \"init\",\n group: \"code\",\n argsHint: \"[force]\",\n summary:\n \"scan the project and synthesize a baseline REASONIX.md (model writes; review with /apply). `force` overwrites an existing file.\",\n contextual: \"code\",\n argCompleter: [\"force\"],\n },\n {\n cmd: \"apply\",\n group: \"code\",\n argsHint: \"[N|N,M|N-M]\",\n summary:\n \"commit pending edit blocks to disk (no arg → all; `1`, `1,3`, or `1-4` → that subset, rest stay pending)\",\n contextual: \"code\",\n },\n {\n cmd: \"discard\",\n group: \"code\",\n argsHint: \"[N|N,M|N-M]\",\n summary: \"drop pending edit blocks without writing (no arg → all; indices → that subset)\",\n contextual: \"code\",\n },\n {\n cmd: \"walk\",\n group: \"code\",\n summary:\n \"step through pending edits one block at a time (git-add-p style: y/n per block, a apply rest, A flip AUTO)\",\n contextual: \"code\",\n },\n {\n cmd: \"undo\",\n group: \"code\",\n summary: \"roll back the last applied edit batch\",\n contextual: \"code\",\n },\n {\n cmd: \"history\",\n group: \"code\",\n summary: \"list every edit batch this session (ids for /show, undone markers)\",\n contextual: \"code\",\n },\n {\n cmd: \"show\",\n group: \"code\",\n argsHint: \"[id]\",\n summary: \"dump a stored edit diff (omit id for newest non-undone)\",\n contextual: \"code\",\n },\n {\n cmd: \"commit\",\n group: \"code\",\n argsHint: '\"msg\"',\n summary: \"git add -A && git commit -m ...\",\n contextual: \"code\",\n },\n {\n cmd: \"mode\",\n group: \"code\",\n argsHint: \"[review|auto|yolo]\",\n summary:\n \"edit-gate: review (queue) · auto (apply+undo) · yolo (apply+auto-shell). Shift+Tab cycles.\",\n contextual: \"code\",\n argCompleter: [\"review\", \"auto\", \"yolo\"],\n },\n {\n cmd: \"plan\",\n group: \"code\",\n argsHint: \"[on|off|strict]\",\n summary: \"toggle read-only plan mode / strict lifecycle rails\",\n contextual: \"code\",\n argCompleter: [\"on\", \"off\", \"strict\"],\n },\n {\n cmd: \"checkpoint\",\n group: \"code\",\n argsHint: \"[name|list|forget <id>]\",\n summary:\n \"snapshot every file the session has touched (Cursor-style internal store, not git). /checkpoint alone lists.\",\n contextual: \"code\",\n argCompleter: [\"list\", \"forget\"],\n },\n {\n cmd: \"restore\",\n group: \"code\",\n argsHint: \"<name|id>\",\n summary: \"roll back files to a named checkpoint (see /checkpoint list)\",\n contextual: \"code\",\n },\n {\n cmd: \"cwd\",\n group: \"code\",\n argsHint: \"[path]\",\n summary:\n \"switch the workspace root mid-session — re-points fs / shell / memory tools, reloads project hooks, refreshes the at-mention walker\",\n contextual: \"code\",\n aliases: [\"sandbox\"],\n argCompleter: \"path\",\n },\n\n {\n cmd: \"jobs\",\n group: \"jobs\",\n summary: \"list background jobs started by run_background\",\n contextual: \"code\",\n },\n {\n cmd: \"kill\",\n group: \"jobs\",\n argsHint: \"<id>\",\n summary: \"stop a background job by id (SIGTERM → SIGKILL after grace)\",\n contextual: \"code\",\n },\n {\n cmd: \"logs\",\n group: \"jobs\",\n argsHint: \"<id> [lines]\",\n summary: \"tail a background job's output (default last 80 lines)\",\n contextual: \"code\",\n },\n\n {\n cmd: \"pro\",\n group: \"advanced\",\n argsHint: \"[off]\",\n summary: \"arm v4-pro for the NEXT turn only (one-shot · auto-disarms after turn)\",\n argCompleter: [\"off\"],\n },\n {\n cmd: \"budget\",\n group: \"advanced\",\n argsHint: \"[usd|off]\",\n summary:\n \"session USD cap — warns at 80%, refuses next turn at 100%. Off by default. /budget alone shows status\",\n argCompleter: [\"off\", \"1\", \"5\", \"10\", \"20\", \"50\"],\n },\n {\n cmd: \"search-engine\",\n group: \"advanced\",\n argsHint: \"<mojeek|searxng|metaso|tavily|perplexity|exa> [<key>]\",\n summary:\n \"switch web search backend — mojeek (default, no deps), searxng (self-hosted), metaso (free 100/d), tavily (free 1000/mo), perplexity (AI-native), or exa (AI-native). Provider with no key prompts inline config.\",\n argCompleter: [\"mojeek\", \"searxng\", \"metaso\", \"tavily\", \"perplexity\", \"exa\"],\n aliases: [\"se\"],\n },\n {\n cmd: \"hooks\",\n group: \"advanced\",\n argsHint: \"[reload]\",\n summary: \"list active hooks (settings.json under .reasonix/) · reload re-reads from disk\",\n },\n {\n cmd: \"permissions\",\n group: \"advanced\",\n argsHint: \"[list|add <prefix>|remove <prefix|N>|clear confirm]\",\n summary:\n \"show / edit shell allowlist (builtin read-only · per-project: ~/.reasonix/config.json)\",\n argCompleter: [\"list\", \"add\", \"remove\", \"clear\"],\n },\n {\n cmd: \"dashboard\",\n group: \"advanced\",\n argsHint: \"[stop]\",\n summary: \"launch the embedded web dashboard (127.0.0.1, token-gated)\",\n argCompleter: [\"stop\"],\n },\n {\n cmd: \"loop\",\n group: \"advanced\",\n argsHint: \"<5s..6h> <prompt> · stop · (no args = status)\",\n summary: \"auto-resubmit <prompt> every <interval> until you type something / Esc / /loop stop\",\n },\n {\n cmd: \"plans\",\n group: \"advanced\",\n summary: \"list this session's active + archived plans, newest first\",\n },\n {\n cmd: \"replay\",\n group: \"advanced\",\n summary: \"load an archived plan as a read-only Time Travel snapshot (default: newest)\",\n argsHint: \"[N]\",\n },\n {\n cmd: \"update\",\n group: \"advanced\",\n summary: \"show current vs latest version + the shell command to upgrade\",\n },\n { cmd: \"exit\", group: \"advanced\", summary: \"quit the TUI\", aliases: [\"quit\", \"q\"] },\n];\n\nexport function suggestSlashCommands(\n prefix: string,\n codeMode = false,\n counts?: Readonly<Record<string, number>>,\n): SlashCommandSpec[] {\n const p = prefix.toLowerCase();\n const matches = SLASH_COMMANDS.filter((c) => {\n // Empty prefix = browsing the menu — show the full release command surface except\n // advanced rows, which remain collapsed behind the footer hint.\n if (p === \"\") return c.group !== \"advanced\";\n if (c.contextual === \"code\" && !codeMode) return false;\n if (c.cmd.startsWith(p)) return true;\n return c.aliases?.some((a) => a.startsWith(p)) ?? false;\n });\n if (p === \"\") return orderSlashCommandsByGroup(matches);\n if (!counts) return matches;\n const indexOf = new Map(matches.map((s, i) => [s.cmd, i]));\n return [...matches].sort((a, b) => {\n const diff = (counts[b.cmd] ?? 0) - (counts[a.cmd] ?? 0);\n if (diff !== 0) return diff;\n return (indexOf.get(a.cmd) ?? 0) - (indexOf.get(b.cmd) ?? 0);\n });\n}\n\nexport function countAdvancedCommands(codeMode: boolean): number {\n return SLASH_COMMANDS.filter(\n (c) => c.group === \"advanced\" && (c.contextual !== \"code\" || codeMode),\n ).length;\n}\n\n/** alias → canonical cmd map, derived from SLASH_COMMANDS at module init. */\nconst ALIAS_TO_CMD: Readonly<Record<string, string>> = (() => {\n const m: Record<string, string> = {};\n for (const spec of SLASH_COMMANDS) {\n if (!spec.aliases) continue;\n for (const a of spec.aliases) m[a] = spec.cmd;\n }\n return m;\n})();\n\nexport function resolveSlashAlias(name: string): string {\n return ALIAS_TO_CMD[name] ?? name;\n}\n\n/** Picker fires only when arg tail has no internal whitespace; past that it's a usage hint. */\nexport function detectSlashArgContext(input: string, codeMode = false): SlashArgContext | null {\n const m = /^\\/(\\S+) ([\\s\\S]*)$/.exec(input);\n if (!m) return null;\n const cmdName = resolveSlashAlias(m[1]!.toLowerCase());\n const tail = m[2] ?? \"\";\n const spec = SLASH_COMMANDS.find(\n (s) => s.cmd === cmdName && (s.contextual !== \"code\" || codeMode),\n );\n if (!spec) return null;\n const hasInternalSpace = /\\s/.test(tail);\n const partialOffset = input.length - tail.length;\n if (hasInternalSpace) {\n return { spec, partial: tail, partialOffset, kind: \"hint\" };\n }\n return {\n spec,\n partial: tail,\n partialOffset,\n kind: spec.argCompleter ? \"picker\" : \"hint\",\n };\n}\n\nexport function parseSlash(text: string): { cmd: string; args: string[] } | null {\n if (!text.startsWith(\"/\")) return null;\n // \"//\" is a line comment, not a slash command\n if (text.startsWith(\"//\")) return null;\n const parts = text.slice(1).trim().split(/\\s+/);\n const cmd = parts[0]?.toLowerCase() ?? \"\";\n if (!cmd) return null;\n return { cmd, args: parts.slice(1) };\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","readFileSync","readdirSync","writeFileSync","dirname","join","join","existsSync","readFileSync","mkdirSync","dirname","writeFileSync","readdirSync"]}