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,9 +1,11 @@
1
+ import { recordedNotifications, saveNotifications, } from "./notify-journal.js";
1
2
  import { spawn } from "node:child_process";
2
- import { readFile, rename, writeFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { send } from "../cli/client.js";
5
+ import { deliveryBackoffMilliseconds } from "../delivery-backoff.js";
5
6
  import { record } from "../protocol.js";
6
7
  import { decisionNotification, outcomeNotification, } from "./notify-message.js";
8
+ const retentionMilliseconds = 7 * 24 * 60 * 60_000;
7
9
  async function request(runtimeDirectory, request) {
8
10
  const reply = await send(runtimeDirectory, request);
9
11
  if (reply.kind === "error")
@@ -20,6 +22,20 @@ function rows(value) {
20
22
  return row;
21
23
  });
22
24
  }
25
+ async function flushNotifications(journal) {
26
+ if (journal.unsaved.size === 0)
27
+ return;
28
+ await saveNotifications(journal.file, journal);
29
+ for (const entry of journal.unsaved.values())
30
+ if (entry.state === "failed" && entry.attempts === 5)
31
+ process.stderr.write(`Notify delivery failed: ${entry.key}\n`);
32
+ journal.unsaved.clear();
33
+ }
34
+ async function finishDelivery(journal, entry) {
35
+ journal.entries.set(entry.key, entry);
36
+ journal.unsaved.set(entry.key, entry);
37
+ await flushNotifications(journal);
38
+ }
23
39
  async function observedOutcome(summary, source) {
24
40
  const { runtimeDirectory, cache } = source;
25
41
  const latestSequence = summary["latestSequence"];
@@ -74,26 +90,6 @@ async function events(runtimeDirectory, cache) {
74
90
  }
75
91
  return found;
76
92
  }
77
- async function recorded(file) {
78
- const text = await readFile(file, "utf8").catch((error) => {
79
- if (error instanceof Error && "code" in error && error.code === "ENOENT")
80
- return undefined;
81
- throw error;
82
- });
83
- if (text === undefined)
84
- return undefined;
85
- const value = JSON.parse(text);
86
- if (!Array.isArray(value) || !value.every((key) => typeof key === "string"))
87
- throw new Error("invalid-notify-record");
88
- return new Set(value.map(String));
89
- }
90
- async function save(file, keys) {
91
- await writeFile(`${file}.tmp`, JSON.stringify([...keys]) + "\n", {
92
- mode: 0o600,
93
- flush: true,
94
- });
95
- await rename(`${file}.tmp`, file);
96
- }
97
93
  export function notifyCommand(command, notification) {
98
94
  return new Promise((resolve, reject) => {
99
95
  const [executable = "", ...argumentsList] = command;
@@ -117,45 +113,189 @@ function report(label, error) {
117
113
  const reason = error instanceof Error ? error.message : String(error);
118
114
  process.stderr.write(`${label}: ${JSON.stringify(reason)}\n`);
119
115
  }
116
+ function failureReason(error) {
117
+ if (!(error instanceof Error))
118
+ return "command error";
119
+ if ("code" in error && (error.code === "ENOENT" || error.code === "EACCES"))
120
+ return `spawn ${error.code}`;
121
+ return /^(?:exit code (?:\d+|null)|signal SIG[A-Z0-9]+)$/.test(error.message)
122
+ ? error.message
123
+ : "command error";
124
+ }
125
+ async function prepareDelivery(journal, entry) {
126
+ if (entry.message === null || entry.state === "sent")
127
+ return undefined;
128
+ if (entry.attempts === 5 && entry.state === "pending")
129
+ await finishDelivery(journal, {
130
+ ...entry,
131
+ state: "failed",
132
+ lastFailure: "attempt interrupted",
133
+ });
134
+ if (entry.attempts === 5)
135
+ return undefined;
136
+ const backoff = deliveryBackoffMilliseconds[entry.attempts] ?? 0;
137
+ if (entry.lastAttemptAt !== null &&
138
+ Date.now() - entry.lastAttemptAt < backoff)
139
+ return undefined;
140
+ const pending = {
141
+ ...entry,
142
+ message: entry.message,
143
+ state: "pending",
144
+ attempts: entry.attempts + 1,
145
+ lastAttemptAt: Date.now(),
146
+ };
147
+ const next = new Map(journal.entries).set(entry.key, pending);
148
+ await saveNotifications(journal.file, { ...journal, entries: next });
149
+ journal.entries.set(entry.key, pending);
150
+ return pending;
151
+ }
152
+ async function deliver(settings, entry) {
153
+ try {
154
+ await notifyCommand(settings.command, entry.message);
155
+ return { ...entry, state: "sent" };
156
+ }
157
+ catch (error) {
158
+ return {
159
+ ...entry,
160
+ state: "failed",
161
+ lastFailure: failureReason(error),
162
+ };
163
+ }
164
+ }
165
+ async function settleDelivery(journal, progress) {
166
+ if (progress.completed !== undefined) {
167
+ const entry = progress.completed;
168
+ progress.completed = undefined;
169
+ await finishDelivery(journal, entry);
170
+ }
171
+ await flushNotifications(journal);
172
+ }
173
+ async function scheduleDelivery(settings, delivery) {
174
+ const { journal, progress } = delivery;
175
+ const stopped = () => progress.stopping.aborted;
176
+ if (stopped() ||
177
+ progress.active !== undefined ||
178
+ progress.completed !== undefined ||
179
+ journal.unsaved.size > 0)
180
+ return;
181
+ for (const entry of journal.entries.values()) {
182
+ if (stopped())
183
+ return;
184
+ const pending = await prepareDelivery(journal, entry);
185
+ if (pending === undefined)
186
+ continue;
187
+ if (stopped()) {
188
+ await finishDelivery(journal, entry);
189
+ return;
190
+ }
191
+ progress.active = deliver(settings, pending).then((completed) => {
192
+ progress.completed = completed;
193
+ progress.active = undefined;
194
+ delivery.ready();
195
+ });
196
+ return;
197
+ }
198
+ }
120
199
  async function check(settings, journal) {
200
+ const retained = new Map([...journal.entries].filter(([, entry]) => entry.state === "pending" ||
201
+ (entry.state === "failed" && entry.attempts < 5) ||
202
+ entry.lastAttemptAt === null ||
203
+ entry.lastAttemptAt >= Date.now() - retentionMilliseconds));
204
+ const removed = [...journal.entries.keys()].filter((key) => !retained.has(key));
205
+ if (removed.length > 0) {
206
+ const retiredKeys = new Set([...journal.retiredKeys, ...removed]);
207
+ await saveNotifications(journal.file, { entries: retained, retiredKeys });
208
+ for (const key of removed) {
209
+ journal.entries.delete(key);
210
+ journal.retiredKeys.add(key);
211
+ }
212
+ }
121
213
  for (const event of await events(settings.runtimeDirectory, journal.cache)) {
122
- if (journal.keys.has(event.key))
214
+ if (journal.entries.has(event.key) || journal.retiredKeys.has(event.key))
123
215
  continue;
124
- await save(journal.file, new Set([...journal.keys, event.key]));
125
- journal.keys.add(event.key);
126
- await notifyCommand(settings.command, event.message).catch((error) => {
127
- report("Notify command failed", error);
128
- });
216
+ const entry = {
217
+ ...event,
218
+ state: "pending",
219
+ attempts: 0,
220
+ lastAttemptAt: null,
221
+ lastFailure: null,
222
+ };
223
+ journal.entries.set(event.key, entry);
224
+ journal.unsaved.set(event.key, entry);
129
225
  }
226
+ await flushNotifications(journal);
130
227
  }
131
228
  export async function notifyRuns(settings) {
132
229
  const file = join(settings.directory, "notify-events.json");
133
- const keys = await recorded(file);
230
+ const recorded = await recordedNotifications(file);
134
231
  const cache = new Map();
135
- const journal = { file, keys: keys ?? new Set(), cache };
136
- if (keys === undefined) {
232
+ const journal = {
233
+ file,
234
+ entries: recorded?.entries ?? new Map(),
235
+ retiredKeys: recorded?.retiredKeys ?? new Set(),
236
+ cache,
237
+ unsaved: new Map(),
238
+ };
239
+ if (recorded === undefined) {
137
240
  for (const event of await events(settings.runtimeDirectory, cache))
138
- journal.keys.add(event.key);
139
- await save(file, journal.keys);
241
+ journal.entries.set(event.key, {
242
+ ...event,
243
+ state: "sent",
244
+ attempts: 0,
245
+ lastAttemptAt: Date.now(),
246
+ lastFailure: null,
247
+ });
140
248
  }
249
+ await saveNotifications(file, journal);
250
+ return notificationLoop(settings, journal);
251
+ }
252
+ function notificationLoop(settings, journal) {
141
253
  let busy = false;
142
254
  let running = Promise.resolve();
255
+ const stopping = new AbortController();
256
+ const progress = {
257
+ stopping: stopping.signal,
258
+ active: undefined,
259
+ completed: undefined,
260
+ };
261
+ const ready = () => {
262
+ if (stopping.signal.aborted)
263
+ return;
264
+ running = running
265
+ .then(() => settleDelivery(journal, progress))
266
+ .then(() => scheduleDelivery(settings, { journal, progress, ready }))
267
+ .catch((error) => {
268
+ report("Notify delivery failed", error);
269
+ });
270
+ };
143
271
  const timer = setInterval(() => {
144
272
  if (busy)
145
273
  return;
146
274
  busy = true;
147
- running = check(settings, journal)
275
+ running = running
276
+ .then(() => settleDelivery(journal, progress))
277
+ .then(() => check(settings, journal))
148
278
  .catch((error) => {
149
279
  report("Notify check failed", error);
150
- })
151
- .finally(() => {
280
+ });
281
+ ready();
282
+ running = running.finally(() => {
152
283
  busy = false;
153
284
  });
154
285
  }, settings.intervalMilliseconds ?? 15_000);
155
286
  return {
156
- stop: async () => {
287
+ stop: () => {
288
+ stopping.abort();
157
289
  clearInterval(timer);
158
- await running;
290
+ running = running
291
+ .then(async () => {
292
+ await progress.active;
293
+ await settleDelivery(journal, progress);
294
+ })
295
+ .catch((error) => {
296
+ report("Notify delivery failed", error);
297
+ });
298
+ return running;
159
299
  },
160
300
  };
161
301
  }
@@ -0,0 +1,5 @@
1
+ export declare function opencodeStream(): {
2
+ line: (line: string) => readonly string[];
3
+ stderr: (chunk: string) => void;
4
+ result: (exitCode: number | null) => string;
5
+ };
@@ -0,0 +1,87 @@
1
+ import { record } from "../protocol.js";
2
+ import { sumUsage, usageOf, tokenCount, } from "../worker-usage.js";
3
+ function parsed(line) {
4
+ try {
5
+ return record(JSON.parse(line)) ?? {};
6
+ }
7
+ catch {
8
+ return {};
9
+ }
10
+ }
11
+ function tokens(value) {
12
+ const counts = record(value) ?? {};
13
+ const cache = record(counts["cache"]) ?? {};
14
+ const output = tokenCount(counts["output"]);
15
+ const reasoning = tokenCount(counts["reasoning"]);
16
+ return usageOf({
17
+ input_tokens: counts["input"],
18
+ cache_read_input_tokens: cache["read"],
19
+ output_tokens: output === null || reasoning === null ? null : output + reasoning,
20
+ });
21
+ }
22
+ function errorMessage(value) {
23
+ const error = record(value) ?? {};
24
+ const data = record(error["data"]) ?? {};
25
+ const message = data["message"] ?? error["name"];
26
+ return typeof message === "string" ? message : "opencode error";
27
+ }
28
+ function translated(line, state) {
29
+ const event = parsed(line);
30
+ const part = record(event["part"]) ?? {};
31
+ if (typeof event["sessionID"] === "string")
32
+ state.sessionId = event["sessionID"];
33
+ if (typeof event["model"] === "string")
34
+ state.model = event["model"];
35
+ if (event["type"] === "error")
36
+ state.error = errorMessage(event["error"]);
37
+ if (event["type"] === "step_finish") {
38
+ state.steps.push(tokens(part["tokens"]));
39
+ state.reason = part["reason"];
40
+ }
41
+ if (event["type"] !== "text" || typeof part["text"] !== "string")
42
+ return [];
43
+ state.message = part["text"];
44
+ return [
45
+ JSON.stringify({
46
+ type: "assistant",
47
+ message: { content: [{ type: "text", text: state.message }] },
48
+ }),
49
+ ];
50
+ }
51
+ function result(exitCode, state) {
52
+ const success = exitCode === 0 && state.error === null && state.reason === "stop";
53
+ const failure = exitCode === 0
54
+ ? "opencode ended without a final stop step"
55
+ : `opencode ended with the code ${String(exitCode)}`;
56
+ return JSON.stringify({
57
+ type: "result",
58
+ subtype: success ? "success" : "error_during_execution",
59
+ is_error: !success,
60
+ result: success
61
+ ? state.message
62
+ : state.error || state.stderr.trim() || failure,
63
+ total_cost_usd: null,
64
+ model: state.model,
65
+ usage: sumUsage(state.steps),
66
+ session_id: state.sessionId,
67
+ num_turns: state.steps.length,
68
+ });
69
+ }
70
+ export function opencodeStream() {
71
+ const state = {
72
+ steps: [],
73
+ message: "",
74
+ sessionId: null,
75
+ model: null,
76
+ reason: null,
77
+ error: null,
78
+ stderr: "",
79
+ };
80
+ return {
81
+ line: (line) => translated(line, state),
82
+ stderr: (chunk) => {
83
+ state.stderr = (state.stderr + chunk).slice(-16_000);
84
+ },
85
+ result: (exitCode) => result(exitCode, state),
86
+ };
87
+ }
@@ -0,0 +1,4 @@
1
+ export declare function activeQueueRuns(settings: {
2
+ readonly runtimeDirectory: string;
3
+ readonly workflowId?: string;
4
+ }): Promise<number>;
@@ -0,0 +1,38 @@
1
+ import { send } from "../cli/client.js";
2
+ import { record } from "../protocol.js";
3
+ function queueBusy(value) {
4
+ const busy = record(value)?.["busy"];
5
+ if (typeof busy !== "number")
6
+ return undefined;
7
+ if (!Number.isSafeInteger(busy) || busy < 0)
8
+ throw new Error("invalid-queue-status");
9
+ return busy;
10
+ }
11
+ export async function activeQueueRuns(settings) {
12
+ let count = 0;
13
+ let after = "";
14
+ do {
15
+ const reply = await send(settings.runtimeDirectory, {
16
+ operation: "status",
17
+ parameters: { after, limit: 500 },
18
+ });
19
+ if (reply.kind === "error")
20
+ throw new Error(reply.error.code);
21
+ const busy = queueBusy(reply.result["queue"]);
22
+ if (busy !== undefined)
23
+ return busy;
24
+ const runs = reply.result["runs"];
25
+ if (!Array.isArray(runs))
26
+ throw new Error("invalid-run-list");
27
+ count += runs.filter((value) => {
28
+ const run = record(value);
29
+ return (run?.["workflowId"] === (settings.workflowId ?? "develop-issue") &&
30
+ !["completed", "failed", "cancelled"].includes(String(run["state"])));
31
+ }).length;
32
+ const next = reply.result["next"];
33
+ if (next !== null && (typeof next !== "string" || next <= after))
34
+ throw new Error("invalid-run-page");
35
+ after = next;
36
+ } while (after !== null);
37
+ return count;
38
+ }
@@ -0,0 +1,18 @@
1
+ export interface RetryTree {
2
+ readonly directory: string;
3
+ readonly signal: AbortSignal;
4
+ }
5
+ interface GitResult {
6
+ readonly text: string;
7
+ readonly code: number | null;
8
+ }
9
+ export declare function retryGit(tree: RetryTree, parts: readonly string[]): Promise<GitResult>;
10
+ export declare function turnHead(tree: RetryTree): Promise<string | null>;
11
+ export declare function retryEvidence(tree: RetryTree, startCommit: string | null): Promise<string>;
12
+ export interface IndexFailure {
13
+ readonly reason: "worktree-index-unknown" | "worktree-index-locked";
14
+ readonly lockPath?: string;
15
+ readonly fix: string;
16
+ }
17
+ export declare function indexFailure(tree: RetryTree): Promise<IndexFailure | null>;
18
+ export {};
@@ -0,0 +1,139 @@
1
+ import { spawn } from "node:child_process";
2
+ import { lstat } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ function kill(child) {
5
+ if (child.pid === undefined)
6
+ return;
7
+ try {
8
+ process.kill(-child.pid, "SIGKILL");
9
+ }
10
+ catch {
11
+ child.kill("SIGKILL");
12
+ }
13
+ }
14
+ export async function retryGit(tree, parts) {
15
+ if (tree.signal.aborted)
16
+ return { text: "", code: null };
17
+ const child = spawn("git", ["-C", tree.directory, ...parts], {
18
+ stdio: ["ignore", "pipe", "ignore"],
19
+ detached: true,
20
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
21
+ });
22
+ const closed = Promise.withResolvers();
23
+ let text = "";
24
+ const stop = () => {
25
+ kill(child);
26
+ child.stdout.destroy();
27
+ closed.resolve(null);
28
+ };
29
+ const timer = setTimeout(stop, 30_000);
30
+ tree.signal.addEventListener("abort", stop, { once: true });
31
+ child.stdout.setEncoding("utf8");
32
+ child.stdout.on("data", (chunk) => {
33
+ text += chunk;
34
+ if (Buffer.byteLength(text) > 1_048_576)
35
+ stop();
36
+ });
37
+ child.once("error", () => {
38
+ closed.resolve(null);
39
+ });
40
+ child.once("close", closed.resolve);
41
+ const code = await closed.promise;
42
+ clearTimeout(timer);
43
+ tree.signal.removeEventListener("abort", stop);
44
+ return { text: text.trim(), code };
45
+ }
46
+ export async function turnHead(tree) {
47
+ const head = await retryGit(tree, ["rev-parse", "--verify", "HEAD"]);
48
+ return head.code === 0 && /^[a-f0-9]{40,64}$/.test(head.text)
49
+ ? head.text
50
+ : null;
51
+ }
52
+ async function remoteState(tree) {
53
+ const branch = await retryGit(tree, ["symbolic-ref", "--short", "HEAD"]);
54
+ if (branch.code !== 0 || tree.signal.aborted)
55
+ return "unknown";
56
+ const reference = `refs/heads/${branch.text}`;
57
+ const remote = await retryGit(tree, [
58
+ "ls-remote",
59
+ "--exit-code",
60
+ "--heads",
61
+ "origin",
62
+ reference,
63
+ ]);
64
+ if (remote.code === 2)
65
+ return "not pushed";
66
+ if (remote.code !== 0)
67
+ return "unknown";
68
+ const tracking = `refs/remotes/origin/${branch.text}`;
69
+ const fetched = await retryGit(tree, [
70
+ "fetch",
71
+ "--no-tags",
72
+ "origin",
73
+ `+${reference}:${tracking}`,
74
+ ]);
75
+ return fetched.code === 0 ? tracking : "unknown";
76
+ }
77
+ async function pushState(tree, evidence) {
78
+ const { commit, remote } = evidence;
79
+ if (!remote.startsWith("refs/"))
80
+ return remote;
81
+ const ancestor = await retryGit(tree, [
82
+ "merge-base",
83
+ "--is-ancestor",
84
+ commit,
85
+ remote,
86
+ ]);
87
+ if (ancestor.code === 1)
88
+ return "not pushed";
89
+ return ancestor.code === 0 ? "pushed" : "unknown";
90
+ }
91
+ export async function retryEvidence(tree, startCommit) {
92
+ const remote = await remoteState(tree);
93
+ if (startCommit === null || tree.signal.aborted)
94
+ return "unknown: commits since the start of this turn could not be determined.";
95
+ const commits = await retryGit(tree, [
96
+ "log",
97
+ "--format=%H %s",
98
+ `${startCommit}..HEAD`,
99
+ "--",
100
+ ]);
101
+ if (commits.code !== 0)
102
+ return "unknown: commits since the start of this turn could not be listed.";
103
+ const lines = [];
104
+ for (const line of commits.text.split("\n").filter(Boolean)) {
105
+ const commit = line.split(" ")[0] ?? "";
106
+ const state = await pushState(tree, { commit, remote });
107
+ lines.push(`${commit} ${state}${line.slice(commit.length)}`);
108
+ }
109
+ if (lines.length > 0)
110
+ return lines.join("\n");
111
+ return remote === "unknown"
112
+ ? "unknown: remote push state could not be determined; no local commits since the start of this turn."
113
+ : "No commits since the start of this turn.";
114
+ }
115
+ export async function indexFailure(tree) {
116
+ const lookup = await retryGit(tree, [
117
+ "rev-parse",
118
+ "--git-path",
119
+ "index.lock",
120
+ ]);
121
+ const unknown = {
122
+ reason: "worktree-index-unknown",
123
+ fix: "Check that the work tree and its git index path are accessible before starting another turn.",
124
+ };
125
+ if (lookup.code !== 0 || lookup.text === "")
126
+ return unknown;
127
+ const lockPath = resolve(tree.directory, lookup.text);
128
+ try {
129
+ await lstat(lockPath);
130
+ return {
131
+ reason: "worktree-index-locked",
132
+ lockPath,
133
+ fix: "Remove the index lock when no git process uses the work tree, then start another turn.",
134
+ };
135
+ }
136
+ catch (error) {
137
+ return Reflect.get(Object(error), "code") === "ENOENT" ? null : unknown;
138
+ }
139
+ }
@@ -1,8 +1,13 @@
1
+ import { type TokenPrices } from "../token-prices.ts";
1
2
  import { type RunningTurn, type TurnStart } from "./claude-turn.ts";
2
3
  export interface RetrySettings {
4
+ readonly tokenPrices?: TokenPrices;
5
+ readonly fallbackModels?: readonly string[];
3
6
  readonly retryDelay?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
4
7
  }
5
8
  interface RetryOptions extends RetrySettings {
9
+ readonly stopping?: AbortController;
10
+ readonly stopMilliseconds?: number;
6
11
  readonly metadata: Readonly<Record<string, unknown>>;
7
12
  }
8
13
  export declare function startRetriedTurn(start: TurnStart, options: RetryOptions): Promise<RunningTurn>;