@open-mercato/cezar 0.1.5-pr506.357

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 (264) hide show
  1. package/README.md +573 -0
  2. package/dist/config.d.ts +144 -0
  3. package/dist/config.js +106 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/core/agent-runner.d.ts +169 -0
  6. package/dist/core/agent-runner.js +23 -0
  7. package/dist/core/agent-runner.js.map +1 -0
  8. package/dist/core/backend-detect.d.ts +16 -0
  9. package/dist/core/backend-detect.js +118 -0
  10. package/dist/core/backend-detect.js.map +1 -0
  11. package/dist/core/claude-cli-runner.d.ts +56 -0
  12. package/dist/core/claude-cli-runner.js +416 -0
  13. package/dist/core/claude-cli-runner.js.map +1 -0
  14. package/dist/core/claude-ui-mapper.d.ts +71 -0
  15. package/dist/core/claude-ui-mapper.js +567 -0
  16. package/dist/core/claude-ui-mapper.js.map +1 -0
  17. package/dist/core/codex-app-server-runner.d.ts +29 -0
  18. package/dist/core/codex-app-server-runner.js +489 -0
  19. package/dist/core/codex-app-server-runner.js.map +1 -0
  20. package/dist/core/codex-ui-mapper.d.ts +63 -0
  21. package/dist/core/codex-ui-mapper.js +491 -0
  22. package/dist/core/codex-ui-mapper.js.map +1 -0
  23. package/dist/core/ndjson.d.ts +6 -0
  24. package/dist/core/ndjson.js +23 -0
  25. package/dist/core/ndjson.js.map +1 -0
  26. package/dist/core/opencode-server-runner.d.ts +30 -0
  27. package/dist/core/opencode-server-runner.js +488 -0
  28. package/dist/core/opencode-server-runner.js.map +1 -0
  29. package/dist/core/opencode-ui-mapper.d.ts +105 -0
  30. package/dist/core/opencode-ui-mapper.js +588 -0
  31. package/dist/core/opencode-ui-mapper.js.map +1 -0
  32. package/dist/core/process-usage.d.ts +63 -0
  33. package/dist/core/process-usage.js +181 -0
  34. package/dist/core/process-usage.js.map +1 -0
  35. package/dist/core/runner-factory.d.ts +8 -0
  36. package/dist/core/runner-factory.js +22 -0
  37. package/dist/core/runner-factory.js.map +1 -0
  38. package/dist/core/tool-display.d.ts +30 -0
  39. package/dist/core/tool-display.js +156 -0
  40. package/dist/core/tool-display.js.map +1 -0
  41. package/dist/core/ui-events.d.ts +308 -0
  42. package/dist/core/ui-events.js +25 -0
  43. package/dist/core/ui-events.js.map +1 -0
  44. package/dist/core/usage.d.ts +11 -0
  45. package/dist/core/usage.js +15 -0
  46. package/dist/core/usage.js.map +1 -0
  47. package/dist/git-worktree.d.ts +88 -0
  48. package/dist/git-worktree.js +297 -0
  49. package/dist/git-worktree.js.map +1 -0
  50. package/dist/handoff.d.ts +62 -0
  51. package/dist/handoff.js +147 -0
  52. package/dist/handoff.js.map +1 -0
  53. package/dist/index.d.ts +2 -0
  54. package/dist/index.js +466 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/install-as-command.d.ts +39 -0
  57. package/dist/install-as-command.js +51 -0
  58. package/dist/install-as-command.js.map +1 -0
  59. package/dist/pack-check.d.ts +17 -0
  60. package/dist/pack-check.js +27 -0
  61. package/dist/pack-check.js.map +1 -0
  62. package/dist/paths.d.ts +23 -0
  63. package/dist/paths.js +34 -0
  64. package/dist/paths.js.map +1 -0
  65. package/dist/planner.d.ts +17 -0
  66. package/dist/planner.js +248 -0
  67. package/dist/planner.js.map +1 -0
  68. package/dist/release/snapshot.d.ts +64 -0
  69. package/dist/release/snapshot.js +75 -0
  70. package/dist/release/snapshot.js.map +1 -0
  71. package/dist/release/stable.d.ts +46 -0
  72. package/dist/release/stable.js +57 -0
  73. package/dist/release/stable.js.map +1 -0
  74. package/dist/runs/auto-name.d.ts +75 -0
  75. package/dist/runs/auto-name.js +168 -0
  76. package/dist/runs/auto-name.js.map +1 -0
  77. package/dist/runs/retention.d.ts +60 -0
  78. package/dist/runs/retention.js +86 -0
  79. package/dist/runs/retention.js.map +1 -0
  80. package/dist/runs/review-gate.d.ts +18 -0
  81. package/dist/runs/review-gate.js +21 -0
  82. package/dist/runs/review-gate.js.map +1 -0
  83. package/dist/runs/store.d.ts +408 -0
  84. package/dist/runs/store.js +526 -0
  85. package/dist/runs/store.js.map +1 -0
  86. package/dist/runs/task-refs.d.ts +24 -0
  87. package/dist/runs/task-refs.js +74 -0
  88. package/dist/runs/task-refs.js.map +1 -0
  89. package/dist/runs/ui-event-sink.d.ts +81 -0
  90. package/dist/runs/ui-event-sink.js +210 -0
  91. package/dist/runs/ui-event-sink.js.map +1 -0
  92. package/dist/server/capabilities.d.ts +33 -0
  93. package/dist/server/capabilities.js +43 -0
  94. package/dist/server/capabilities.js.map +1 -0
  95. package/dist/server/forge/github.d.ts +70 -0
  96. package/dist/server/forge/github.js +375 -0
  97. package/dist/server/forge/github.js.map +1 -0
  98. package/dist/server/forge/index.d.ts +24 -0
  99. package/dist/server/forge/index.js +45 -0
  100. package/dist/server/forge/index.js.map +1 -0
  101. package/dist/server/forge/types.d.ts +80 -0
  102. package/dist/server/forge/types.js +2 -0
  103. package/dist/server/forge/types.js.map +1 -0
  104. package/dist/server/git-changes.d.ts +195 -0
  105. package/dist/server/git-changes.js +497 -0
  106. package/dist/server/git-changes.js.map +1 -0
  107. package/dist/server/git.d.ts +26 -0
  108. package/dist/server/git.js +103 -0
  109. package/dist/server/git.js.map +1 -0
  110. package/dist/server/github.d.ts +8 -0
  111. package/dist/server/github.js +8 -0
  112. package/dist/server/github.js.map +1 -0
  113. package/dist/server/launch-key.d.ts +7 -0
  114. package/dist/server/launch-key.js +33 -0
  115. package/dist/server/launch-key.js.map +1 -0
  116. package/dist/server/open-in-app.d.ts +51 -0
  117. package/dist/server/open-in-app.js +189 -0
  118. package/dist/server/open-in-app.js.map +1 -0
  119. package/dist/server/open-in-terminal.d.ts +25 -0
  120. package/dist/server/open-in-terminal.js +120 -0
  121. package/dist/server/open-in-terminal.js.map +1 -0
  122. package/dist/server/pr.d.ts +7 -0
  123. package/dist/server/pr.js +7 -0
  124. package/dist/server/pr.js.map +1 -0
  125. package/dist/server/server.d.ts +41 -0
  126. package/dist/server/server.js +1390 -0
  127. package/dist/server/server.js.map +1 -0
  128. package/dist/server/static-ui.d.ts +49 -0
  129. package/dist/server/static-ui.js +92 -0
  130. package/dist/server/static-ui.js.map +1 -0
  131. package/dist/server/wsl.d.ts +25 -0
  132. package/dist/server/wsl.js +92 -0
  133. package/dist/server/wsl.js.map +1 -0
  134. package/dist/server-install/engine.d.ts +33 -0
  135. package/dist/server-install/engine.js +314 -0
  136. package/dist/server-install/engine.js.map +1 -0
  137. package/dist/server-install/platforms/macosx-ngrok.d.ts +6 -0
  138. package/dist/server-install/platforms/macosx-ngrok.js +345 -0
  139. package/dist/server-install/platforms/macosx-ngrok.js.map +1 -0
  140. package/dist/server-install/platforms/ubuntu-vps.d.ts +39 -0
  141. package/dist/server-install/platforms/ubuntu-vps.js +746 -0
  142. package/dist/server-install/platforms/ubuntu-vps.js.map +1 -0
  143. package/dist/server-install/state.d.ts +26 -0
  144. package/dist/server-install/state.js +125 -0
  145. package/dist/server-install/state.js.map +1 -0
  146. package/dist/server-install/steps.d.ts +109 -0
  147. package/dist/server-install/steps.js +330 -0
  148. package/dist/server-install/steps.js.map +1 -0
  149. package/dist/server-install/strategies.d.ts +4 -0
  150. package/dist/server-install/strategies.js +20 -0
  151. package/dist/server-install/strategies.js.map +1 -0
  152. package/dist/server-install/types.d.ts +597 -0
  153. package/dist/server-install/types.js +98 -0
  154. package/dist/server-install/types.js.map +1 -0
  155. package/dist/server-install/ui.d.ts +42 -0
  156. package/dist/server-install/ui.js +130 -0
  157. package/dist/server-install/ui.js.map +1 -0
  158. package/dist/skills-banner.d.ts +21 -0
  159. package/dist/skills-banner.js +40 -0
  160. package/dist/skills-banner.js.map +1 -0
  161. package/dist/skills-remote.d.ts +35 -0
  162. package/dist/skills-remote.js +266 -0
  163. package/dist/skills-remote.js.map +1 -0
  164. package/dist/skills.d.ts +45 -0
  165. package/dist/skills.js +182 -0
  166. package/dist/skills.js.map +1 -0
  167. package/dist/todos.d.ts +63 -0
  168. package/dist/todos.js +168 -0
  169. package/dist/todos.js.map +1 -0
  170. package/dist/ui-state.d.ts +12 -0
  171. package/dist/ui-state.js +25 -0
  172. package/dist/ui-state.js.map +1 -0
  173. package/dist/update-check.d.ts +12 -0
  174. package/dist/update-check.js +41 -0
  175. package/dist/update-check.js.map +1 -0
  176. package/dist/workflows/load.d.ts +15 -0
  177. package/dist/workflows/load.js +56 -0
  178. package/dist/workflows/load.js.map +1 -0
  179. package/dist/workflows/run.d.ts +281 -0
  180. package/dist/workflows/run.js +1511 -0
  181. package/dist/workflows/run.js.map +1 -0
  182. package/dist/workflows/types.d.ts +307 -0
  183. package/dist/workflows/types.js +171 -0
  184. package/dist/workflows/types.js.map +1 -0
  185. package/package.json +90 -0
  186. package/scripts/check-pack.mjs +46 -0
  187. package/scripts/dev.mjs +74 -0
  188. package/scripts/install-as-command.mjs +120 -0
  189. package/scripts/mock-claude.mjs +310 -0
  190. package/scripts/release-snapshot.mjs +130 -0
  191. package/scripts/release.mjs +119 -0
  192. package/scripts/test-process-usage.mjs +47 -0
  193. package/web/dist/assets/arrow-left-BE957rJs.js +1 -0
  194. package/web/dist/assets/bundle-mjs-DLPpRFyl.js +1 -0
  195. package/web/dist/assets/centered-state-BddhEEtO.js +43 -0
  196. package/web/dist/assets/chunk-BO2N2NFS-f5igTtpB.js +131 -0
  197. package/web/dist/assets/command-CjhFbABo.js +1 -0
  198. package/web/dist/assets/compare-variants-Cs52IAEG.js +1 -0
  199. package/web/dist/assets/core-BuMqAF_1.js +12 -0
  200. package/web/dist/assets/css-BsVw1vtW.js +1 -0
  201. package/web/dist/assets/dialog-DFvXTkFv.js +1 -0
  202. package/web/dist/assets/diff-view-C9b8AITq.js +4 -0
  203. package/web/dist/assets/diff-woXpYk--.js +1 -0
  204. package/web/dist/assets/dist-FBs4wmIY.js +1 -0
  205. package/web/dist/assets/dist-o_kVMXjg.js +1 -0
  206. package/web/dist/assets/engine-javascript-FQvzRocB.js +141 -0
  207. package/web/dist/assets/file-BVuztAOd.js +1 -0
  208. package/web/dist/assets/folder-0pJ1NZ_S.js +1 -0
  209. package/web/dist/assets/git-pull-request-DJkAMT0f.js +1 -0
  210. package/web/dist/assets/git-toolbar-CwhQdx3J.js +1 -0
  211. package/web/dist/assets/github-D0rAX4-r.js +1 -0
  212. package/web/dist/assets/go-rLFTqkRN.js +1 -0
  213. package/web/dist/assets/highlighted-body-OFNGDK62-DGHHie_q.js +1 -0
  214. package/web/dist/assets/highlighter-BKVEsACy.js +3 -0
  215. package/web/dist/assets/html-BY76lXLH.js +1 -0
  216. package/web/dist/assets/index-CEkI7QxN.css +2 -0
  217. package/web/dist/assets/index-CO2lH2et.js +11 -0
  218. package/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  219. package/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  220. package/web/dist/assets/javascript-BgS3c2Ky.js +1 -0
  221. package/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  222. package/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  223. package/web/dist/assets/json-qhed-kSA.js +1 -0
  224. package/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
  225. package/web/dist/assets/jsx-Bz0zcwM4.js +1 -0
  226. package/web/dist/assets/lib-CNGa3Dig.js +1 -0
  227. package/web/dist/assets/loader-circle-BV3DO9mE.js +1 -0
  228. package/web/dist/assets/markdown-BYOwaDjH.js +1 -0
  229. package/web/dist/assets/markdown-D4-ADgH9.js +1 -0
  230. package/web/dist/assets/mermaid-GHXKKRXX-DM2VsGBG.js +1 -0
  231. package/web/dist/assets/open-mercato-toBr6SOa.svg +11 -0
  232. package/web/dist/assets/prompt-templates-C7ptKvDd.js +15 -0
  233. package/web/dist/assets/python-gzcpVVnB.js +1 -0
  234. package/web/dist/assets/react-dom-Ddtik4qM.js +1 -0
  235. package/web/dist/assets/refresh-cw-DCa-Rlwz.js +1 -0
  236. package/web/dist/assets/repo-git-DIhryGDx.js +1 -0
  237. package/web/dist/assets/run-diff-Dyow8B1q.js +3 -0
  238. package/web/dist/assets/run-header-jx9-18b8.js +1 -0
  239. package/web/dist/assets/rust-Cfkwpbl8.js +1 -0
  240. package/web/dist/assets/search-x-CoCyl7zT.js +1 -0
  241. package/web/dist/assets/shellscript-CLZ0U2zV.js +1 -0
  242. package/web/dist/assets/skill-detail-DB7x_FQp.js +1 -0
  243. package/web/dist/assets/skills-98vCroU8.js +1 -0
  244. package/web/dist/assets/skills-BKIoqD6K.js +1 -0
  245. package/web/dist/assets/sql-BsFa4tDR.js +1 -0
  246. package/web/dist/assets/square-terminal-B6PZX4Qp.js +1 -0
  247. package/web/dist/assets/tab-link-C5--YMQd.js +1 -0
  248. package/web/dist/assets/task-changes-ejxPGVJw.js +1 -0
  249. package/web/dist/assets/task-commits-C6GO5qT-.js +1 -0
  250. package/web/dist/assets/task-files-CatpCBXa.js +2 -0
  251. package/web/dist/assets/task-thread-BMbXDM3d.js +5 -0
  252. package/web/dist/assets/tasks-table-dgezlCcg.js +1 -0
  253. package/web/dist/assets/trash-2-CDtxmmc8.js +1 -0
  254. package/web/dist/assets/triangle-alert-6su4Js5O.js +1 -0
  255. package/web/dist/assets/tsx-udAQXfEw.js +1 -0
  256. package/web/dist/assets/typescript-bsJCZSQ-.js +1 -0
  257. package/web/dist/assets/upload-Bp7hQxll.js +1 -0
  258. package/web/dist/assets/use-desktop-CvTwojOJ.js +3 -0
  259. package/web/dist/assets/utils-rQGbOrwc.js +1 -0
  260. package/web/dist/assets/workflows-Dy2c6790.js +11 -0
  261. package/web/dist/assets/x-Br_jIDBw.js +1 -0
  262. package/web/dist/assets/yaml-rwi0_p6S.js +1 -0
  263. package/web/dist/index.html +70 -0
  264. package/web/open-mercato.svg +11 -0
@@ -0,0 +1,416 @@
1
+ import { spawn as nodeSpawn } from 'node:child_process';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, resolve as resolvePath } from 'node:path';
4
+ import { costWeightedTokens } from './usage.js';
5
+ import { readNdjson } from './ndjson.js';
6
+ import { claudeTurnStarted, createClaudeUiState, mapClaudeMessage, stringifyToolResultContent, toolResultImageBlocks, } from './claude-ui-mapper.js';
7
+ /** Default wall-clock cap for a single run before SIGTERM → SIGKILL.
8
+ * Interactive sessions pass `timeoutMs: 0` to disable it entirely. */
9
+ export const DEFAULT_RUN_TIMEOUT_MS = 30 * 60_000;
10
+ /** Grace period between SIGTERM and SIGKILL when a timeout fires. */
11
+ export const KILL_GRACE_MS = 10_000;
12
+ /** After `end()` closes stdin: claude in stream-json mode can ignore EOF and
13
+ * hang (janitor-confirmed CLI bug) — escalate SIGTERM, then SIGKILL. */
14
+ export const EOF_TERM_GRACE_MS = 8_000;
15
+ export const EOF_KILL_GRACE_MS = 4_000;
16
+ /** Reopen window after a turn ends before an auto-ended session closes stdin. */
17
+ export const AUTO_END_DELAY_MS = 250;
18
+ /**
19
+ * `AgentRunner` over the Claude Code CLI in headless stream-json mode. Auth =
20
+ * the host's logged-in Pro/Max subscription (no API key needed). Sandboxing is
21
+ * `--allowedTools` (default-deny for anything not listed) + running inside the
22
+ * repo `cwd`; `Bash` is narrowed to `Bash(<prefix>:*)` patterns only when
23
+ * `bashAllowlist` is set — the zero-config default has no allowlist, so `Bash`
24
+ * is unrestricted shell access (#430).
25
+ *
26
+ * Session mechanics (multi-turn stdin, EOF watchdog, reopen window) follow
27
+ * github-janitor's `claudeRunner.ts`; the original single-turn adaptation
28
+ * came from @cezar/core's `ClaudeCodeCliRunner`.
29
+ */
30
+ export class ClaudeCliRunner {
31
+ backend = 'claude';
32
+ bin;
33
+ timeoutMs;
34
+ lastSession = null;
35
+ constructor(opts = {}) {
36
+ // CEZ_DRY_RUN=1 swaps in the bundled mock so the cockpit / store /
37
+ // GUI can be exercised without a logged-in claude or burning tokens.
38
+ const defaultBin = process.env.CEZ_CLAUDE_BIN ??
39
+ (process.env.CEZ_DRY_RUN === '1' ? mockClaudePath() : 'claude');
40
+ this.bin = opts.bin ?? defaultBin;
41
+ this.timeoutMs = opts.timeoutMs ?? DEFAULT_RUN_TIMEOUT_MS;
42
+ }
43
+ /** One-shot run: start a session and auto-end it after the first turn. */
44
+ run(spec, onEvent) {
45
+ return this.startSession(spec, onEvent, { autoEndAfterFirstTurn: true }).result;
46
+ }
47
+ async interrupt() {
48
+ this.lastSession?.interrupt();
49
+ }
50
+ startSession(spec, onEvent, opts = {}) {
51
+ const args = buildClaudeArgs(spec);
52
+ let child;
53
+ try {
54
+ child = nodeSpawn(this.bin, args, { cwd: spec.cwd, env: { ...process.env, ...spec.env } });
55
+ }
56
+ catch (err) {
57
+ throw wrapSpawnError(err, this.bin);
58
+ }
59
+ let stdinOpen = true;
60
+ let autoEndTimer;
61
+ let eofTermTimer;
62
+ let eofKillTimer;
63
+ // Protocol v2 emission — additive alongside v1 (`onEvent` keeps flowing
64
+ // byte-identical); the channel is `opts.onUiEvent` (RunManager wiring
65
+ // lands in R2 step 2.1). The mapper never throws, but a defect in it
66
+ // must still never disturb the v1 stream — hence the belt-and-braces try.
67
+ let uiState = createClaudeUiState({ fallbackSessionId: spec.sessionId });
68
+ const emitUi = (map) => {
69
+ try {
70
+ const mapped = map(uiState);
71
+ uiState = mapped.state;
72
+ if (opts.onUiEvent) {
73
+ for (const event of mapped.events)
74
+ opts.onUiEvent(event);
75
+ }
76
+ }
77
+ catch {
78
+ // v2 mapping is best-effort; v1 consumers stay unaffected.
79
+ }
80
+ };
81
+ const sendMessage = (content) => {
82
+ if (!stdinOpen)
83
+ return false;
84
+ // A follow-up inside the reopen window cancels the scheduled close.
85
+ if (autoEndTimer) {
86
+ clearTimeout(autoEndTimer);
87
+ autoEndTimer = undefined;
88
+ }
89
+ const line = JSON.stringify({
90
+ type: 'user',
91
+ message: { role: 'user', content },
92
+ session_id: spec.sessionId,
93
+ });
94
+ try {
95
+ child.stdin.write(`${line}\n`);
96
+ // Each user message written to stdin begins a turn (§7.1).
97
+ emitUi(claudeTurnStarted);
98
+ return true;
99
+ }
100
+ catch (err) {
101
+ const message = err instanceof Error ? err.message : String(err);
102
+ onEvent?.({ type: 'note', message: `claude: stdin write failed: ${message}` });
103
+ return false;
104
+ }
105
+ };
106
+ const end = () => {
107
+ if (!stdinOpen)
108
+ return;
109
+ stdinOpen = false;
110
+ try {
111
+ child.stdin.end();
112
+ }
113
+ catch {
114
+ // already gone
115
+ }
116
+ eofTermTimer = setTimeout(() => {
117
+ if (child.exitCode == null && !child.killed)
118
+ child.kill('SIGTERM');
119
+ eofKillTimer = setTimeout(() => {
120
+ if (child.exitCode == null && !child.killed)
121
+ child.kill('SIGKILL');
122
+ }, EOF_KILL_GRACE_MS);
123
+ eofKillTimer.unref?.();
124
+ }, EOF_TERM_GRACE_MS);
125
+ eofTermTimer.unref?.();
126
+ };
127
+ const interrupt = () => {
128
+ stdinOpen = false;
129
+ if (!child.killed)
130
+ child.kill('SIGTERM');
131
+ };
132
+ // Seed the first user message — the same path every follow-up takes.
133
+ // Pasted task screenshots (spec.images) ride along as leading blocks.
134
+ sendMessage([...(spec.images ?? []), { type: 'text', text: spec.userPrompt }]);
135
+ const toolCalls = [];
136
+ const textChunks = [];
137
+ let tokensUsed = 0;
138
+ let sawUsage = false;
139
+ let spawnFailed = null;
140
+ child.on('error', (err) => {
141
+ spawnFailed = wrapSpawnError(err, this.bin);
142
+ });
143
+ const stderrChunks = [];
144
+ child.stderr.setEncoding('utf8');
145
+ child.stderr.on('data', (chunk) => stderrChunks.push(chunk));
146
+ // Optional wall-clock kill switch (disabled for interactive sessions).
147
+ const limitMs = spec.timeoutMs ?? this.timeoutMs;
148
+ let timedOut = false;
149
+ let killTimer;
150
+ let deadline;
151
+ if (limitMs > 0) {
152
+ deadline = setTimeout(() => {
153
+ timedOut = true;
154
+ interrupt();
155
+ child.stdout.destroy();
156
+ killTimer = setTimeout(() => {
157
+ if (child.exitCode == null && !child.killed)
158
+ child.kill('SIGKILL');
159
+ }, KILL_GRACE_MS);
160
+ killTimer.unref?.();
161
+ }, limitMs);
162
+ deadline.unref?.();
163
+ }
164
+ const result = (async () => {
165
+ try {
166
+ for await (const line of readNdjson(child.stdout)) {
167
+ if (timedOut)
168
+ break;
169
+ let msg;
170
+ try {
171
+ msg = JSON.parse(line);
172
+ }
173
+ catch {
174
+ onEvent?.({ type: 'note', message: `claude: skipped unparseable stream line: ${truncate(line)}` });
175
+ continue;
176
+ }
177
+ emitUi((state) => mapClaudeMessage(msg, state));
178
+ let delta = 0;
179
+ try {
180
+ delta = handleClaudeMessage(msg, { toolCalls, textChunks, onEvent });
181
+ }
182
+ catch (err) {
183
+ const message = err instanceof Error ? err.message : String(err);
184
+ onEvent?.({ type: 'note', message: `claude: skipped malformed event (${msg.type ?? 'unknown'}): ${message}` });
185
+ continue;
186
+ }
187
+ if (delta > 0) {
188
+ sawUsage = true;
189
+ tokensUsed += delta;
190
+ onEvent?.({ type: 'token-usage', tokensUsed });
191
+ }
192
+ if (msg.type === 'result') {
193
+ if (typeof msg.total_cost_usd === 'number' && msg.total_cost_usd > 0) {
194
+ onEvent?.({ type: 'cost', usd: msg.total_cost_usd });
195
+ }
196
+ onEvent?.({ type: 'turn-end' });
197
+ if (opts.autoEndAfterFirstTurn && stdinOpen && !autoEndTimer) {
198
+ autoEndTimer = setTimeout(end, AUTO_END_DELAY_MS);
199
+ autoEndTimer.unref?.();
200
+ }
201
+ }
202
+ }
203
+ }
204
+ catch (err) {
205
+ // A timeout destroys stdout, which surfaces here as a premature-close
206
+ // error — expected; rethrow anything else.
207
+ if (!timedOut)
208
+ throw err;
209
+ }
210
+ finally {
211
+ if (deadline)
212
+ clearTimeout(deadline);
213
+ if (killTimer)
214
+ clearTimeout(killTimer);
215
+ if (autoEndTimer)
216
+ clearTimeout(autoEndTimer);
217
+ stdinOpen = false;
218
+ }
219
+ const exitCode = await waitForExit(child);
220
+ if (eofTermTimer)
221
+ clearTimeout(eofTermTimer);
222
+ if (eofKillTimer)
223
+ clearTimeout(eofKillTimer);
224
+ if (spawnFailed)
225
+ throw spawnFailed;
226
+ const text = textChunks.join('\n').trim();
227
+ if (timedOut) {
228
+ const mins = Math.round((limitMs / 60_000) * 10) / 10;
229
+ onEvent?.({ type: 'error', message: `claude CLI timed out after ${mins}m and was killed` });
230
+ onEvent?.({ type: 'done' });
231
+ return { text, toolCalls, tokensUsed, sessionId: spec.sessionId };
232
+ }
233
+ if (exitCode !== 0 && exitCode !== null) {
234
+ const stderr = stderrChunks.join('').trim();
235
+ const detail = stderr ? ` — ${stderr.split('\n').slice(-3).join(' | ')}` : '';
236
+ const msg = `claude CLI exited with code ${exitCode}${detail}`;
237
+ onEvent?.({ type: 'error', message: msg });
238
+ throw new Error(msg);
239
+ }
240
+ if (!sawUsage) {
241
+ onEvent?.({ type: 'note', message: 'token usage not reported by claude CLI' });
242
+ }
243
+ onEvent?.({ type: 'done' });
244
+ return { text, toolCalls, tokensUsed, sessionId: spec.sessionId };
245
+ })();
246
+ const session = {
247
+ result,
248
+ sendMessage,
249
+ end,
250
+ interrupt,
251
+ pid: child.pid,
252
+ get open() {
253
+ return stdinOpen;
254
+ },
255
+ };
256
+ this.lastSession = session;
257
+ return session;
258
+ }
259
+ }
260
+ /**
261
+ * Build the headless argv. `--input-format stream-json` reads user messages
262
+ * from stdin; `--output-format stream-json --verbose` gives per-event NDJSON;
263
+ * `--permission-mode dontAsk` keeps headless runs non-interactive: tools in
264
+ * `--allowedTools` proceed and everything else is denied instead of prompting.
265
+ * `CEZ_APPROVAL_GATE=1` opts back into Claude's approval UI (#435).
266
+ */
267
+ export function buildClaudeArgs(spec, env = process.env) {
268
+ const args = [
269
+ '--input-format',
270
+ 'stream-json',
271
+ '--output-format',
272
+ 'stream-json',
273
+ '--verbose',
274
+ '--permission-mode',
275
+ env.CEZ_APPROVAL_GATE === '1' ? 'acceptEdits' : 'dontAsk',
276
+ ];
277
+ if (spec.systemPrompt) {
278
+ args.push('--append-system-prompt', spec.systemPrompt);
279
+ }
280
+ // Pin the session so the user can `claude --resume <sessionId>` in the repo
281
+ // to take over interactively after a run. With `resume` we reopen the
282
+ // existing on-disk conversation instead.
283
+ if (spec.sessionId) {
284
+ if (spec.resume) {
285
+ args.push('--resume', spec.sessionId);
286
+ }
287
+ else {
288
+ args.push('--session-id', spec.sessionId);
289
+ }
290
+ }
291
+ const allowed = buildAllowedTools(spec.allowedTools ?? [], spec.bashAllowlist);
292
+ if (allowed.length > 0) {
293
+ args.push('--allowedTools', allowed.join(','));
294
+ }
295
+ if (spec.model) {
296
+ args.push('--model', spec.model);
297
+ }
298
+ for (const dir of spec.additionalDirectories ?? []) {
299
+ args.push('--add-dir', dir);
300
+ }
301
+ return args;
302
+ }
303
+ /**
304
+ * Map `allowedTools` onto claude's `--allowedTools` syntax. `Bash` with a
305
+ * `bashAllowlist` becomes one `Bash(<prefix>:*)` entry per allowed prefix;
306
+ * `Bash` with no allowlist stays plain `Bash`.
307
+ */
308
+ export function buildAllowedTools(allowedTools, bashAllowlist) {
309
+ const out = [];
310
+ for (const tool of allowedTools) {
311
+ if (tool === 'Bash' && bashAllowlist && bashAllowlist.length > 0) {
312
+ for (const prefix of bashAllowlist) {
313
+ const p = prefix.trim();
314
+ if (p)
315
+ out.push(`Bash(${p}:*)`);
316
+ }
317
+ }
318
+ else {
319
+ out.push(tool);
320
+ }
321
+ }
322
+ return out;
323
+ }
324
+ function truncate(s, max = 200) {
325
+ return s.length > max ? `${s.slice(0, max)}…` : s;
326
+ }
327
+ /** Path to the bundled mock (`scripts/mock-claude.mjs`), for CEZ_DRY_RUN=1. */
328
+ function mockClaudePath() {
329
+ const here = dirname(fileURLToPath(import.meta.url));
330
+ // here = <pkg>/dist/core (built) or <pkg>/src/core (tsx dev).
331
+ return resolvePath(here, '..', '..', 'scripts', 'mock-claude.mjs');
332
+ }
333
+ function handleClaudeMessage(msg, ctx) {
334
+ if (msg.type === 'assistant' && msg.message?.content) {
335
+ for (const block of msg.message.content) {
336
+ const b = block;
337
+ if (b.type === 'text' && typeof b.text === 'string') {
338
+ ctx.textChunks.push(b.text);
339
+ ctx.onEvent?.({ type: 'text', text: b.text });
340
+ }
341
+ else if (b.type === 'tool_use' && b.id && b.name) {
342
+ ctx.toolCalls.push({ id: b.id, name: b.name, input: b.input });
343
+ ctx.onEvent?.({ type: 'tool-call', id: b.id, tool: b.name, input: b.input });
344
+ }
345
+ }
346
+ return costWeightedTokens(msg.message.usage);
347
+ }
348
+ if (msg.type === 'user' && msg.message?.content) {
349
+ for (const block of msg.message.content) {
350
+ const b = block;
351
+ if (b.type === 'tool_result' && typeof b.tool_use_id === 'string') {
352
+ ctx.onEvent?.({
353
+ type: 'tool-result',
354
+ toolCallId: b.tool_use_id,
355
+ result: stringifyToolResultContent(b.content),
356
+ isError: b.is_error === true,
357
+ });
358
+ // Screenshots and other images inside the result get their own
359
+ // events — the text path above renders them as a placeholder.
360
+ for (const img of toolResultImageBlocks(b.content)) {
361
+ ctx.onEvent?.({ type: 'image', mediaType: img.media_type, data: img.data });
362
+ }
363
+ }
364
+ }
365
+ return 0;
366
+ }
367
+ if (msg.type === 'result') {
368
+ // Final message of a turn: `result` is the full assistant text; only fall
369
+ // back to it if we never saw streamed assistant text blocks.
370
+ if (typeof msg.result === 'string' && ctx.textChunks.length === 0) {
371
+ ctx.textChunks.push(msg.result);
372
+ ctx.onEvent?.({ type: 'text', text: msg.result });
373
+ }
374
+ if (msg.is_error) {
375
+ ctx.onEvent?.({
376
+ type: 'note',
377
+ message: `claude reported result error${msg.subtype ? ` (${msg.subtype})` : ''}`,
378
+ });
379
+ }
380
+ return costWeightedTokens(msg.usage);
381
+ }
382
+ // system/init and anything else: nothing actionable.
383
+ return 0;
384
+ }
385
+ // stringify/image helpers moved to claude-ui-mapper.ts (shared by v1 and v2).
386
+ // ---- subprocess plumbing --------------------------------------------------
387
+ function waitForExit(child) {
388
+ if (child.exitCode != null)
389
+ return Promise.resolve(child.exitCode);
390
+ return new Promise((resolve) => {
391
+ let done = false;
392
+ const fin = (code) => {
393
+ if (done)
394
+ return;
395
+ done = true;
396
+ clearTimeout(safety);
397
+ resolve(code);
398
+ };
399
+ child.once('close', (code) => fin(code));
400
+ child.once('exit', (code) => fin(code));
401
+ // Don't swallow a late error as a clean null exit — fall back to the
402
+ // child's own exit code (which is non-null/non-zero on failure).
403
+ child.once('error', () => fin(child.exitCode ?? null));
404
+ // A SIGKILLed process may never emit 'close' through some edge cases.
405
+ const safety = setTimeout(() => fin(child.exitCode ?? null), EOF_TERM_GRACE_MS + EOF_KILL_GRACE_MS + KILL_GRACE_MS + 5_000);
406
+ safety.unref?.();
407
+ });
408
+ }
409
+ function wrapSpawnError(err, bin) {
410
+ const code = err?.code;
411
+ if (code === 'ENOENT') {
412
+ return new Error(`\`${bin}\` not found on PATH — install Claude Code (https://claude.com/claude-code) and run \`claude\` once to log in`);
413
+ }
414
+ return err instanceof Error ? err : new Error(String(err));
415
+ }
416
+ //# sourceMappingURL=claude-cli-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-cli-runner.js","sourceRoot":"","sources":["../../src/core/claude-cli-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Pure claude stream-json → protocol-v2 mapper. `mapClaudeMessage` folds one
3
+ * parsed NDJSON stdout line into `UiEvent`s plus the next mapper state; the
4
+ * runner calls it ALONGSIDE the v1 path (v1 events keep flowing unchanged).
5
+ *
6
+ * Contract: `.ai/analysis/cockpit-ui-redesign/agent-event-protocols.md` §1
7
+ * (wire format) and §7.1 "Claude (stream-json)" (the mapping). Golden
8
+ * fixtures replaying real wire shapes live in `__fixtures__/claude/`.
9
+ *
10
+ * Robustness rule: input is untrusted wire data — the mapper never throws;
11
+ * unknown message/block types map to zero events.
12
+ *
13
+ * State is explicit and treated as immutable: callers thread the returned
14
+ * `state` into the next call. Item ids are deterministic — tool items reuse
15
+ * the wire `tool_use` id; text/thinking blocks (which have no wire id) get
16
+ * sequential `item_<n>` ids, turns get `turn_<n>` — so replaying a stored
17
+ * transcript reproduces the exact event sequence.
18
+ *
19
+ * Plan/task rule: task ids are the harness's, and it only ever reports them in
20
+ * tool RESULT text (`Task #3 created successfully: …`, `#3 [pending] …`), never
21
+ * in the call. So a `TaskCreate` parks until its result lands. Inferring ids by
22
+ * counting creates looks equivalent and is not: `--resume` reopens a session
23
+ * whose list is already at 1..N while a fresh mapper state starts at zero, and
24
+ * the two id spaces then drift silently — updates land on the wrong row.
25
+ */
26
+ import type { PlanEntry, UiEvent, UiToolItem } from './ui-events.js';
27
+ export interface ClaudeUiMapperState {
28
+ /** Used when `system/init` lacks `session_id` (the dry-run mock does). */
29
+ readonly fallbackSessionId?: string;
30
+ /** True once `system/init` produced `session.started`. */
31
+ readonly sessionStarted: boolean;
32
+ /** Turns begun before init arrived — their `turn.started` is queued so
33
+ * `session.started` stays the first event on the wire. */
34
+ readonly pendingTurnIds: readonly string[];
35
+ readonly turnSeq: number;
36
+ readonly currentTurnId: string | null;
37
+ readonly itemSeq: number;
38
+ /** `tool_use` items awaiting their `tool_result`, keyed by tool_use id. */
39
+ readonly openTools: ReadonlyMap<string, UiToolItem>;
40
+ /** The running plan built incrementally by Claude's task tools, keyed by the
41
+ * task id the harness assigned — read from the `TaskCreate` result, never
42
+ * guessed (see `applyTaskCreateResult`). */
43
+ readonly tasks: ReadonlyMap<string, PlanEntry>;
44
+ /** `TaskCreate` calls whose result has not arrived yet, keyed by tool_use id.
45
+ * The entry parks here until the result reveals its real id. */
46
+ readonly pendingTaskCreates: ReadonlyMap<string, PlanEntry>;
47
+ }
48
+ export interface ClaudeUiMapping {
49
+ events: UiEvent[];
50
+ state: ClaudeUiMapperState;
51
+ }
52
+ export declare function createClaudeUiState(opts?: {
53
+ fallbackSessionId?: string;
54
+ }): ClaudeUiMapperState;
55
+ /**
56
+ * Claude has no wire-level turn-start — the runner writing a user message to
57
+ * stdin IS the turn boundary, so the runner calls this on each send. Until
58
+ * `init` arrives the event is queued (the seed message is written before the
59
+ * first stdout line is read).
60
+ */
61
+ export declare function claudeTurnStarted(state: ClaudeUiMapperState): ClaudeUiMapping;
62
+ /** Fold one parsed stream-json message into v2 events. Never throws. */
63
+ export declare function mapClaudeMessage(msg: unknown, state: ClaudeUiMapperState): ClaudeUiMapping;
64
+ /** Flatten a `tool_result.content` (string or block array) to display text.
65
+ * Image blocks become a placeholder — they ride as their own events. */
66
+ export declare function stringifyToolResultContent(content: unknown): string;
67
+ /** base64 image blocks inside a tool_result's content, if any. */
68
+ export declare function toolResultImageBlocks(content: unknown): Array<{
69
+ media_type: string;
70
+ data: string;
71
+ }>;