cloving 1.1.0 → 1.3.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 (568) hide show
  1. package/README.md +584 -144
  2. package/assets/watch-fonts/fira-code-OFL.md +93 -0
  3. package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
  4. package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
  5. package/assets/watch-fonts/heebo-OFL.md +93 -0
  6. package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
  7. package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
  8. package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
  9. package/assets/watch-fonts/manifest.json +112 -0
  10. package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
  11. package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  12. package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  13. package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
  14. package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  15. package/dist/src/agent-harness-shell.d.ts +12 -0
  16. package/dist/src/agent-harness-shell.js +90 -0
  17. package/dist/src/agent-harness-versions.d.ts +8 -0
  18. package/dist/src/agent-harness-versions.js +49 -0
  19. package/dist/src/agent-harnesses.d.ts +4 -0
  20. package/dist/src/agent-harnesses.js +13 -0
  21. package/dist/src/authority/commands.d.ts +2 -0
  22. package/dist/src/authority/commands.js +49 -8
  23. package/dist/src/authority/dispatch-decision.d.ts +1 -0
  24. package/dist/src/authority/dispatch-decision.js +7 -4
  25. package/dist/src/authority/events.js +2 -2
  26. package/dist/src/authority/gate-reduction.d.ts +1 -0
  27. package/dist/src/authority/gate-reduction.js +18 -3
  28. package/dist/src/authority/gates.d.ts +2 -1
  29. package/dist/src/authority/gates.js +5 -1
  30. package/dist/src/authority/handoff-chain.d.ts +24 -0
  31. package/dist/src/authority/handoff-chain.js +46 -0
  32. package/dist/src/authority/operations.js +1 -1
  33. package/dist/src/authority/reconciliation.d.ts +1 -0
  34. package/dist/src/authority/reconciliation.js +18 -11
  35. package/dist/src/authority/reduction.d.ts +1 -1
  36. package/dist/src/authority/reduction.js +6 -1
  37. package/dist/src/authority/status-input.d.ts +1 -1
  38. package/dist/src/authority/status.d.ts +1 -0
  39. package/dist/src/authority/status.js +27 -3
  40. package/dist/src/authority/transitions.d.ts +5 -5
  41. package/dist/src/authority/transitions.js +9 -0
  42. package/dist/src/broker/actor/authority-delivery.js +1 -0
  43. package/dist/src/broker/actor/authority-queries.d.ts +11 -1
  44. package/dist/src/broker/actor/authority-queries.js +67 -3
  45. package/dist/src/broker/actor/authority-receipts.js +11 -1
  46. package/dist/src/broker/actor/authority-session.js +2 -2
  47. package/dist/src/broker/actor/authority-settings.js +4 -0
  48. package/dist/src/broker/actor/delivery-intents.d.ts +3 -1
  49. package/dist/src/broker/actor/delivery-intents.js +4 -4
  50. package/dist/src/broker/actor/effect-delivery.js +13 -1
  51. package/dist/src/broker/actor/effect-queries.d.ts +1 -0
  52. package/dist/src/broker/actor/effect-queries.js +7 -0
  53. package/dist/src/broker/actor/pin-check.js +1 -1
  54. package/dist/src/broker/actor/stop-plan.js +1 -1
  55. package/dist/src/broker/actor/turn-state.js +1 -1
  56. package/dist/src/broker/authority-admission.js +26 -5
  57. package/dist/src/broker/authority-restore.js +1 -0
  58. package/dist/src/broker/decision-restore.js +4 -4
  59. package/dist/src/broker/socket-address.d.ts +3 -1
  60. package/dist/src/broker/socket-address.js +2 -2
  61. package/dist/src/cli/arguments.d.ts +11 -13
  62. package/dist/src/cli/arguments.js +37 -107
  63. package/dist/src/cli/command-effects.d.ts +7 -0
  64. package/dist/src/cli/command-effects.js +39 -0
  65. package/dist/src/cli/commands.js +11 -4
  66. package/dist/src/cli/config-arguments.d.ts +11 -0
  67. package/dist/src/cli/config-arguments.js +59 -0
  68. package/dist/src/cli/config-command.d.ts +2 -0
  69. package/dist/src/cli/config-command.js +105 -0
  70. package/dist/src/cli/config-file.d.ts +3 -0
  71. package/dist/src/cli/config-file.js +50 -0
  72. package/dist/src/cli/config-lock.d.ts +7 -0
  73. package/dist/src/cli/config-lock.js +61 -0
  74. package/dist/src/cli/config-notice.d.ts +5 -0
  75. package/dist/src/cli/config-notice.js +46 -0
  76. package/dist/src/cli/doctor-github.d.ts +9 -0
  77. package/dist/src/cli/doctor-github.js +138 -0
  78. package/dist/src/cli/doctor-harness.d.ts +13 -0
  79. package/dist/src/cli/doctor-harness.js +242 -0
  80. package/dist/src/cli/doctor-local.d.ts +18 -0
  81. package/dist/src/cli/doctor-local.js +77 -0
  82. package/dist/src/cli/doctor-runtime.d.ts +15 -0
  83. package/dist/src/cli/doctor-runtime.js +176 -0
  84. package/dist/src/cli/doctor-service.d.ts +1 -0
  85. package/dist/src/cli/doctor-service.js +11 -0
  86. package/dist/src/cli/doctor-workflows.d.ts +3 -0
  87. package/dist/src/cli/doctor-workflows.js +45 -0
  88. package/dist/src/cli/doctor.d.ts +15 -0
  89. package/dist/src/cli/doctor.js +190 -0
  90. package/dist/src/cli/github-ci-progress.d.ts +8 -0
  91. package/dist/src/cli/github-ci-progress.js +83 -0
  92. package/dist/src/cli/github-retry.d.ts +6 -0
  93. package/dist/src/cli/github-retry.js +47 -0
  94. package/dist/src/cli/harness-probes.d.ts +22 -0
  95. package/dist/src/cli/harness-probes.js +183 -0
  96. package/dist/src/cli/main.d.ts +7 -1
  97. package/dist/src/cli/main.js +39 -61
  98. package/dist/src/cli/phone-arguments.d.ts +14 -0
  99. package/dist/src/cli/phone-arguments.js +37 -0
  100. package/dist/src/cli/phone-client.d.ts +2 -0
  101. package/dist/src/cli/phone-client.js +32 -0
  102. package/dist/src/cli/phone-command.d.ts +13 -0
  103. package/dist/src/cli/phone-command.js +101 -0
  104. package/dist/src/cli/probe-command.d.ts +36 -0
  105. package/dist/src/cli/probe-command.js +59 -0
  106. package/dist/src/cli/project-settings.d.ts +4 -0
  107. package/dist/src/cli/project-settings.js +33 -0
  108. package/dist/src/cli/render.d.ts +3 -1
  109. package/dist/src/cli/render.js +102 -39
  110. package/dist/src/cli/report-github.d.ts +18 -0
  111. package/dist/src/cli/report-github.js +200 -0
  112. package/dist/src/cli/report.d.ts +17 -0
  113. package/dist/src/cli/report.js +192 -0
  114. package/dist/src/cli/repository-arguments.d.ts +5 -0
  115. package/dist/src/cli/repository-arguments.js +34 -0
  116. package/dist/src/cli/runtime-arguments.d.ts +4 -0
  117. package/dist/src/cli/runtime-arguments.js +15 -0
  118. package/dist/src/cli/runtime-directory.d.ts +6 -2
  119. package/dist/src/cli/runtime-directory.js +72 -14
  120. package/dist/src/cli/toolchain.d.ts +2 -0
  121. package/dist/src/cli/toolchain.js +22 -2
  122. package/dist/src/cli/usage-render.d.ts +5 -0
  123. package/dist/src/cli/usage-render.js +40 -1
  124. package/dist/src/cli/usage.d.ts +3 -3
  125. package/dist/src/cli/usage.js +74 -45
  126. package/dist/src/cli/watch-actions.d.ts +2 -0
  127. package/dist/src/cli/watch-actions.js +4 -4
  128. package/dist/src/cli/watch-board-view.d.ts +12 -1
  129. package/dist/src/cli/watch-board-view.js +64 -12
  130. package/dist/src/cli/watch-board.d.ts +7 -1
  131. package/dist/src/cli/watch-board.js +61 -16
  132. package/dist/src/cli/watch-card-forms.js +2 -2
  133. package/dist/src/cli/watch-client.d.ts +1 -1
  134. package/dist/src/cli/watch-client.js +12 -3
  135. package/dist/src/cli/watch-header-view.d.ts +27 -0
  136. package/dist/src/cli/watch-header-view.js +116 -0
  137. package/dist/src/cli/watch-model.d.ts +10 -4
  138. package/dist/src/cli/watch-model.js +49 -59
  139. package/dist/src/cli/watch-page.js +67 -14
  140. package/dist/src/cli/watch-phases.js +3 -3
  141. package/dist/src/cli/watch-phone-client.d.ts +1 -0
  142. package/dist/src/cli/watch-phone-client.js +84 -0
  143. package/dist/src/cli/watch-phone-view.d.ts +56 -0
  144. package/dist/src/cli/watch-phone-view.js +113 -0
  145. package/dist/src/cli/watch-phone.d.ts +5 -0
  146. package/dist/src/cli/watch-phone.js +53 -0
  147. package/dist/src/cli/watch-pr-command.d.ts +5 -2
  148. package/dist/src/cli/watch-pr-command.js +41 -4
  149. package/dist/src/cli/watch-pr-identity.d.ts +14 -2
  150. package/dist/src/cli/watch-pr-identity.js +25 -0
  151. package/dist/src/cli/watch-pr-observer.d.ts +1 -0
  152. package/dist/src/cli/watch-pr-observer.js +48 -6
  153. package/dist/src/cli/watch-pull-request.d.ts +12 -0
  154. package/dist/src/cli/watch-pull-request.js +134 -0
  155. package/dist/src/cli/watch-reads.d.ts +7 -1
  156. package/dist/src/cli/watch-reads.js +42 -20
  157. package/dist/src/cli/watch-render.d.ts +23 -2
  158. package/dist/src/cli/watch-render.js +2 -1
  159. package/dist/src/cli/watch-server.js +56 -7
  160. package/dist/src/cli/watch-turn.d.ts +4 -1
  161. package/dist/src/cli/watch-turn.js +38 -2
  162. package/dist/src/cli/watch-usage.js +5 -1
  163. package/dist/src/cli/watch-view.d.ts +10 -17
  164. package/dist/src/cli/watch-view.js +33 -77
  165. package/dist/src/cli.js +106 -23
  166. package/dist/src/command-settings.d.ts +16 -0
  167. package/dist/src/command-settings.js +42 -0
  168. package/dist/src/configuration-change.d.ts +11 -0
  169. package/dist/src/configuration-change.js +62 -0
  170. package/dist/src/configuration-display.d.ts +21 -0
  171. package/dist/src/configuration-display.js +69 -0
  172. package/dist/src/configuration-schema.d.ts +49 -0
  173. package/dist/src/configuration-schema.js +159 -0
  174. package/dist/src/daemon/claude-turn.d.ts +20 -5
  175. package/dist/src/daemon/claude-turn.js +116 -53
  176. package/dist/src/daemon/claude-worker.d.ts +3 -5
  177. package/dist/src/daemon/claude-worker.js +64 -80
  178. package/dist/src/daemon/command-journal.d.ts +5 -0
  179. package/dist/src/daemon/command-journal.js +50 -0
  180. package/dist/src/daemon/command-process.d.ts +28 -0
  181. package/dist/src/daemon/command-process.js +164 -0
  182. package/dist/src/daemon/command-worker.d.ts +19 -0
  183. package/dist/src/daemon/command-worker.js +182 -0
  184. package/dist/src/daemon/cursor-stream.d.ts +4 -0
  185. package/dist/src/daemon/cursor-stream.js +154 -0
  186. package/dist/src/daemon/daemon-adapters.d.ts +58 -0
  187. package/dist/src/daemon/daemon-adapters.js +102 -0
  188. package/dist/src/daemon/daemon-loops.d.ts +14 -0
  189. package/dist/src/daemon/daemon-loops.js +39 -0
  190. package/dist/src/daemon/daemon.d.ts +3 -30
  191. package/dist/src/daemon/daemon.js +132 -110
  192. package/dist/src/daemon/declared-input.d.ts +3 -0
  193. package/dist/src/daemon/declared-input.js +9 -0
  194. package/dist/src/daemon/delivery-router.js +7 -1
  195. package/dist/src/daemon/gemini-stream.d.ts +4 -0
  196. package/dist/src/daemon/gemini-stream.js +129 -0
  197. package/dist/src/daemon/github-calls.d.ts +4 -0
  198. package/dist/src/daemon/github-calls.js +16 -7
  199. package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
  200. package/dist/src/daemon/github-ci-rerun.js +92 -0
  201. package/dist/src/daemon/github-ci.d.ts +6 -0
  202. package/dist/src/daemon/github-ci.js +251 -0
  203. package/dist/src/daemon/github-merge-call.d.ts +16 -0
  204. package/dist/src/daemon/github-merge-call.js +73 -0
  205. package/dist/src/daemon/github-merge.d.ts +3 -5
  206. package/dist/src/daemon/github-merge.js +59 -98
  207. package/dist/src/daemon/github-methods.d.ts +28 -0
  208. package/dist/src/daemon/github-methods.js +90 -16
  209. package/dist/src/daemon/github-operation.d.ts +3 -0
  210. package/dist/src/daemon/github-retry.d.ts +6 -0
  211. package/dist/src/daemon/github-retry.js +13 -0
  212. package/dist/src/daemon/github-ticket-status.js +27 -1
  213. package/dist/src/daemon/github-worker.js +2 -1
  214. package/dist/src/daemon/handoff-worker.d.ts +10 -0
  215. package/dist/src/daemon/handoff-worker.js +232 -0
  216. package/dist/src/daemon/issue-queue.d.ts +2 -0
  217. package/dist/src/daemon/issue-queue.js +92 -63
  218. package/dist/src/daemon/notify-journal.d.ts +18 -0
  219. package/dist/src/daemon/notify-journal.js +108 -0
  220. package/dist/src/daemon/notify-message.js +2 -1
  221. package/dist/src/daemon/notify.js +177 -37
  222. package/dist/src/daemon/opencode-stream.d.ts +5 -0
  223. package/dist/src/daemon/opencode-stream.js +87 -0
  224. package/dist/src/daemon/queue-status.d.ts +4 -0
  225. package/dist/src/daemon/queue-status.js +38 -0
  226. package/dist/src/daemon/retry-worktree.d.ts +18 -0
  227. package/dist/src/daemon/retry-worktree.js +139 -0
  228. package/dist/src/daemon/retrying-turn.d.ts +5 -0
  229. package/dist/src/daemon/retrying-turn.js +145 -21
  230. package/dist/src/daemon/schedule-journal.d.ts +19 -0
  231. package/dist/src/daemon/schedule-journal.js +57 -0
  232. package/dist/src/daemon/text-output.d.ts +18 -0
  233. package/dist/src/daemon/text-output.js +44 -0
  234. package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
  235. package/dist/src/daemon/ticket-dependency-waits.js +60 -0
  236. package/dist/src/daemon/ticket-registration.d.ts +10 -8
  237. package/dist/src/daemon/ticket-registration.js +146 -47
  238. package/dist/src/daemon/ticket-source.d.ts +4 -1
  239. package/dist/src/daemon/ticket-source.js +8 -2
  240. package/dist/src/daemon/turn-command.d.ts +10 -0
  241. package/dist/src/daemon/turn-command.js +33 -0
  242. package/dist/src/daemon/turn-report.d.ts +18 -0
  243. package/dist/src/daemon/turn-report.js +79 -0
  244. package/dist/src/daemon/work-tree.d.ts +2 -1
  245. package/dist/src/daemon/work-tree.js +15 -12
  246. package/dist/src/daemon/workflow-generations.d.ts +32 -0
  247. package/dist/src/daemon/workflow-generations.js +57 -0
  248. package/dist/src/daemon/workflow-replay.d.ts +16 -0
  249. package/dist/src/daemon/workflow-replay.js +58 -0
  250. package/dist/src/daemon/workflow-schedules.d.ts +27 -0
  251. package/dist/src/daemon/workflow-schedules.js +185 -0
  252. package/dist/src/decision-visibility.d.ts +2 -0
  253. package/dist/src/decision-visibility.js +10 -0
  254. package/dist/src/decision-wait.d.ts +1 -0
  255. package/dist/src/decision-wait.js +3 -0
  256. package/dist/src/delivery-backoff.d.ts +1 -0
  257. package/dist/src/delivery-backoff.js +3 -0
  258. package/dist/src/doctor-report.d.ts +24 -0
  259. package/dist/src/doctor-report.js +70 -0
  260. package/dist/src/execution-pin.d.ts +9 -0
  261. package/dist/src/execution-pin.js +86 -2
  262. package/dist/src/grok-result.d.ts +12 -0
  263. package/dist/src/grok-result.js +61 -0
  264. package/dist/src/harness-defaults.d.ts +35 -0
  265. package/dist/src/harness-defaults.js +121 -0
  266. package/dist/src/host/decision-resume.d.ts +35 -0
  267. package/dist/src/host/decision-resume.js +86 -0
  268. package/dist/src/host/gate-bridge.d.ts +48 -0
  269. package/dist/src/host/gate-bridge.js +124 -0
  270. package/dist/src/host/run-wait.d.ts +26 -0
  271. package/dist/src/host/run-wait.js +37 -0
  272. package/dist/src/host/start-delivery.d.ts +3 -2
  273. package/dist/src/host/start-delivery.js +11 -4
  274. package/dist/src/host/step-bridge-host.d.ts +6 -19
  275. package/dist/src/host/step-bridge-host.js +57 -55
  276. package/dist/src/host/world-reconciliation.d.ts +1 -0
  277. package/dist/src/host/world-reconciliation.js +3 -0
  278. package/dist/src/host/world-runs.js +5 -0
  279. package/dist/src/issue-identity.d.ts +6 -0
  280. package/dist/src/issue-identity.js +23 -0
  281. package/dist/src/merge-request.d.ts +19 -0
  282. package/dist/src/merge-request.js +32 -0
  283. package/dist/src/phone/canonical-json.d.ts +1 -0
  284. package/dist/src/phone/canonical-json.js +16 -0
  285. package/dist/src/phone/phone-link.d.ts +7 -0
  286. package/dist/src/phone/phone-link.js +21 -0
  287. package/dist/src/phone/qr-data.d.ts +8 -0
  288. package/dist/src/phone/qr-data.js +133 -0
  289. package/dist/src/phone/qr-matrix.d.ts +6 -0
  290. package/dist/src/phone/qr-matrix.js +175 -0
  291. package/dist/src/phone/qr-penalty.d.ts +3 -0
  292. package/dist/src/phone/qr-penalty.js +67 -0
  293. package/dist/src/phone/qr-picture.d.ts +5 -0
  294. package/dist/src/phone/qr-picture.js +24 -0
  295. package/dist/src/private-config.schema.json +263 -0
  296. package/dist/src/project-config.schema.json +65 -0
  297. package/dist/src/project-settings.d.ts +19 -0
  298. package/dist/src/project-settings.js +131 -0
  299. package/dist/src/relay/answer-check.d.ts +24 -0
  300. package/dist/src/relay/answer-check.js +145 -0
  301. package/dist/src/relay/answer-inbox.d.ts +15 -0
  302. package/dist/src/relay/answer-inbox.js +173 -0
  303. package/dist/src/relay/daemon-keys.d.ts +16 -0
  304. package/dist/src/relay/daemon-keys.js +75 -0
  305. package/dist/src/relay/decision-check.d.ts +3 -0
  306. package/dist/src/relay/decision-check.js +77 -0
  307. package/dist/src/relay/decision-close.d.ts +6 -0
  308. package/dist/src/relay/decision-close.js +72 -0
  309. package/dist/src/relay/decision-envelopes.d.ts +29 -0
  310. package/dist/src/relay/decision-envelopes.js +93 -0
  311. package/dist/src/relay/decision-watch.d.ts +14 -0
  312. package/dist/src/relay/decision-watch.js +68 -0
  313. package/dist/src/relay/envelope-post.d.ts +8 -0
  314. package/dist/src/relay/envelope-post.js +71 -0
  315. package/dist/src/relay/envelope.d.ts +28 -0
  316. package/dist/src/relay/envelope.js +53 -0
  317. package/dist/src/relay/hpke.d.ts +25 -0
  318. package/dist/src/relay/hpke.js +108 -0
  319. package/dist/src/relay/pairing-checks.d.ts +42 -0
  320. package/dist/src/relay/pairing-checks.js +172 -0
  321. package/dist/src/relay/pairing-follow.d.ts +8 -0
  322. package/dist/src/relay/pairing-follow.js +95 -0
  323. package/dist/src/relay/pairing-session.d.ts +29 -0
  324. package/dist/src/relay/pairing-session.js +87 -0
  325. package/dist/src/relay/phone-delivery.d.ts +51 -0
  326. package/dist/src/relay/phone-delivery.js +139 -0
  327. package/dist/src/relay/phone-devices.d.ts +36 -0
  328. package/dist/src/relay/phone-devices.js +46 -0
  329. package/dist/src/relay/phone-inbox.d.ts +18 -0
  330. package/dist/src/relay/phone-inbox.js +17 -0
  331. package/dist/src/relay/phone-operations.d.ts +18 -0
  332. package/dist/src/relay/phone-operations.js +121 -0
  333. package/dist/src/relay/phone-outbox.d.ts +21 -0
  334. package/dist/src/relay/phone-outbox.js +25 -0
  335. package/dist/src/relay/phone-socket.d.ts +6 -0
  336. package/dist/src/relay/phone-socket.js +63 -0
  337. package/dist/src/relay/relay-control.d.ts +7 -0
  338. package/dist/src/relay/relay-control.js +24 -0
  339. package/dist/src/relay/relay-files.d.ts +2 -0
  340. package/dist/src/relay/relay-files.js +23 -0
  341. package/dist/src/relay/relay-heartbeat.d.ts +17 -0
  342. package/dist/src/relay/relay-heartbeat.js +81 -0
  343. package/dist/src/relay/relay-http.d.ts +14 -0
  344. package/dist/src/relay/relay-http.js +63 -0
  345. package/dist/src/relay/relay-registration.d.ts +15 -0
  346. package/dist/src/relay/relay-registration.js +63 -0
  347. package/dist/src/relay/relay-service.d.ts +25 -0
  348. package/dist/src/relay/relay-service.js +216 -0
  349. package/dist/src/relay/relay-store.d.ts +48 -0
  350. package/dist/src/relay/relay-store.js +131 -0
  351. package/dist/src/relay/sealed-post.d.ts +25 -0
  352. package/dist/src/relay/sealed-post.js +52 -0
  353. package/dist/src/relay.d.ts +1 -0
  354. package/dist/src/relay.js +8 -0
  355. package/dist/src/report-statistics.d.ts +50 -0
  356. package/dist/src/report-statistics.js +70 -0
  357. package/dist/src/report.d.ts +171 -0
  358. package/dist/src/report.js +119 -0
  359. package/dist/src/repository-identity.d.ts +4 -0
  360. package/dist/src/repository-identity.js +4 -0
  361. package/dist/src/review-subject.d.ts +41 -0
  362. package/dist/src/review-subject.js +91 -0
  363. package/dist/src/run-wait.d.ts +23 -0
  364. package/dist/src/run-wait.js +20 -0
  365. package/dist/src/service/active-tickets.d.ts +4 -0
  366. package/dist/src/service/active-tickets.js +49 -0
  367. package/dist/src/service/command-effects.d.ts +4 -0
  368. package/dist/src/service/command-effects.js +16 -0
  369. package/dist/src/service/decision-handler.d.ts +4 -0
  370. package/dist/src/service/decision-handler.js +39 -4
  371. package/dist/src/service/gateway.js +18 -3
  372. package/dist/src/service/queue-runs.d.ts +3 -0
  373. package/dist/src/service/queue-runs.js +39 -0
  374. package/dist/src/service/registry.d.ts +22 -3
  375. package/dist/src/service/registry.js +51 -8
  376. package/dist/src/service/replies.d.ts +10 -0
  377. package/dist/src/service/replies.js +12 -0
  378. package/dist/src/service/run-handlers.js +45 -54
  379. package/dist/src/service/run-metadata.d.ts +8 -0
  380. package/dist/src/service/run-metadata.js +53 -0
  381. package/dist/src/service/run-waits.d.ts +3 -0
  382. package/dist/src/service/run-waits.js +41 -0
  383. package/dist/src/service/service.d.ts +21 -2
  384. package/dist/src/service/service.js +23 -5
  385. package/dist/src/service/submission-handler.js +70 -19
  386. package/dist/src/service/worker-port.d.ts +1 -0
  387. package/dist/src/service/worker-totals.js +10 -1
  388. package/dist/src/step-bridge.d.ts +32 -0
  389. package/dist/src/steps/decision-gate.d.ts +2 -1
  390. package/dist/src/steps/decision-gate.js +7 -0
  391. package/dist/src/steps/handoff.d.ts +2 -0
  392. package/dist/src/steps/handoff.js +13 -0
  393. package/dist/src/steps/merge-by-person.d.ts +2 -0
  394. package/dist/src/steps/merge-by-person.js +18 -0
  395. package/dist/src/steps/merge-when-green.d.ts +2 -0
  396. package/dist/src/steps/merge-when-green.js +62 -0
  397. package/dist/src/steps/review-by-agent.d.ts +5 -0
  398. package/dist/src/steps/review-by-agent.js +124 -0
  399. package/dist/src/steps/review-by-person.d.ts +4 -0
  400. package/dist/src/steps/review-by-person.js +16 -0
  401. package/dist/src/steps/review-subject.d.ts +2 -0
  402. package/dist/src/steps/review-subject.js +11 -0
  403. package/dist/src/steps/run-command.d.ts +2 -0
  404. package/dist/src/steps/run-command.js +15 -0
  405. package/dist/src/steps/sleep.d.ts +3 -0
  406. package/dist/src/steps/sleep.js +19 -0
  407. package/dist/src/steps/wait-for-decision.d.ts +2 -0
  408. package/dist/src/steps/wait-for-decision.js +71 -0
  409. package/dist/src/steps/wait-for-run.d.ts +5 -0
  410. package/dist/src/steps/wait-for-run.js +9 -0
  411. package/dist/src/storage/decision-snapshots.d.ts +1 -0
  412. package/dist/src/storage/decision-snapshots.js +7 -1
  413. package/dist/src/submission.d.ts +4 -0
  414. package/dist/src/submission.js +6 -2
  415. package/dist/src/testing.d.ts +29 -0
  416. package/dist/src/testing.js +264 -0
  417. package/dist/src/ticket-dependencies.d.ts +1 -0
  418. package/dist/src/ticket-dependencies.js +15 -0
  419. package/dist/src/ticket-status-stream.d.ts +9 -0
  420. package/dist/src/ticket-status-stream.js +94 -0
  421. package/dist/src/ticket-status.js +7 -4
  422. package/dist/src/token-prices.d.ts +14 -4
  423. package/dist/src/token-prices.js +56 -11
  424. package/dist/src/turn-profile.d.ts +1 -0
  425. package/dist/src/turn-profile.js +8 -1
  426. package/dist/src/worker-usage.d.ts +25 -0
  427. package/dist/src/worker-usage.js +58 -1
  428. package/dist/src/workflow-admission.d.ts +6 -0
  429. package/dist/src/workflow-candidate.d.ts +7 -2
  430. package/dist/src/workflow-candidate.js +48 -5
  431. package/dist/src/workflow-contracts.d.ts +2 -0
  432. package/dist/src/workflow-contracts.js +8 -3
  433. package/dist/src/workflow-declaration.d.ts +31 -2
  434. package/dist/src/workflow-declaration.js +140 -16
  435. package/dist/src/workflow-discovery.d.ts +19 -0
  436. package/dist/src/workflow-discovery.js +36 -0
  437. package/dist/src/workflow-refusals.d.ts +6 -0
  438. package/dist/src/workflow-refusals.js +42 -0
  439. package/dist/src/workflow-schedule.d.ts +22 -0
  440. package/dist/src/workflow-schedule.js +53 -0
  441. package/dist/src/workflows.d.ts +12 -1
  442. package/dist/src/workflows.js +9 -0
  443. package/dist/tools/admit-workflow.d.ts +14 -0
  444. package/dist/tools/admit-workflow.js +107 -0
  445. package/dist/tools/doctor-adoption.d.ts +1 -0
  446. package/dist/tools/doctor-adoption.js +11 -0
  447. package/dist/tools/project-configuration.d.ts +4 -0
  448. package/dist/tools/project-configuration.js +47 -0
  449. package/dist/tools/self-host-processes.d.ts +1 -0
  450. package/dist/tools/self-host-processes.js +33 -22
  451. package/dist/tools/self-host-project.d.ts +21 -0
  452. package/dist/tools/self-host-project.js +224 -0
  453. package/dist/tools/self-host-runtime.d.ts +16 -0
  454. package/dist/tools/self-host-runtime.js +60 -0
  455. package/dist/tools/self-host-workflows.d.ts +1 -0
  456. package/dist/tools/self-host-workflows.js +36 -1
  457. package/dist/tools/self-host.js +106 -135
  458. package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
  459. package/dist/tools/workflow-bundle-dependencies.js +93 -0
  460. package/dist/tools/workflow-bundles.d.ts +20 -0
  461. package/dist/tools/workflow-bundles.js +173 -0
  462. package/dist/tools/workflow-candidate-counts.d.ts +12 -0
  463. package/dist/tools/workflow-candidate-counts.js +266 -0
  464. package/dist/tools/workflow-candidate-fields.d.ts +5 -0
  465. package/dist/tools/workflow-candidate-fields.js +24 -0
  466. package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
  467. package/dist/tools/workflow-candidate-helper-counts.js +129 -0
  468. package/dist/tools/workflow-candidate-program.d.ts +13 -0
  469. package/dist/tools/workflow-candidate-program.js +106 -0
  470. package/dist/tools/workflow-candidate-source.d.ts +6 -0
  471. package/dist/tools/workflow-candidate-source.js +169 -0
  472. package/dist/tools/workflow-candidate-syntax.d.ts +21 -0
  473. package/dist/tools/workflow-candidate-syntax.js +263 -0
  474. package/dist/tools/workflow-command.d.ts +1 -0
  475. package/dist/tools/workflow-command.js +143 -0
  476. package/dist/tools/workflow-folder-capture.d.ts +18 -0
  477. package/dist/tools/workflow-folder-capture.js +261 -0
  478. package/dist/tools/workflow-folders.d.ts +49 -0
  479. package/dist/tools/workflow-folders.js +203 -0
  480. package/dist/tools/workflow-source-effects.d.ts +10 -0
  481. package/dist/tools/workflow-source-effects.js +213 -0
  482. package/dist/tools/workflow-test-hook.d.ts +7 -0
  483. package/dist/tools/workflow-test-hook.js +16 -0
  484. package/dist/tools/workflow-test-loader.d.ts +1 -0
  485. package/dist/tools/workflow-test-loader.js +10 -0
  486. package/dist/workflows/develop-prd.js +71 -3
  487. package/dist/workflows/develop-ticket.js +6 -1
  488. package/dist/workflows/ticket-prompts.js +17 -3
  489. package/package.json +66 -6
  490. package/templates/develop/README.md +78 -0
  491. package/templates/develop/develop/accept.ts +11 -0
  492. package/templates/develop/develop/flow-tests.ts +357 -0
  493. package/templates/develop/develop/local.ts +40 -0
  494. package/templates/develop/develop/option-tests.ts +174 -0
  495. package/templates/develop/develop/partial-choice.ts +29 -0
  496. package/templates/develop/develop/partial.ts +28 -0
  497. package/templates/develop/develop/pull.ts +152 -0
  498. package/templates/develop/develop/queue-partial.ts +39 -0
  499. package/templates/develop/develop/refusal-tests.ts +174 -0
  500. package/templates/develop/develop/report.ts +156 -0
  501. package/templates/develop/develop/round.ts +40 -0
  502. package/templates/develop/develop/scenarios.ts +87 -0
  503. package/templates/develop/develop/turn.ts +67 -0
  504. package/templates/develop/develop.declaration.json +24 -0
  505. package/templates/develop/develop.test.ts +287 -0
  506. package/templates/develop/develop.ts +30 -0
  507. package/templates/develop/template.json +153 -0
  508. package/dist/src/chats/analysis-batches.d.ts +0 -24
  509. package/dist/src/chats/analysis-batches.js +0 -83
  510. package/dist/src/chats/analysis-contract.d.ts +0 -80
  511. package/dist/src/chats/analysis-contract.js +0 -16
  512. package/dist/src/chats/analysis-data.d.ts +0 -3
  513. package/dist/src/chats/analysis-data.js +0 -85
  514. package/dist/src/chats/analysis-input.d.ts +0 -12
  515. package/dist/src/chats/analysis-input.js +0 -83
  516. package/dist/src/chats/analysis-links.d.ts +0 -2
  517. package/dist/src/chats/analysis-links.js +0 -25
  518. package/dist/src/chats/analysis-prompt.d.ts +0 -10
  519. package/dist/src/chats/analysis-prompt.js +0 -16
  520. package/dist/src/chats/analysis-proposal.d.ts +0 -2
  521. package/dist/src/chats/analysis-proposal.js +0 -32
  522. package/dist/src/chats/analysis-provenance.d.ts +0 -4
  523. package/dist/src/chats/analysis-provenance.js +0 -99
  524. package/dist/src/chats/analysis-shape.d.ts +0 -3
  525. package/dist/src/chats/analysis-shape.js +0 -228
  526. package/dist/src/chats/analysis.d.ts +0 -3
  527. package/dist/src/chats/analysis.js +0 -42
  528. package/dist/src/chats/corpus-input.d.ts +0 -5
  529. package/dist/src/chats/corpus-input.js +0 -288
  530. package/dist/src/chats/destination.d.ts +0 -4
  531. package/dist/src/chats/destination.js +0 -96
  532. package/dist/src/chats/import.d.ts +0 -15
  533. package/dist/src/chats/import.js +0 -243
  534. package/dist/src/chats/input-file.d.ts +0 -3
  535. package/dist/src/chats/input-file.js +0 -32
  536. package/dist/src/chats/normalize.d.ts +0 -29
  537. package/dist/src/chats/normalize.js +0 -155
  538. package/dist/src/chats/previous-import.d.ts +0 -5
  539. package/dist/src/chats/previous-import.js +0 -34
  540. package/dist/src/chats/reader.d.ts +0 -21
  541. package/dist/src/chats/reader.js +0 -118
  542. package/dist/src/chats/redact-import.d.ts +0 -14
  543. package/dist/src/chats/redact-import.js +0 -141
  544. package/dist/src/chats/redaction.d.ts +0 -41
  545. package/dist/src/chats/redaction.js +0 -161
  546. package/dist/src/chats/revision-input.d.ts +0 -3
  547. package/dist/src/chats/revision-input.js +0 -180
  548. package/dist/src/chats/revision.d.ts +0 -48
  549. package/dist/src/chats/revision.js +0 -94
  550. package/dist/src/chats/selection.d.ts +0 -25
  551. package/dist/src/chats/selection.js +0 -109
  552. package/dist/src/chats/source.d.ts +0 -23
  553. package/dist/src/chats/source.js +0 -135
  554. package/dist/src/chats/structure.d.ts +0 -57
  555. package/dist/src/chats/structure.js +0 -216
  556. package/dist/src/daemon/analysis-launch.d.ts +0 -5
  557. package/dist/src/daemon/analysis-launch.js +0 -81
  558. package/dist/src/daemon/analysis-token.d.ts +0 -6
  559. package/dist/src/daemon/analysis-token.js +0 -88
  560. package/dist/src/daemon/analysis-worker.d.ts +0 -22
  561. package/dist/src/daemon/analysis-worker.js +0 -219
  562. package/dist/src/daemon/chats-files.d.ts +0 -15
  563. package/dist/src/daemon/chats-files.js +0 -113
  564. package/dist/src/daemon/chats-worker.d.ts +0 -12
  565. package/dist/src/daemon/chats-worker.js +0 -200
  566. package/dist/workflows/analyze-chats.d.ts +0 -10
  567. package/dist/workflows/analyze-chats.declaration.json +0 -9
  568. package/dist/workflows/analyze-chats.js +0 -73
@@ -1,10 +1,16 @@
1
+ import { turnCommand } from "./turn-command.js";
1
2
  import { spawn } from "node:child_process";
2
3
  import { createWriteStream, mkdtempSync, rmSync } from "node:fs";
3
4
  import { join } from "node:path";
4
5
  import { codexStream } from "./codex-stream.js";
5
- import { priceOf, usageOf } from "../worker-usage.js";
6
+ import { cursorStream } from "./cursor-stream.js";
7
+ import { opencodeStream } from "./opencode-stream.js";
8
+ import { textOutput } from "./text-output.js";
9
+ import { grokResultFields, grokUsageWarnings } from "../grok-result.js";
10
+ import { geminiStream } from "./gemini-stream.js";
11
+ import { priceOf, modelUsageOf, usageOf, } from "../worker-usage.js";
6
12
  import { commandModel } from "../token-prices.js";
7
- import { analysisCommand, analysisEnvironment } from "./analysis-launch.js";
13
+ import { shellTurnScript } from "../agent-harness-shell.js";
8
14
  function parsed(line) {
9
15
  try {
10
16
  const value = JSON.parse(line);
@@ -20,21 +26,39 @@ function numberOf(value) {
20
26
  function textOf(value) {
21
27
  return typeof value === "string" ? value : null;
22
28
  }
29
+ function networkFailure(result) {
30
+ return (result?.failed === true &&
31
+ result.text.startsWith("API Error: Can't reach the API server"));
32
+ }
23
33
  export function capacityRefusal(result) {
34
+ if (networkFailure(result))
35
+ return false;
24
36
  return (result?.failed === true &&
25
37
  ["success", "error_during_execution"].includes(result.subtype ?? "error_during_execution") &&
26
38
  (result.text ===
27
39
  "Selected model is at capacity. Please try a different model." ||
28
40
  result.errorType === "overloaded"));
29
41
  }
30
- export function streamResult(line) {
42
+ export function retryKind(result) {
43
+ if (networkFailure(result))
44
+ return "network";
45
+ return capacityRefusal(result) ? "capacity" : null;
46
+ }
47
+ export function succeeded(end) {
48
+ return (end.reason === undefined &&
49
+ end.exitCode === 0 &&
50
+ end.result?.failed === false);
51
+ }
52
+ export function streamResult(line, worker) {
31
53
  if (!line.includes('"result"'))
32
54
  return undefined;
33
55
  const record = parsed(line);
34
56
  const field = (name) => Reflect.get(Object(record), name);
35
57
  if (field("type") !== "result")
36
58
  return undefined;
59
+ const models = modelUsageOf(field("models"));
37
60
  return {
61
+ ...(models === undefined ? {} : { models }),
38
62
  ...(typeof field("subtype") === "string"
39
63
  ? { subtype: String(field("subtype")) }
40
64
  : {}),
@@ -48,6 +72,7 @@ export function streamResult(line) {
48
72
  model: textOf(field("model")),
49
73
  sessionId: textOf(field("session_id")),
50
74
  turns: numberOf(field("num_turns")),
75
+ ...(worker === "grok" ? grokResultFields(record) : {}),
51
76
  };
52
77
  }
53
78
  function ended(stream) {
@@ -55,12 +80,7 @@ function ended(stream) {
55
80
  stream.end(settle);
56
81
  });
57
82
  }
58
- function turnEnvironment(configuration, start) {
59
- if (start.mode === "analysis")
60
- return {
61
- ...analysisEnvironment(start.folder),
62
- CLAUDE_CODE_OAUTH_TOKEN: start.analysisToken,
63
- };
83
+ export function turnEnvironment(configuration, start) {
64
84
  const excluded = new Set([
65
85
  "GH_TOKEN",
66
86
  "GITHUB_TOKEN",
@@ -75,25 +95,42 @@ function turnEnvironment(configuration, start) {
75
95
  if (start.turnId !== undefined)
76
96
  environment["CLOVING_TURN_ID"] = start.turnId;
77
97
  environment["GH_CONFIG_DIR"] = configuration;
98
+ if (start.worker === "opencode")
99
+ environment["OPENCODE_PERMISSION"] = '{"*":"allow"}';
78
100
  return environment;
79
101
  }
80
102
  function spawnTurn(start) {
81
103
  const configuration = mkdtempSync(join(start.folder, "gh-config-"));
82
- const [executable = "", ...fixed] = start.mode === "analysis" ? analysisCommand() : start.command;
104
+ const { parts, standardInput } = turnCommand(start);
105
+ const command = start.shell === undefined
106
+ ? parts
107
+ : [
108
+ start.shell,
109
+ "-l",
110
+ "-i",
111
+ "-c",
112
+ shellTurnScript,
113
+ "cloving-harness",
114
+ configuration,
115
+ ...parts,
116
+ ];
117
+ const [executable = "", ...fixed] = command;
83
118
  try {
84
119
  const child = spawn(executable, fixed, {
85
120
  cwd: start.directory,
86
121
  env: turnEnvironment(configuration, start),
87
122
  stdio: ["pipe", "pipe", "pipe"],
123
+ detached: start.shell !== undefined,
88
124
  });
89
- return { child, configuration };
125
+ return { child, configuration, standardInput };
90
126
  }
91
127
  catch (error) {
92
128
  rmSync(configuration, { recursive: true, force: true });
93
129
  throw error;
94
130
  }
95
131
  }
96
- function receivedLines(stream, lines) {
132
+ function receivedLines(stream, input) {
133
+ const { lines, worker } = input;
97
134
  for (const line of lines) {
98
135
  const event = parsed(line);
99
136
  const field = (name) => Reflect.get(Object(event), name);
@@ -102,7 +139,7 @@ function receivedLines(stream, lines) {
102
139
  stream.errorType = textOf(field("error"));
103
140
  if (type === "system" || type === "result")
104
141
  stream.model = textOf(field("model")) ?? stream.model;
105
- const result = streamResult(line);
142
+ const result = streamResult(line, worker);
106
143
  if (result !== undefined) {
107
144
  const errorType = result.errorType ?? stream.errorType;
108
145
  stream.result = {
@@ -113,16 +150,31 @@ function receivedLines(stream, lines) {
113
150
  }
114
151
  }
115
152
  function activityOutput(start) {
116
- if (start.mode === "analysis")
117
- return undefined;
118
153
  const output = createWriteStream(join(start.activityFolder ?? start.folder, "turn.jsonl"), { flags: start.activityFolder === undefined ? "w" : "a" });
119
154
  if (start.activityFolder !== undefined)
120
155
  output.write("\n");
121
156
  return output;
122
157
  }
123
- function turnOutput(start, stdout) {
158
+ function streamAdapter(worker) {
159
+ if (worker === "codex")
160
+ return codexStream();
161
+ if (worker === "cursor-agent")
162
+ return cursorStream();
163
+ if (worker === "gemini")
164
+ return geminiStream();
165
+ return undefined;
166
+ }
167
+ function turnOutput(start, child) {
124
168
  const output = activityOutput(start);
125
- const codex = start.worker === "codex" ? codexStream() : undefined;
169
+ if (start.output === "text")
170
+ return textOutput(child, { output, limit: start.resultBytes ?? 48_000 });
171
+ const translated = start.worker === "opencode" ? opencodeStream() : undefined;
172
+ const adapter = translated ?? streamAdapter(start.worker);
173
+ const { stdout, stderr } = child;
174
+ if (translated !== undefined) {
175
+ stderr.setEncoding("utf8");
176
+ stderr.on("data", translated.stderr);
177
+ }
126
178
  const stream = {
127
179
  pending: "",
128
180
  result: undefined,
@@ -130,66 +182,72 @@ function turnOutput(start, stdout) {
130
182
  errorType: null,
131
183
  };
132
184
  const received = (lines) => {
133
- receivedLines(stream, lines);
185
+ receivedLines(stream, {
186
+ lines,
187
+ ...(start.worker === undefined ? {} : { worker: start.worker }),
188
+ });
134
189
  };
135
190
  const written = (lines) => {
136
191
  for (const line of lines)
137
- output?.write(`${line}\n`);
192
+ output.write(`${line}\n`);
138
193
  received(lines);
139
194
  };
140
195
  stdout.setEncoding("utf8");
141
196
  stdout.on("data", (chunk) => {
142
- if (codex === undefined)
143
- output?.write(chunk);
197
+ if (adapter === undefined)
198
+ output.write(chunk);
144
199
  const lines = `${stream.pending}${chunk}`.split("\n");
145
200
  stream.pending = lines.pop() ?? "";
146
- if (codex !== undefined) {
147
- written(lines.flatMap(codex.line));
201
+ if (adapter !== undefined) {
202
+ written(lines.flatMap(adapter.line));
148
203
  return;
149
204
  }
150
205
  received(lines);
151
206
  });
152
207
  return async (exitCode) => {
153
- if (codex !== undefined) {
154
- written(codex.line(stream.pending));
155
- written([codex.result(exitCode)]);
208
+ if (adapter !== undefined) {
209
+ written(adapter.line(stream.pending));
210
+ written([adapter.result(exitCode)]);
156
211
  }
157
- if (output !== undefined)
158
- await ended(output);
159
- if (codex === undefined)
212
+ await ended(output);
213
+ if (adapter === undefined)
160
214
  received([stream.pending]);
161
215
  const result = stream.result;
162
216
  return result === undefined
163
217
  ? undefined
164
218
  : {
165
219
  ...result,
166
- model: result.model ??
167
- stream.model ??
168
- commandModel(start.mode === "analysis" ? analysisCommand() : start.command),
220
+ model: result.model ?? stream.model ?? commandModel(start.command),
169
221
  };
170
222
  };
171
223
  }
172
- function withoutAnalysisToken(start, result) {
173
- const token = start.mode === "analysis" ? start.analysisToken : undefined;
174
- if (token === undefined || result === undefined)
175
- return result;
176
- const redact = (value) => value === null ? null : value.replaceAll(token, "[redacted]");
177
- return {
178
- ...result,
179
- text: redact(result.text) ?? "",
180
- model: redact(result.model),
181
- sessionId: redact(result.sessionId),
182
- };
224
+ function signalTurn(turn, signal) {
225
+ const { child, start } = turn;
226
+ if (start.shell === undefined || child.pid === undefined) {
227
+ child.kill(signal);
228
+ return;
229
+ }
230
+ try {
231
+ process.kill(-child.pid, signal);
232
+ }
233
+ catch (error) {
234
+ const code = Reflect.get(Object(error), "code");
235
+ if (code !== "ESRCH" && code !== "EPERM")
236
+ throw error;
237
+ child.kill(signal);
238
+ }
183
239
  }
184
240
  export function startTurn(start) {
185
- const { child, configuration } = spawnTurn(start);
186
- const output = turnOutput(start, child.stdout);
187
- if (start.mode === "analysis")
188
- child.stderr.resume();
189
- else
190
- child.stderr.pipe(createWriteStream(join(start.folder, "turn.stderr.log")));
241
+ const { child, configuration, standardInput } = spawnTurn(start);
242
+ const output = turnOutput(start, child);
243
+ const warnings = grokUsageWarnings();
244
+ if (start.worker === "grok") {
245
+ child.stderr.setEncoding("utf8");
246
+ child.stderr.on("data", warnings.write);
247
+ }
248
+ child.stderr.pipe(createWriteStream(join(start.folder, "turn.stderr.log")));
191
249
  child.stdin.on("error", () => undefined);
192
- child.stdin.end(start.prompt);
250
+ child.stdin.end(standardInput);
193
251
  const closed = new Promise((settle) => {
194
252
  child.once("error", () => undefined);
195
253
  child.once("close", settle);
@@ -200,17 +258,22 @@ export function startTurn(start) {
200
258
  ended: closed
201
259
  .then(async (exitCode) => {
202
260
  timers.forEach(clearTimeout);
261
+ const result = await output(exitCode);
203
262
  return {
204
263
  exitCode,
205
- result: withoutAnalysisToken(start, await output(exitCode)),
264
+ result: result !== undefined && warnings.incomplete()
265
+ ? { ...result, usage: usageOf(null), costUsd: null }
266
+ : result,
206
267
  };
207
268
  })
208
269
  .finally(() => {
209
270
  rmSync(configuration, { recursive: true, force: true });
210
271
  }),
211
272
  stop: (graceMilliseconds) => {
212
- child.kill("SIGTERM");
213
- timers.push(setTimeout(() => child.kill("SIGKILL"), graceMilliseconds).unref());
273
+ signalTurn({ child, start }, "SIGTERM");
274
+ timers.push(setTimeout(() => {
275
+ signalTurn({ child, start }, "SIGKILL");
276
+ }, graceMilliseconds).unref());
214
277
  },
215
278
  };
216
279
  }
@@ -1,12 +1,9 @@
1
- import { type TokenPrices } from "../token-prices.ts";
1
+ import { type HarnessSettings } from "../harness-defaults.ts";
2
2
  import { type TurnProfiles } from "../turn-profile.ts";
3
3
  import type { Delivery } from "../broker/actor/delivery-intents.ts";
4
- import { type Worker } from "./claude-turn.ts";
5
4
  import { type RetrySettings } from "./retrying-turn.ts";
6
5
  import { type WorkerReport } from "./operation-journal.ts";
7
- export interface ClaudeWorkerSettings extends RetrySettings {
8
- readonly tokenPrices?: TokenPrices;
9
- readonly worker?: Worker;
6
+ export interface ClaudeWorkerSettings extends RetrySettings, HarnessSettings {
10
7
  readonly profiles?: TurnProfiles;
11
8
  readonly workflowId?: (runId: string) => Promise<string | undefined>;
12
9
  readonly repository: string;
@@ -18,6 +15,7 @@ export interface ClaudeWorkerSettings extends RetrySettings {
18
15
  readonly stopMilliseconds?: number;
19
16
  }
20
17
  export interface ClaudeWorker extends Delivery {
18
+ readonly harness: (operationId: string) => Promise<string | undefined>;
21
19
  readonly stop: NonNullable<Delivery["stop"]>;
22
20
  readonly close: () => Promise<void>;
23
21
  }
@@ -1,19 +1,23 @@
1
1
  import { join } from "node:path";
2
- import { ticketStatus } from "../ticket-status.js";
3
- import { analysisWorker } from "./analysis-worker.js";
4
- import { analysisMethod } from "./analysis-launch.js";
5
- import { estimatedCostUsd, priceForModel, } from "../token-prices.js";
2
+ import { turnHarness } from "../harness-defaults.js";
6
3
  import { profileCommand, } from "../turn-profile.js";
7
- import {} from "./claude-turn.js";
4
+ import { succeeded } from "./claude-turn.js";
5
+ import { turnReport } from "./turn-report.js";
8
6
  import { startRetriedTurn } from "./retrying-turn.js";
9
7
  import { interrupted, located, operationKey, readRecord as read, replied, reportOf, writeRecord as written, } from "./operation-journal.js";
10
- import { changes, treeFailure, workTree } from "./work-tree.js";
8
+ import { treeFailure, workTree } from "./work-tree.js";
11
9
  export const claudeLimits = {
12
10
  summaryCharacters: 16_000,
13
11
  resultBytes: 48_000,
14
12
  stopMilliseconds: 2_000,
15
13
  };
16
14
  const worker = "claude";
15
+ async function recordedHarness(journal, operationId) {
16
+ const { folder } = located(journal, operationId);
17
+ const started = await read(folder, "started.json").catch(() => undefined);
18
+ const harness = Reflect.get(Object(started), "harness");
19
+ return typeof harness === "string" ? harness : undefined;
20
+ }
17
21
  function alive(processId) {
18
22
  if (typeof processId !== "number")
19
23
  return false;
@@ -41,78 +45,43 @@ async function reconciled(parts, intent) {
41
45
  await written(folder, { name: "result.json", value: ending });
42
46
  return replied({ receipt: key, worker }, ending);
43
47
  }
44
- async function resultText(tree, turn) {
45
- const { result, settings } = turn;
46
- const fields = {
47
- ticketStatus: ticketStatus(result.text),
48
- summary: result.text.slice(0, claudeLimits.summaryCharacters),
49
- ...(await changes(tree)),
50
- worktree: tree.path,
51
- costUsd: result.costUsd,
52
- usage: result.usage,
53
- model: result.model,
54
- estimatedCostUsd: estimatedCostUsd(result.usage, {
55
- worker: settings.worker ?? "claude",
56
- price: priceForModel(settings.tokenPrices ?? {}, result.model),
57
- }),
58
- sessionId: result.sessionId,
59
- turns: result.turns,
60
- };
61
- const text = JSON.stringify(fields);
62
- const excess = Buffer.byteLength(text) - claudeLimits.resultBytes;
63
- if (excess <= 0)
64
- return { text };
65
- const kept = Math.max(0, fields.summary.length - excess);
66
- const shortened = JSON.stringify({
67
- ...fields,
68
- summary: fields.summary.slice(0, kept),
69
- });
70
- if (Buffer.byteLength(shortened) <= claudeLimits.resultBytes)
71
- return { text: shortened };
72
- const metadata = JSON.stringify({
73
- ...fields,
74
- ticketStatus: undefined,
75
- summary: "",
76
- });
77
- return {
78
- reason: "claude-result-too-large",
79
- ...(Buffer.byteLength(metadata) <= claudeLimits.resultBytes
80
- ? { text: metadata }
81
- : {}),
82
- };
83
- }
84
48
  async function outcome(running, end) {
85
49
  const endedAt = new Date().toISOString();
86
50
  const { result } = end;
87
51
  const report = result === undefined
88
52
  ? {}
89
- : await resultText(running.tree, { result, settings: running.settings });
53
+ : await turnReport({
54
+ tree: running.tree,
55
+ harness: running.harness,
56
+ limits: claudeLimits,
57
+ }, result);
90
58
  const { text, reason } = report;
91
- if (reason === undefined &&
92
- text !== undefined &&
93
- end.exitCode === 0 &&
94
- result?.failed === false)
59
+ if (succeeded(end) && reason === undefined && text !== undefined)
95
60
  return { outcome: "completed", result: text, endedAt };
96
61
  if (running.stopping.requested)
97
62
  return { outcome: "stopped", endedAt };
98
63
  return {
99
64
  outcome: "failed",
100
- reason: reason ?? "claude-turn-failed",
65
+ reason: end.reason ?? reason ?? "claude-turn-failed",
66
+ ...(end.detail === undefined ? {} : { detail: end.detail }),
101
67
  ...(text === undefined ? {} : { result: text }),
102
68
  endedAt,
103
69
  };
104
70
  }
105
71
  async function concluded(parts, running) {
106
72
  const { intent, key } = running;
107
- const recorded = await outcome({ ...running, settings: parts.settings }, await running.turn.ended);
73
+ const recorded = await outcome(running, await running.turn.ended);
108
74
  await written(running.folder, { name: "result.json", value: recorded });
109
75
  await parts.settings.report(reportOf({ intent, commandId: `claude-turn:${key}`, worker }, recorded));
110
76
  }
111
77
  async function begun(parts, start) {
112
78
  const { intent, key, folder, tree, prompt } = start;
79
+ const { harness } = start;
80
+ const stopping = { requested: false, controller: new AbortController() };
113
81
  const turn = startRetriedTurn({
114
- worker: parts.settings.worker ?? "claude",
115
- command: profileCommand(parts.settings.command, start.profile),
82
+ ...harness,
83
+ resultBytes: claudeLimits.resultBytes,
84
+ command: profileCommand(harness.command, start.profile),
116
85
  environment: start.profile.env ?? {},
117
86
  turnId: `${intent.runId}-${key}`,
118
87
  directory: tree.path,
@@ -120,7 +89,9 @@ async function begun(parts, start) {
120
89
  prompt,
121
90
  }, {
122
91
  ...parts.settings,
92
+ stopping: stopping.controller,
123
93
  metadata: {
94
+ harness: harness.worker,
124
95
  operationId: intent.operationId,
125
96
  target: intent.target,
126
97
  branch: tree.branch,
@@ -128,7 +99,6 @@ async function begun(parts, start) {
128
99
  startCommit: tree.startCommit,
129
100
  },
130
101
  });
131
- const stopping = { requested: false };
132
102
  parts.active.set(key, {
133
103
  turn,
134
104
  stopping,
@@ -174,16 +144,30 @@ async function runWorkflow(settings, runId) {
174
144
  return undefined;
175
145
  }
176
146
  }
147
+ function unsupportedProfile(profile, harness) {
148
+ if (harness.output === "text" && profile.model !== undefined)
149
+ return "profile-model-not-supported";
150
+ if (harness.worker === "claude")
151
+ return undefined;
152
+ return [
153
+ profile.allowedTools,
154
+ profile.permissionMode,
155
+ profile.maxBudgetUsd,
156
+ ].some((value) => value !== undefined)
157
+ ? "profile-needs-claude"
158
+ : undefined;
159
+ }
177
160
  async function selectedProfile(settings, intent) {
178
161
  if (intent.method === "run-turn")
179
162
  return {};
180
- if (settings.worker === "codex")
181
- return "profile-needs-claude";
182
163
  const name = intent.method.slice("run-turn:".length);
183
164
  const profiles = settings.profiles ?? {};
184
165
  const profile = Object.hasOwn(profiles, name) ? profiles[name] : undefined;
185
166
  if (profile === undefined)
186
167
  return "unknown-profile";
168
+ const unsupported = unsupportedProfile(profile, turnHarness(settings, profile));
169
+ if (unsupported !== undefined)
170
+ return unsupported;
187
171
  if (profile.workflows === undefined)
188
172
  return profile;
189
173
  const workflowId = await runWorkflow(settings, intent.runId);
@@ -222,11 +206,19 @@ async function delivered(parts, call) {
222
206
  const first = await firstTurn(settings, { tree, intent });
223
207
  if (aborted())
224
208
  return failure("claude-start-aborted");
225
- await begun(parts, { ...place, intent, tree: first, prompt, profile });
209
+ await begun(parts, {
210
+ ...place,
211
+ intent,
212
+ tree: first,
213
+ prompt,
214
+ profile,
215
+ harness: turnHarness(settings, profile),
216
+ });
226
217
  return { receipt: place.key, worker };
227
218
  }
228
219
  async function halted(parts, active) {
229
220
  active.stopping.requested = true;
221
+ active.stopping.controller.abort();
230
222
  const turn = await active.turn.catch(() => undefined);
231
223
  turn?.stop(parts.settings.stopMilliseconds ?? claudeLimits.stopMilliseconds);
232
224
  await active.concluded;
@@ -241,35 +233,27 @@ async function stopped(parts, intent) {
241
233
  export function claudeWorker(settings) {
242
234
  if (settings.command.length === 0)
243
235
  throw new Error("invalid-claude-command");
236
+ turnHarness(settings);
237
+ for (const profile of Object.values(settings.profiles ?? {}))
238
+ turnHarness(settings, profile);
244
239
  const parts = {
245
240
  settings,
246
241
  active: new Map(),
247
242
  stopping: new AbortController(),
248
243
  };
249
- const analysis = analysisWorker(settings);
250
- const guarded = async (intent, run) => {
251
- if (!turnIntent(intent) ||
252
- Object.hasOwn(settings.profiles ?? {}, "analyze-chats") ||
253
- (await runWorkflow(settings, intent.runId)) !== "analyze-chats")
254
- return failure("analysis-worker-unavailable");
255
- return run();
256
- };
244
+ const guarded = (intent, run) => intent.method === "run-turn:analyze-chats"
245
+ ? Promise.resolve(failure("unsupported-effect"))
246
+ : run();
257
247
  return {
258
- deliver: (intent, signal) => intent.method === analysisMethod
259
- ? guarded(intent, () => analysis.deliver(intent, signal))
260
- : delivered(parts, {
261
- intent,
262
- signal: AbortSignal.any([signal, parts.stopping.signal]),
263
- }),
264
- reconcile: (intent, signal) => intent.method === analysisMethod
265
- ? guarded(intent, () => analysis.reconcile(intent, signal))
266
- : reconciled(parts, intent),
267
- stop: (intent, signal) => intent.method === analysisMethod
268
- ? guarded(intent, () => analysis.stop(intent, signal))
269
- : stopped(parts, intent),
248
+ harness: (operationId) => recordedHarness(settings.journal, operationId),
249
+ deliver: (intent, signal) => guarded(intent, () => delivered(parts, {
250
+ intent,
251
+ signal: AbortSignal.any([signal, parts.stopping.signal]),
252
+ })),
253
+ reconcile: (intent) => guarded(intent, () => reconciled(parts, intent)),
254
+ stop: (intent) => guarded(intent, () => stopped(parts, intent)),
270
255
  close: async () => {
271
256
  parts.stopping.abort();
272
- await analysis.close();
273
257
  await Promise.all([...parts.active.values()].map((active) => halted(parts, active)));
274
258
  },
275
259
  };
@@ -0,0 +1,5 @@
1
+ import type { CommandEffects } from "../command-settings.ts";
2
+ export declare function claimCommand(folder: string): Promise<boolean>;
3
+ export declare function commandStarted(folder: string): Promise<boolean>;
4
+ export declare function recordCommandResult(folder: string, value: unknown): Promise<boolean>;
5
+ export declare function commandEffects(journal: string): CommandEffects;
@@ -0,0 +1,50 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { link, mkdir, rm, stat, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { located, readRecord } from "./operation-journal.js";
5
+ import { record } from "../protocol.js";
6
+ function alreadyExists(error) {
7
+ if (Reflect.get(Object(error), "code") === "EEXIST")
8
+ return false;
9
+ throw error;
10
+ }
11
+ export async function claimCommand(folder) {
12
+ await mkdir(dirname(folder), { recursive: true, mode: 0o700 });
13
+ return mkdir(folder, { mode: 0o700 }).then(() => true, alreadyExists);
14
+ }
15
+ export async function commandStarted(folder) {
16
+ return stat(folder).then(() => true, (error) => {
17
+ if (Reflect.get(Object(error), "code") === "ENOENT")
18
+ return false;
19
+ throw error;
20
+ });
21
+ }
22
+ export async function recordCommandResult(folder, value) {
23
+ const staged = join(folder, `${randomUUID()}.staged`);
24
+ await writeFile(staged, JSON.stringify(value), { mode: 0o600, flag: "wx" });
25
+ try {
26
+ return await link(staged, join(folder, "result.json")).then(() => true, alreadyExists);
27
+ }
28
+ finally {
29
+ await rm(staged);
30
+ }
31
+ }
32
+ export function commandEffects(journal) {
33
+ const completed = new Map();
34
+ return (effects) => Promise.all(effects.map(async (effect) => {
35
+ const { key, folder } = located(journal, effect.operationId);
36
+ const cached = completed.get(key);
37
+ if (cached !== undefined)
38
+ return { ...effect, ...cached };
39
+ const result = record(await readRecord(folder, "result.json"));
40
+ const exitCode = result?.["exitCode"];
41
+ const duration = result?.["durationMilliseconds"];
42
+ const metadata = {
43
+ exitCode: typeof exitCode === "number" ? exitCode : null,
44
+ durationMilliseconds: typeof duration === "number" ? duration : null,
45
+ };
46
+ if (result !== undefined)
47
+ completed.set(key, metadata);
48
+ return { ...effect, ...metadata };
49
+ }));
50
+ }
@@ -0,0 +1,28 @@
1
+ export interface CommandStart {
2
+ readonly command: readonly string[];
3
+ readonly directory: string;
4
+ readonly folder: string;
5
+ readonly payload: string;
6
+ readonly runId: string;
7
+ readonly operationId: string;
8
+ readonly seconds: number;
9
+ readonly deadline?: string;
10
+ }
11
+ export interface CommandEnd {
12
+ readonly stdout: string;
13
+ readonly exitCode: number | null;
14
+ readonly durationMilliseconds: number;
15
+ readonly reason?: string;
16
+ }
17
+ export interface RunningCommand {
18
+ readonly ended: Promise<CommandEnd>;
19
+ readonly stop: () => void;
20
+ }
21
+ export interface CommandClock {
22
+ readonly now: () => number;
23
+ readonly timer: (wait: {
24
+ readonly milliseconds: number;
25
+ readonly expired: () => void;
26
+ }) => () => void;
27
+ }
28
+ export declare function startCommand(start: CommandStart, clock?: CommandClock): RunningCommand;