cloving 1.3.0 → 1.5.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 (484) hide show
  1. package/README.md +329 -215
  2. package/dist/src/agent-harness-shell.d.ts +2 -1
  3. package/dist/src/agent-harness-shell.js +8 -5
  4. package/dist/src/authority/command-wait-checks.d.ts +8 -0
  5. package/dist/src/authority/command-wait-checks.js +88 -0
  6. package/dist/src/authority/command-wait-results.d.ts +15 -0
  7. package/dist/src/authority/command-wait-results.js +73 -0
  8. package/dist/src/authority/command-wait-view.d.ts +21 -0
  9. package/dist/src/authority/command-wait-view.js +34 -0
  10. package/dist/src/authority/command-waits.d.ts +39 -0
  11. package/dist/src/authority/command-waits.js +97 -0
  12. package/dist/src/authority/commands.js +22 -1
  13. package/dist/src/authority/dispatch-decision.d.ts +8 -0
  14. package/dist/src/authority/dispatch-decision.js +26 -1
  15. package/dist/src/authority/effect-requests.js +6 -3
  16. package/dist/src/authority/effect-results.js +4 -2
  17. package/dist/src/authority/history-state.d.ts +2 -0
  18. package/dist/src/authority/history-state.js +13 -1
  19. package/dist/src/authority/instants.d.ts +1 -0
  20. package/dist/src/authority/instants.js +21 -0
  21. package/dist/src/authority/reduction-state.d.ts +2 -0
  22. package/dist/src/authority/reduction-state.js +5 -0
  23. package/dist/src/authority/reduction.js +24 -0
  24. package/dist/src/authority/status-input.d.ts +2 -0
  25. package/dist/src/authority/status.d.ts +2 -0
  26. package/dist/src/authority/status.js +1 -0
  27. package/dist/src/authority/stop-sequence.d.ts +1 -0
  28. package/dist/src/authority/stop-sequence.js +2 -1
  29. package/dist/src/authority/transitions.d.ts +6 -4
  30. package/dist/src/authority/transitions.js +7 -0
  31. package/dist/src/broker/actor/authority-health.d.ts +9 -0
  32. package/dist/src/broker/actor/authority-health.js +24 -0
  33. package/dist/src/broker/actor/authority-queries.d.ts +2 -1
  34. package/dist/src/broker/actor/authority-queries.js +14 -5
  35. package/dist/src/broker/actor/authority-receipts.js +1 -1
  36. package/dist/src/broker/actor/authority-runtime.d.ts +4 -2
  37. package/dist/src/broker/actor/authority-runtime.js +29 -20
  38. package/dist/src/broker/actor/authority-session.d.ts +6 -19
  39. package/dist/src/broker/actor/authority-session.js +66 -88
  40. package/dist/src/broker/actor/authority-settings.d.ts +2 -1
  41. package/dist/src/broker/actor/authority-settings.js +6 -3
  42. package/dist/src/broker/actor/authority-upgrades.d.ts +23 -2
  43. package/dist/src/broker/actor/authority-upgrades.js +8 -2
  44. package/dist/src/broker/actor/authority-watchdog.d.ts +6 -2
  45. package/dist/src/broker/actor/authority-watchdog.js +31 -9
  46. package/dist/src/broker/actor/authority.js +3 -1
  47. package/dist/src/broker/actor/delivery-intents.js +2 -0
  48. package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
  49. package/dist/src/broker/actor/effect-delivery.js +15 -2
  50. package/dist/src/broker/actor/effect-plan.js +11 -2
  51. package/dist/src/broker/actor/effect-queries.d.ts +4 -0
  52. package/dist/src/broker/actor/effect-queries.js +9 -1
  53. package/dist/src/broker/actor/effect-turn.js +2 -0
  54. package/dist/src/broker/actor/projection-memory.d.ts +43 -0
  55. package/dist/src/broker/actor/projection-memory.js +207 -0
  56. package/dist/src/broker/actor/runtime-parts.d.ts +5 -0
  57. package/dist/src/broker/actor/runtime-parts.js +8 -3
  58. package/dist/src/broker/actor/stop-plan.js +9 -3
  59. package/dist/src/broker/actor/stop-turn.d.ts +2 -0
  60. package/dist/src/broker/actor/stop-turn.js +24 -11
  61. package/dist/src/broker/actor/turn-draft.d.ts +1 -0
  62. package/dist/src/broker/actor/turn-draft.js +4 -0
  63. package/dist/src/broker/actor/turn-state.js +5 -1
  64. package/dist/src/broker/authority-admission.js +60 -0
  65. package/dist/src/broker/authority-restore.d.ts +2 -0
  66. package/dist/src/broker/authority-restore.js +35 -1
  67. package/dist/src/broker/command-wait-restore.d.ts +31 -0
  68. package/dist/src/broker/command-wait-restore.js +86 -0
  69. package/dist/src/broker/decision-restore.d.ts +1 -1
  70. package/dist/src/broker/decision-restore.js +1 -0
  71. package/dist/src/broker/effect-upgrade.d.ts +3 -0
  72. package/dist/src/broker/effect-upgrade.js +11 -2
  73. package/dist/src/cli/arguments.d.ts +13 -0
  74. package/dist/src/cli/arguments.js +43 -3
  75. package/dist/src/cli/chat-stores.d.ts +2 -0
  76. package/dist/src/cli/chat-stores.js +113 -0
  77. package/dist/src/cli/client.d.ts +7 -2
  78. package/dist/src/cli/client.js +13 -7
  79. package/dist/src/cli/command-requests.d.ts +46 -0
  80. package/dist/src/cli/command-requests.js +84 -0
  81. package/dist/src/cli/command-waits.d.ts +9 -0
  82. package/dist/src/cli/command-waits.js +51 -0
  83. package/dist/src/cli/commands.js +70 -88
  84. package/dist/src/cli/config-file.d.ts +2 -2
  85. package/dist/src/cli/config-file.js +4 -2
  86. package/dist/src/cli/config-notice.js +5 -2
  87. package/dist/src/cli/doctor-retention.d.ts +2 -0
  88. package/dist/src/cli/doctor-retention.js +93 -0
  89. package/dist/src/cli/doctor-workflows.d.ts +5 -2
  90. package/dist/src/cli/doctor-workflows.js +12 -7
  91. package/dist/src/cli/doctor.js +11 -9
  92. package/dist/src/cli/harness-probes.d.ts +2 -0
  93. package/dist/src/cli/harness-probes.js +1 -1
  94. package/dist/src/cli/harness-processes.d.ts +6 -0
  95. package/dist/src/cli/harness-processes.js +36 -0
  96. package/dist/src/cli/init-command.d.ts +9 -0
  97. package/dist/src/cli/init-command.js +52 -0
  98. package/dist/src/cli/init-prompt-command.d.ts +10 -0
  99. package/dist/src/cli/init-prompt-command.js +145 -0
  100. package/dist/src/cli/init-prompt.d.ts +35 -0
  101. package/dist/src/cli/init-prompt.js +74 -0
  102. package/dist/src/cli/init-selection.d.ts +13 -0
  103. package/dist/src/cli/init-selection.js +75 -0
  104. package/dist/src/cli/main.d.ts +2 -0
  105. package/dist/src/cli/main.js +37 -7
  106. package/dist/src/cli/mcp-server.d.ts +1 -0
  107. package/dist/src/cli/mcp-server.js +156 -0
  108. package/dist/src/cli/mcp-tools.d.ts +15 -0
  109. package/dist/src/cli/mcp-tools.js +242 -0
  110. package/dist/src/cli/queue-arguments.d.ts +15 -0
  111. package/dist/src/cli/queue-arguments.js +31 -0
  112. package/dist/src/cli/queue-render.d.ts +3 -0
  113. package/dist/src/cli/queue-render.js +26 -0
  114. package/dist/src/cli/reload-render.d.ts +2 -0
  115. package/dist/src/cli/reload-render.js +12 -0
  116. package/dist/src/cli/render.d.ts +1 -1
  117. package/dist/src/cli/render.js +54 -38
  118. package/dist/src/cli/report-ci-jobs.d.ts +23 -0
  119. package/dist/src/cli/report-ci-jobs.js +103 -0
  120. package/dist/src/cli/report-ci-usage.d.ts +9 -0
  121. package/dist/src/cli/report-ci-usage.js +185 -0
  122. package/dist/src/cli/report-ci.d.ts +13 -0
  123. package/dist/src/cli/report-ci.js +74 -0
  124. package/dist/src/cli/report-closures.d.ts +6 -0
  125. package/dist/src/cli/report-closures.js +97 -0
  126. package/dist/src/cli/report-flow.d.ts +7 -0
  127. package/dist/src/cli/report-flow.js +122 -0
  128. package/dist/src/cli/report-github-reader.d.ts +29 -0
  129. package/dist/src/cli/report-github-reader.js +157 -0
  130. package/dist/src/cli/report-github.d.ts +15 -8
  131. package/dist/src/cli/report-github.js +131 -150
  132. package/dist/src/cli/report-operator.d.ts +3 -0
  133. package/dist/src/cli/report-operator.js +40 -0
  134. package/dist/src/cli/report-ready.d.ts +3 -0
  135. package/dist/src/cli/report-ready.js +96 -0
  136. package/dist/src/cli/report-text.d.ts +9 -0
  137. package/dist/src/cli/report-text.js +33 -0
  138. package/dist/src/cli/report.d.ts +1 -0
  139. package/dist/src/cli/report.js +104 -27
  140. package/dist/src/cli/runtime-arguments.d.ts +18 -3
  141. package/dist/src/cli/runtime-arguments.js +29 -20
  142. package/dist/src/cli/schedule-arguments.d.ts +14 -0
  143. package/dist/src/cli/schedule-arguments.js +26 -0
  144. package/dist/src/cli/schedule-render.d.ts +22 -0
  145. package/dist/src/cli/schedule-render.js +73 -0
  146. package/dist/src/cli/terminal-text.d.ts +3 -0
  147. package/dist/src/cli/terminal-text.js +28 -0
  148. package/dist/src/cli/toolchain.d.ts +1 -0
  149. package/dist/src/cli/toolchain.js +1 -0
  150. package/dist/src/cli/usage-render.d.ts +1 -0
  151. package/dist/src/cli/usage-render.js +28 -1
  152. package/dist/src/cli/usage.d.ts +2 -2
  153. package/dist/src/cli/usage.js +89 -11
  154. package/dist/src/cli/watch-actions.js +2 -2
  155. package/dist/src/cli/watch-api-document.d.ts +430 -0
  156. package/dist/src/cli/watch-api-document.js +291 -0
  157. package/dist/src/cli/watch-api-run.d.ts +56 -0
  158. package/dist/src/cli/watch-api-run.js +112 -0
  159. package/dist/src/cli/watch-api.d.ts +17 -0
  160. package/dist/src/cli/watch-api.js +230 -0
  161. package/dist/src/cli/watch-board-view.js +19 -2
  162. package/dist/src/cli/watch-board.d.ts +4 -2
  163. package/dist/src/cli/watch-board.js +53 -43
  164. package/dist/src/cli/watch-card-forms.d.ts +1 -1
  165. package/dist/src/cli/watch-card-forms.js +11 -10
  166. package/dist/src/cli/watch-client.d.ts +1 -1
  167. package/dist/src/cli/watch-client.js +2 -11
  168. package/dist/src/cli/watch-header-view.d.ts +1 -5
  169. package/dist/src/cli/watch-header-view.js +17 -21
  170. package/dist/src/cli/watch-model.d.ts +5 -1
  171. package/dist/src/cli/watch-model.js +20 -11
  172. package/dist/src/cli/watch-page.js +15 -15
  173. package/dist/src/cli/watch-phases.d.ts +12 -3
  174. package/dist/src/cli/watch-phases.js +68 -11
  175. package/dist/src/cli/watch-pr-board.js +1 -1
  176. package/dist/src/cli/watch-pr-command.d.ts +1 -0
  177. package/dist/src/cli/watch-pull-request.js +18 -8
  178. package/dist/src/cli/watch-reads.d.ts +3 -0
  179. package/dist/src/cli/watch-reads.js +22 -20
  180. package/dist/src/cli/watch-render.d.ts +15 -0
  181. package/dist/src/cli/watch-run-input.d.ts +0 -1
  182. package/dist/src/cli/watch-run-input.js +0 -13
  183. package/dist/src/cli/watch-server.js +24 -10
  184. package/dist/src/cli/watch-view.d.ts +0 -3
  185. package/dist/src/cli/watch-view.js +13 -13
  186. package/dist/src/cli.js +73 -12
  187. package/dist/src/command-wait.d.ts +4 -0
  188. package/dist/src/command-wait.js +45 -0
  189. package/dist/src/configuration-change.d.ts +7 -0
  190. package/dist/src/configuration-change.js +14 -0
  191. package/dist/src/configuration-display.js +2 -0
  192. package/dist/src/configuration-schema.d.ts +14 -0
  193. package/dist/src/configuration-schema.js +6 -2
  194. package/dist/src/daemon/attachment-file.d.ts +6 -0
  195. package/dist/src/daemon/attachment-file.js +86 -0
  196. package/dist/src/daemon/attachments.d.ts +14 -0
  197. package/dist/src/daemon/attachments.js +17 -0
  198. package/dist/src/daemon/claude-recovery.d.ts +50 -0
  199. package/dist/src/daemon/claude-recovery.js +208 -0
  200. package/dist/src/daemon/claude-stream.d.ts +27 -0
  201. package/dist/src/daemon/claude-stream.js +63 -0
  202. package/dist/src/daemon/claude-turn.d.ts +11 -25
  203. package/dist/src/daemon/claude-turn.js +64 -81
  204. package/dist/src/daemon/claude-worker.d.ts +5 -4
  205. package/dist/src/daemon/claude-worker.js +127 -126
  206. package/dist/src/daemon/daemon-adapters.d.ts +9 -0
  207. package/dist/src/daemon/daemon-adapters.js +33 -5
  208. package/dist/src/daemon/daemon-loops.d.ts +5 -1
  209. package/dist/src/daemon/daemon-loops.js +18 -10
  210. package/dist/src/daemon/daemon.js +80 -61
  211. package/dist/src/daemon/github-attach.d.ts +2 -0
  212. package/dist/src/daemon/github-attach.js +222 -0
  213. package/dist/src/daemon/github-calls.js +1 -1
  214. package/dist/src/daemon/github-ci-filters.d.ts +6 -0
  215. package/dist/src/daemon/github-ci-filters.js +138 -0
  216. package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
  217. package/dist/src/daemon/github-ci-workflows.js +148 -0
  218. package/dist/src/daemon/github-ci.js +22 -4
  219. package/dist/src/daemon/github-issue-methods.d.ts +2 -0
  220. package/dist/src/daemon/github-issue-methods.js +37 -2
  221. package/dist/src/daemon/github-merge-call.d.ts +2 -1
  222. package/dist/src/daemon/github-merge-call.js +10 -3
  223. package/dist/src/daemon/github-merge.js +52 -24
  224. package/dist/src/daemon/github-methods.js +18 -4
  225. package/dist/src/daemon/github-operation.d.ts +4 -0
  226. package/dist/src/daemon/github-operation.js +6 -0
  227. package/dist/src/daemon/github-worker.d.ts +4 -0
  228. package/dist/src/daemon/github-worker.js +6 -0
  229. package/dist/src/daemon/issue-queue.d.ts +4 -1
  230. package/dist/src/daemon/issue-queue.js +76 -78
  231. package/dist/src/daemon/merge-turns.d.ts +10 -0
  232. package/dist/src/daemon/merge-turns.js +37 -0
  233. package/dist/src/daemon/notify-events.d.ts +6 -0
  234. package/dist/src/daemon/notify-events.js +84 -0
  235. package/dist/src/daemon/notify-journal.js +1 -1
  236. package/dist/src/daemon/notify-message.d.ts +4 -1
  237. package/dist/src/daemon/notify-message.js +36 -0
  238. package/dist/src/daemon/notify.d.ts +1 -1
  239. package/dist/src/daemon/notify.js +5 -77
  240. package/dist/src/daemon/operation-journal.d.ts +1 -0
  241. package/dist/src/daemon/queue-control.d.ts +13 -0
  242. package/dist/src/daemon/queue-control.js +86 -0
  243. package/dist/src/daemon/queue-journal.d.ts +20 -0
  244. package/dist/src/daemon/queue-journal.js +89 -0
  245. package/dist/src/daemon/queue-status.d.ts +9 -3
  246. package/dist/src/daemon/queue-status.js +17 -4
  247. package/dist/src/daemon/record-archive.d.ts +19 -0
  248. package/dist/src/daemon/record-archive.js +82 -0
  249. package/dist/src/daemon/record-sweep.d.ts +24 -0
  250. package/dist/src/daemon/record-sweep.js +147 -0
  251. package/dist/src/daemon/resume-index-lock.d.ts +13 -0
  252. package/dist/src/daemon/resume-index-lock.js +160 -0
  253. package/dist/src/daemon/resume-worktree.d.ts +7 -0
  254. package/dist/src/daemon/resume-worktree.js +29 -0
  255. package/dist/src/daemon/retrying-turn.d.ts +2 -12
  256. package/dist/src/daemon/retrying-turn.js +98 -172
  257. package/dist/src/daemon/schedule-control.d.ts +26 -0
  258. package/dist/src/daemon/schedule-control.js +110 -0
  259. package/dist/src/daemon/schedule-journal.d.ts +2 -15
  260. package/dist/src/daemon/schedule-journal.js +67 -4
  261. package/dist/src/daemon/settings-reload.d.ts +26 -0
  262. package/dist/src/daemon/settings-reload.js +82 -0
  263. package/dist/src/daemon/ticket-registration.d.ts +2 -7
  264. package/dist/src/daemon/ticket-registration.js +15 -81
  265. package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
  266. package/dist/src/daemon/turn-attempt-journal.js +136 -0
  267. package/dist/src/daemon/turn-attempts.d.ts +47 -0
  268. package/dist/src/daemon/turn-attempts.js +166 -0
  269. package/dist/src/daemon/turn-details.d.ts +4 -0
  270. package/dist/src/daemon/turn-details.js +33 -0
  271. package/dist/src/daemon/turn-report.d.ts +8 -1
  272. package/dist/src/daemon/turn-report.js +39 -0
  273. package/dist/src/daemon/work-tree.d.ts +9 -0
  274. package/dist/src/daemon/work-tree.js +20 -0
  275. package/dist/src/daemon/worker-profile.d.ts +9 -0
  276. package/dist/src/daemon/worker-profile.js +44 -0
  277. package/dist/src/daemon/workflow-generations.d.ts +7 -4
  278. package/dist/src/daemon/workflow-generations.js +22 -14
  279. package/dist/src/daemon/workflow-reload.d.ts +41 -0
  280. package/dist/src/daemon/workflow-reload.js +244 -0
  281. package/dist/src/daemon/workflow-replay.d.ts +2 -1
  282. package/dist/src/daemon/workflow-replay.js +7 -3
  283. package/dist/src/daemon/workflow-schedules.d.ts +3 -0
  284. package/dist/src/daemon/workflow-schedules.js +98 -45
  285. package/dist/src/daemon/worktree-processes.d.ts +9 -0
  286. package/dist/src/daemon/worktree-processes.js +151 -0
  287. package/dist/src/doctor-report.d.ts +4 -6
  288. package/dist/src/doctor-report.js +8 -13
  289. package/dist/src/harness-start.d.ts +15 -0
  290. package/dist/src/harness-start.js +37 -0
  291. package/dist/src/host/command-wait.d.ts +38 -0
  292. package/dist/src/host/command-wait.js +115 -0
  293. package/dist/src/host/start-delivery.d.ts +5 -7
  294. package/dist/src/host/start-delivery.js +3 -15
  295. package/dist/src/host/step-bridge-host.d.ts +2 -0
  296. package/dist/src/host/step-bridge-host.js +21 -0
  297. package/dist/src/operation-identity.d.ts +1 -0
  298. package/dist/src/operation-identity.js +4 -0
  299. package/dist/src/private-config.schema.json +71 -0
  300. package/dist/src/project-config.schema.json +40 -0
  301. package/dist/src/project-settings.d.ts +16 -2
  302. package/dist/src/project-settings.js +35 -1
  303. package/dist/src/queue-spend.d.ts +4 -0
  304. package/dist/src/queue-spend.js +21 -0
  305. package/dist/src/queue-state.d.ts +26 -0
  306. package/dist/src/queue-state.js +34 -0
  307. package/dist/src/record-retention.d.ts +46 -0
  308. package/dist/src/record-retention.js +81 -0
  309. package/dist/src/relay/relay-service.d.ts +3 -0
  310. package/dist/src/relay/relay-service.js +5 -3
  311. package/dist/src/report-ci.d.ts +164 -0
  312. package/dist/src/report-ci.js +32 -0
  313. package/dist/src/report-effects.d.ts +15 -0
  314. package/dist/src/report-effects.js +212 -0
  315. package/dist/src/report-flow-types.d.ts +38 -0
  316. package/dist/src/report-flow-types.js +7 -0
  317. package/dist/src/report-flow.d.ts +43 -0
  318. package/dist/src/report-flow.js +193 -0
  319. package/dist/src/report-operator.d.ts +67 -0
  320. package/dist/src/report-operator.js +25 -0
  321. package/dist/src/report-quality.d.ts +221 -0
  322. package/dist/src/report-quality.js +94 -0
  323. package/dist/src/report-ready.d.ts +23 -0
  324. package/dist/src/report-ready.js +117 -0
  325. package/dist/src/report-statistics.d.ts +2 -1
  326. package/dist/src/report-statistics.js +40 -4
  327. package/dist/src/report.d.ts +588 -47
  328. package/dist/src/report.js +156 -41
  329. package/dist/src/schedule-progress.d.ts +33 -0
  330. package/dist/src/schedule-progress.js +45 -0
  331. package/dist/src/service/active-tickets.js +11 -6
  332. package/dist/src/service/command-waits.d.ts +34 -0
  333. package/dist/src/service/command-waits.js +86 -0
  334. package/dist/src/service/dispatcher.d.ts +4 -0
  335. package/dist/src/service/dispatcher.js +33 -0
  336. package/dist/src/service/expiry.js +2 -0
  337. package/dist/src/service/gateway.js +3 -1
  338. package/dist/src/service/queue-handlers.d.ts +4 -0
  339. package/dist/src/service/queue-handlers.js +32 -0
  340. package/dist/src/service/queue-spend.d.ts +6 -0
  341. package/dist/src/service/queue-spend.js +68 -0
  342. package/dist/src/service/registry.d.ts +28 -2
  343. package/dist/src/service/registry.js +48 -0
  344. package/dist/src/service/replies.d.ts +22 -8
  345. package/dist/src/service/replies.js +16 -2
  346. package/dist/src/service/run-handlers.js +37 -12
  347. package/dist/src/service/run-metadata.d.ts +15 -1
  348. package/dist/src/service/run-metadata.js +93 -8
  349. package/dist/src/service/service.d.ts +11 -3
  350. package/dist/src/service/service.js +22 -37
  351. package/dist/src/service/submission-handler.js +18 -4
  352. package/dist/src/service/worker-port.js +9 -1
  353. package/dist/src/service/worker-totals.d.ts +6 -0
  354. package/dist/src/service/worker-totals.js +8 -1
  355. package/dist/src/service/workflow-reload.d.ts +35 -0
  356. package/dist/src/service/workflow-reload.js +52 -0
  357. package/dist/src/step-bridge.d.ts +20 -0
  358. package/dist/src/steps/command-wait.d.ts +12 -0
  359. package/dist/src/steps/command-wait.js +26 -0
  360. package/dist/src/steps/open-decision-wait.d.ts +2 -0
  361. package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
  362. package/dist/src/steps/review-by-person.js +4 -1
  363. package/dist/src/steps/wait-for-command.d.ts +3 -0
  364. package/dist/src/steps/wait-for-command.js +17 -0
  365. package/dist/src/steps/wait-for-decision.js +1 -1
  366. package/dist/src/storage/command-wait-rows.d.ts +30 -0
  367. package/dist/src/storage/command-wait-rows.js +96 -0
  368. package/dist/src/storage/decision-snapshots.d.ts +8 -2
  369. package/dist/src/storage/decision-snapshots.js +16 -8
  370. package/dist/src/storage/domain-changes.d.ts +3 -1
  371. package/dist/src/storage/domain-changes.js +4 -0
  372. package/dist/src/storage/domain-schema.d.ts +16 -1
  373. package/dist/src/storage/domain-schema.js +35 -4
  374. package/dist/src/storage/effect-schema.d.ts +2 -0
  375. package/dist/src/storage/effect-schema.js +9 -0
  376. package/dist/src/storage/projection-changes.d.ts +12 -0
  377. package/dist/src/storage/projection-changes.js +194 -0
  378. package/dist/src/storage/projection-lookups.d.ts +7 -0
  379. package/dist/src/storage/projection-lookups.js +30 -0
  380. package/dist/src/testing-requests.d.ts +15 -0
  381. package/dist/src/testing-requests.js +93 -0
  382. package/dist/src/testing.d.ts +4 -10
  383. package/dist/src/testing.js +33 -86
  384. package/dist/src/worker-usage.d.ts +1 -0
  385. package/dist/src/worker-usage.js +3 -0
  386. package/dist/src/workflow-candidate.d.ts +1 -0
  387. package/dist/src/workflow-candidate.js +12 -1
  388. package/dist/src/workflow-contracts.d.ts +1 -0
  389. package/dist/src/workflow-contracts.js +9 -2
  390. package/dist/src/workflow-declaration.d.ts +1 -0
  391. package/dist/src/workflow-declaration.js +3 -0
  392. package/dist/src/workflow-discovery.d.ts +2 -13
  393. package/dist/src/workflow-discovery.js +1 -13
  394. package/dist/src/workflow-refusals.js +0 -1
  395. package/dist/src/workflows.d.ts +1 -1
  396. package/dist/src/workflows.js +1 -1
  397. package/dist/tools/compile-workflows.js +3 -0
  398. package/dist/tools/project-configuration.d.ts +7 -2
  399. package/dist/tools/project-configuration.js +30 -1
  400. package/dist/tools/red-green-command.d.ts +1 -0
  401. package/dist/tools/red-green-command.js +174 -0
  402. package/dist/tools/red-green-process.d.ts +10 -0
  403. package/dist/tools/red-green-process.js +59 -0
  404. package/dist/tools/self-host-processes.d.ts +2 -0
  405. package/dist/tools/self-host-processes.js +69 -26
  406. package/dist/tools/self-host-project.d.ts +2 -0
  407. package/dist/tools/self-host-project.js +30 -77
  408. package/dist/tools/self-host-runtime.js +1 -1
  409. package/dist/tools/self-host.js +76 -34
  410. package/dist/tools/template-command.d.ts +1 -0
  411. package/dist/tools/template-command.js +160 -0
  412. package/dist/tools/template-copy.d.ts +11 -0
  413. package/dist/tools/template-copy.js +130 -0
  414. package/dist/tools/template-files.d.ts +17 -0
  415. package/dist/tools/template-files.js +74 -0
  416. package/dist/tools/workflow-bundles.js +1 -0
  417. package/dist/tools/workflow-candidate-counts.js +2 -2
  418. package/dist/tools/workflow-candidate-program.d.ts +4 -2
  419. package/dist/tools/workflow-candidate-program.js +30 -11
  420. package/dist/tools/workflow-candidate-shape.d.ts +3 -0
  421. package/dist/tools/workflow-candidate-shape.js +90 -0
  422. package/dist/tools/workflow-candidate-source.d.ts +1 -0
  423. package/dist/tools/workflow-candidate-source.js +26 -4
  424. package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
  425. package/dist/tools/workflow-candidate-syntax.js +24 -94
  426. package/dist/tools/workflow-command.js +1 -2
  427. package/dist/tools/workflow-folders.d.ts +2 -3
  428. package/dist/tools/workflow-folders.js +1 -1
  429. package/package.json +17 -9
  430. package/templates/develop/README.md +93 -4
  431. package/templates/develop/develop/flow-tests.ts +38 -1
  432. package/templates/develop/develop/interruption-tests.ts +157 -0
  433. package/templates/develop/develop/local.ts +1 -0
  434. package/templates/develop/develop/option-tests.ts +138 -9
  435. package/templates/develop/develop/pull.ts +5 -1
  436. package/templates/develop/develop/red-green.ts +55 -0
  437. package/templates/develop/develop/refusal-tests.ts +77 -0
  438. package/templates/develop/develop/report.ts +31 -11
  439. package/templates/develop/develop/round.ts +1 -0
  440. package/templates/develop/develop/scenarios.ts +27 -0
  441. package/templates/develop/develop/turn.ts +28 -7
  442. package/templates/develop/develop.declaration.json +1 -1
  443. package/templates/develop/develop.test.ts +4 -0
  444. package/templates/develop/template.json +29 -2
  445. package/templates/idea-to-issue/README.md +27 -0
  446. package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
  447. package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
  448. package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
  449. package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
  450. package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
  451. package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
  452. package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
  453. package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
  454. package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
  455. package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
  456. package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
  457. package/templates/idea-to-issue/idea-to-issue.ts +49 -0
  458. package/templates/idea-to-issue/template.json +81 -0
  459. package/templates/review-day/README.md +97 -0
  460. package/templates/review-day/review-day/critique.ts +58 -0
  461. package/templates/review-day/review-day/decision.ts +29 -0
  462. package/templates/review-day/review-day/facts.ts +69 -0
  463. package/templates/review-day/review-day/label.ts +29 -0
  464. package/templates/review-day/review-day/next.ts +28 -0
  465. package/templates/review-day/review-day/post.ts +27 -0
  466. package/templates/review-day/review-day/report.ts +98 -0
  467. package/templates/review-day/review-day/rules.ts +12 -0
  468. package/templates/review-day/review-day/scenarios.ts +76 -0
  469. package/templates/review-day/review-day/turn.ts +73 -0
  470. package/templates/review-day/review-day.declaration.json +16 -0
  471. package/templates/review-day/review-day.test.ts +362 -0
  472. package/templates/review-day/review-day.ts +37 -0
  473. package/templates/review-day/template.json +56 -0
  474. package/dist/src/cli/watch-start-view.d.ts +0 -18
  475. package/dist/src/cli/watch-start-view.js +0 -77
  476. package/dist/src/steps/decision-gate.d.ts +0 -3
  477. package/dist/workflows/develop-prd.d.ts +0 -7
  478. package/dist/workflows/develop-prd.js +0 -165
  479. package/dist/workflows/develop-ticket.d.ts +0 -9
  480. package/dist/workflows/develop-ticket.js +0 -207
  481. package/dist/workflows/issue-labels.d.ts +0 -16
  482. package/dist/workflows/issue-labels.js +0 -70
  483. package/dist/workflows/ticket-prompts.d.ts +0 -35
  484. package/dist/workflows/ticket-prompts.js +0 -147
@@ -0,0 +1,82 @@
1
+ import { turnHarness } from "../harness-defaults.js";
2
+ import { reloadedSettingFields, } from "../project-settings.js";
3
+ import { record } from "../protocol.js";
4
+ import { parseFallbackModels, parseTokenPrices } from "../token-prices.js";
5
+ import { isProfilesFile } from "../turn-profile.js";
6
+ import { checkedProfiles } from "./worker-profile.js";
7
+ export function turnSettingsSource(initial) {
8
+ let current = initial;
9
+ return {
10
+ current: () => current,
11
+ replace: (next) => {
12
+ current = next;
13
+ },
14
+ };
15
+ }
16
+ function turnSettingsOf(value) {
17
+ const fields = record(value) ?? {};
18
+ const profiles = { profiles: fields["profiles"] };
19
+ if (!isProfilesFile(profiles))
20
+ return undefined;
21
+ try {
22
+ return {
23
+ profiles: profiles.profiles,
24
+ fallbackModels: parseFallbackModels(JSON.stringify(fields["fallbackModels"])),
25
+ tokenPrices: parseTokenPrices(JSON.stringify(fields["tokenPrices"])),
26
+ };
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ }
32
+ function digestsOf(value) {
33
+ const fields = record(value);
34
+ if (fields === undefined)
35
+ return undefined;
36
+ const entries = Object.entries(fields);
37
+ const digests = entries.filter((entry) => typeof entry[1] === "string");
38
+ return digests.length === entries.length
39
+ ? Object.fromEntries(digests)
40
+ : undefined;
41
+ }
42
+ export function reloadedSettings(output) {
43
+ const turnSettings = turnSettingsOf(output?.["turnSettings"]);
44
+ const settingDigests = digestsOf(output?.["settingDigests"]);
45
+ return turnSettings === undefined || settingDigests === undefined
46
+ ? undefined
47
+ : { turnSettings, settingDigests };
48
+ }
49
+ export function settingChanges(current, next) {
50
+ const changed = [...new Set([...Object.keys(current), ...Object.keys(next)])]
51
+ .filter((field) => current[field] !== next[field])
52
+ .sort();
53
+ return {
54
+ reloadedFields: changed.filter((field) => reloadedSettingFields.includes(field)),
55
+ restartFields: changed.filter((field) => !reloadedSettingFields.includes(field)),
56
+ };
57
+ }
58
+ export function keptDigests(current, change) {
59
+ return {
60
+ ...current,
61
+ ...Object.fromEntries(Object.entries(change.digests).filter(([field]) => change.reloadedFields.includes(field))),
62
+ };
63
+ }
64
+ function newHarness(settings, profiles) {
65
+ const started = new Set([{}, ...Object.values(settings.profiles ?? {})].map((profile) => turnHarness(settings, profile).worker));
66
+ return Object.values(profiles)
67
+ .map((profile) => turnHarness(settings, profile).worker)
68
+ .find((name) => !started.has(name));
69
+ }
70
+ export function profileRefusal(settings, turnSettings) {
71
+ try {
72
+ checkedProfiles(settings, turnSettings.profiles);
73
+ }
74
+ catch (error) {
75
+ const detail = String(Reflect.get(Object(error), "message"));
76
+ return { code: detail.replace(/:.*$/s, ""), detail };
77
+ }
78
+ const added = newHarness(settings, turnSettings.profiles);
79
+ return added === undefined
80
+ ? undefined
81
+ : { code: "harness-no-worker", detail: `harness-no-worker: ${added}` };
82
+ }
@@ -1,10 +1,7 @@
1
1
  import { type DeclaredWorkflow } from "../workflow-declaration.ts";
2
2
  import type { Resolver, WorkflowRegistration } from "../service/registry.ts";
3
+ import { type SubmissionContract } from "../submission.ts";
3
4
  import type { LocalCommands } from "../command-settings.ts";
4
- export declare const ticketWorkflow: "develop-ticket";
5
- export declare const promptWorkflow: "develop-prompt";
6
- export declare const issueWorkflow: "develop-issue";
7
- export declare const ticketCapabilities: string[];
8
5
  export type TicketRegistrations = {
9
6
  readonly kind: "admitted";
10
7
  readonly registrations: readonly WorkflowRegistration[];
@@ -24,10 +21,8 @@ export interface TicketRegistration extends Omit<WorkflowRegistration, "manifest
24
21
  readonly effectLimit: number;
25
22
  readonly capabilities?: readonly string[];
26
23
  }
27
- export declare function ticketResolver(source: TicketSource): Resolver;
28
- export declare function issueResolver(source: TicketSource): Resolver;
29
- export declare function promptResolver(repository: string): Resolver;
30
24
  export declare function ticketRegistrationTable(source: TicketSource, declarations?: readonly DeclaredWorkflow[]): readonly TicketRegistration[];
25
+ export declare function declaredResolver(source: TicketSource, contract: SubmissionContract): Resolver;
31
26
  export declare function ticketRegistrations(manifests: Readonly<Record<string, string | undefined>>, options: {
32
27
  readonly table: readonly TicketRegistration[];
33
28
  readonly bundleDigest?: string;
@@ -1,45 +1,34 @@
1
- import { createHash } from "node:crypto";
2
1
  import { admitCompiled } from "../cli/validate.js";
3
2
  import { isCommandWaits, workflowQueueRefusals, } from "../workflow-declaration.js";
4
3
  import { ticketCommandText, ticketText } from "./ticket-source.js";
5
4
  import { declaredInput } from "./declared-input.js";
6
- import { bundledWorkflowIds } from "../workflow-discovery.js";
7
5
  import { declaredManifest } from "../execution-pin.js";
8
6
  import { record } from "../protocol.js";
9
7
  import { hasTicketField } from "../submission.js";
10
8
  import { issueIdentity } from "../issue-identity.js";
11
9
  import { ticketDependencyWaits, TicketDependencyReadError, } from "./ticket-dependency-waits.js";
12
- export const ticketWorkflow = bundledWorkflowIds.ticket;
13
- export const promptWorkflow = bundledWorkflowIds.prompt;
14
- export const issueWorkflow = bundledWorkflowIds.issue;
15
- export const ticketCapabilities = ["claude", "github"];
10
+ const defaultCapabilities = ["claude", "github"];
16
11
  const ticketIdentifier = /^[A-Za-z0-9._:-]{1,64}$/;
17
12
  function rejected(code, detail) {
18
13
  return { kind: "rejected", code, detail };
19
14
  }
20
- function digest(commandId) {
21
- return createHash("sha256").update(commandId).digest("hex");
22
- }
23
15
  async function ticket(source, request) {
24
- const { command, repository } = source;
16
+ const { command } = source;
25
17
  const ticketId = String(request.submission["ticket"]);
26
18
  if (ticketId === "next")
27
19
  return nextTicket(source, request);
28
20
  if (!ticketIdentifier.test(ticketId))
29
21
  return rejected("invalid-ticket-id", "A ticket ID has letters, digits and the characters . _ : - only.");
30
22
  if (command === undefined)
31
- return rejected("ticket-source-not-configured", "The daemon has no ticket command. Set CLOVING_TICKET_COMMAND, or use the workflow develop-prompt.");
23
+ return rejected("ticket-source-not-configured", "The daemon has no ticket command. Set CLOVING_TICKET_COMMAND.");
32
24
  const read = await ticketText(command, { ticketId, signal: request.signal });
33
25
  if (read.kind === "failed")
34
26
  return rejected("ticket-not-available", read.detail);
35
- const name = ticketId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
36
27
  return {
37
28
  kind: "resolved",
38
29
  input: {
39
- cycleId: `${name}-${digest(request.commandId).slice(0, 8)}`,
40
30
  ticketId,
41
31
  ticket: read.text,
42
- repository,
43
32
  },
44
33
  };
45
34
  }
@@ -63,17 +52,10 @@ async function nextTicket(source, request) {
63
52
  return rejected("invalid-ticket-id", "The next-ticket command must print one valid ticket ID other than next.");
64
53
  return ticket(source, { ...request, submission: { ticket: selected.text } });
65
54
  }
66
- export function ticketResolver(source) {
67
- return {
68
- id: "ticket-command",
69
- version: "1",
70
- resolve: (request) => ticket(source, request),
71
- };
72
- }
73
- export function issueResolver(source) {
55
+ function ticketResolver(source) {
74
56
  const waits = ticketDependencyWaits(source);
75
57
  return {
76
- id: "issue-command",
58
+ id: "ticket-command",
77
59
  version: "1",
78
60
  skippedTickets: waits.skipped,
79
61
  resolve: (request) => issueTicket({ source, waits }, request).catch((error) => {
@@ -107,66 +89,18 @@ async function issueTicket(context, request) {
107
89
  return rejected("ticket-dependency-open", `Ticket ${String(input["ticketId"])} needs open issues: ${dependencies.map((id) => `#${id}`).join(", ")}.`);
108
90
  return {
109
91
  kind: "resolved",
110
- input: { ...input, delivery: "pull-request" },
111
- };
112
- }
113
- export function promptResolver(repository) {
114
- return {
115
- id: "ticket-prompt",
116
- version: "1",
117
- resolve: (request) => Promise.resolve({
118
- kind: "resolved",
119
- input: {
120
- cycleId: `task-${digest(request.commandId).slice(0, 12)}`,
121
- ticket: String(request.submission["prompt"]),
122
- repository,
123
- },
124
- }),
92
+ input,
125
93
  };
126
94
  }
127
95
  export function ticketRegistrationTable(source, declarations = []) {
128
- return [
129
- {
130
- workflowId: ticketWorkflow,
131
- functionName: "developTicket",
132
- effectLimit: 8,
133
- handoffs: [],
134
- submission: { maximumBytes: 4_096, fields: { ticket: "string" } },
135
- resolver: ticketResolver(source),
136
- },
137
- {
138
- workflowId: issueWorkflow,
139
- functionName: "developTicket",
140
- effectLimit: 20,
141
- handoffs: [],
142
- submission: { maximumBytes: 4_096, fields: { ticket: "string" } },
143
- resolver: issueResolver(source),
144
- },
145
- {
146
- workflowId: bundledWorkflowIds.prd,
147
- functionName: "developPrd",
148
- effectLimit: 8,
149
- handoffs: [issueWorkflow],
150
- submission: { maximumBytes: 65_536, fields: { prompt: "string" } },
151
- resolver: promptResolver(source.repository),
152
- },
153
- {
154
- workflowId: promptWorkflow,
155
- functionName: "developTicket",
156
- effectLimit: 8,
157
- handoffs: [],
158
- submission: { maximumBytes: 65_536, fields: { prompt: "string" } },
159
- resolver: promptResolver(source.repository),
160
- },
161
- ...declarations.map(({ input, ...declaration }) => ({
162
- ...declaration,
163
- submission: input,
164
- resolver: declaredResolver(source, input),
165
- })),
166
- ];
96
+ return declarations.map(({ input, ...declaration }) => ({
97
+ ...declaration,
98
+ submission: input,
99
+ resolver: declaredResolver(source, input),
100
+ }));
167
101
  }
168
- function declaredResolver(source, contract) {
169
- const tickets = hasTicketField(contract) ? issueResolver(source) : undefined;
102
+ export function declaredResolver(source, contract) {
103
+ const tickets = hasTicketField(contract) ? ticketResolver(source) : undefined;
170
104
  return {
171
105
  id: "declared-input",
172
106
  version: "1",
@@ -202,7 +136,7 @@ export async function ticketRegistrations(manifests, options) {
202
136
  return { kind: "rejected", detail: refusal };
203
137
  const registrations = [];
204
138
  for (const row of options.table) {
205
- const { functionName, capabilities = ticketCapabilities, ...registration } = row;
139
+ const { functionName, capabilities = defaultCapabilities, ...registration } = row;
206
140
  const manifest = manifests[functionName];
207
141
  if (manifest === undefined)
208
142
  return {
@@ -254,7 +188,7 @@ function registrationRefusal(table, commands) {
254
188
  function commandRegistrationRefusal(row, commands) {
255
189
  if (Object.hasOwn(row, "commandWaits") &&
256
190
  !isCommandWaits(row.commandWaits, {
257
- capabilities: row.capabilities ?? ticketCapabilities,
191
+ capabilities: row.capabilities ?? defaultCapabilities,
258
192
  commands: row.commands ?? [],
259
193
  }))
260
194
  return `invalid-command-waits: ${row.workflowId}`;
@@ -0,0 +1,38 @@
1
+ import { type TurnEnd, type TurnProgress } from "./claude-turn.ts";
2
+ import { attemptCommand, type Attempts } from "./turn-attempts.ts";
3
+ declare function attemptEntry(attempts: Attempts, selected: ReturnType<typeof attemptCommand>): {
4
+ startedAt: string;
5
+ resumedAfter?: "daemon-restart";
6
+ attempt: number;
7
+ fallbackReason?: string;
8
+ budgetUsd?: number;
9
+ turnStartCommit: string | null;
10
+ model: string | null;
11
+ };
12
+ export declare function prepareAttempt(attempts: Attempts): Promise<{
13
+ entry: {
14
+ startedAt: string;
15
+ resumedAfter?: "daemon-restart";
16
+ attempt: number;
17
+ fallbackReason?: string;
18
+ budgetUsd?: number;
19
+ turnStartCommit: string | null;
20
+ model: string | null;
21
+ };
22
+ selected: {
23
+ fallbackReason?: string;
24
+ model: string | null;
25
+ budgetUsd?: number;
26
+ command: readonly string[];
27
+ };
28
+ folder: string;
29
+ } | undefined>;
30
+ export declare function attemptJournal(attempts: Attempts, entry: ReturnType<typeof attemptEntry>): {
31
+ progress: (snapshot: TurnProgress) => Promise<void>;
32
+ running: (identifier: number | null) => Promise<void>;
33
+ };
34
+ export declare function recordedEnd(attempts: Attempts, completion: {
35
+ readonly processId: number | null;
36
+ readonly end: TurnEnd;
37
+ }): Promise<void>;
38
+ export {};
@@ -0,0 +1,136 @@
1
+ import { join } from "node:path";
2
+ import { mkdir } from "node:fs/promises";
3
+ import { readRecord, writeRecord } from "./operation-journal.js";
4
+ import { capacityRefusal, } from "./claude-turn.js";
5
+ import { attemptCommand, attemptUsage, attemptCost, } from "./turn-attempts.js";
6
+ function written(folder, entry) {
7
+ return writeRecord(folder, { ...entry, permissions: "private" });
8
+ }
9
+ function attemptEntry(attempts, selected) {
10
+ const attempt = attempts.ends.length + 1;
11
+ const resume = attempts.options.resume;
12
+ return {
13
+ ...attempts.options.metadata,
14
+ turnStartCommit: attempts.turnStartCommit,
15
+ model: selected.model,
16
+ ...(selected.budgetUsd === undefined
17
+ ? {}
18
+ : { budgetUsd: selected.budgetUsd }),
19
+ ...(selected.fallbackReason === undefined
20
+ ? {}
21
+ : { fallbackReason: selected.fallbackReason }),
22
+ attempt,
23
+ ...(resume !== undefined && attempt === resume.ends.length + 1
24
+ ? { resumedAfter: "daemon-restart" }
25
+ : {}),
26
+ startedAt: attempt === 1 ? attempts.startedAt : new Date().toISOString(),
27
+ };
28
+ }
29
+ export async function prepareAttempt(attempts) {
30
+ const selected = attemptCommand(attempts, attempts.ends.length + 1);
31
+ if (selected.budgetUsd === 0) {
32
+ attempts.failure = "claude-turn-budget-exhausted";
33
+ return undefined;
34
+ }
35
+ const entry = attemptEntry(attempts, selected);
36
+ const folder = entry.attempt === 1
37
+ ? attempts.start.folder
38
+ : join(attempts.start.folder, `attempt-${String(entry.attempt)}`);
39
+ await written(attempts.start.folder, {
40
+ name: "started.json",
41
+ value: {
42
+ ...entry,
43
+ startedAt: attempts.startedAt,
44
+ phase: "starting",
45
+ processId: null,
46
+ },
47
+ });
48
+ await mkdir(folder, { recursive: true, mode: 0o700 });
49
+ return { entry, selected, folder };
50
+ }
51
+ function progressFields(attempts, progress) {
52
+ const result = progress?.result;
53
+ const end = { exitCode: null, result };
54
+ if (result === undefined)
55
+ return {
56
+ sessionId: progress?.sessionId ?? null,
57
+ sessionCostUsd: null,
58
+ costUsd: null,
59
+ };
60
+ return {
61
+ sessionId: progress?.sessionId ?? null,
62
+ sessionCostUsd: result.costUsd,
63
+ costUsd: attemptCost([...attempts.ends, end], attempts.ends.length),
64
+ usage: result.usage,
65
+ turns: result.turns,
66
+ };
67
+ }
68
+ export function attemptJournal(attempts, entry) {
69
+ let saved = Promise.resolve();
70
+ let progress;
71
+ let processId = null;
72
+ const save = () => {
73
+ const value = {
74
+ ...entry,
75
+ phase: "running",
76
+ processId,
77
+ ...progressFields(attempts, progress),
78
+ };
79
+ saved = saved.then(() => written(attempts.start.folder, {
80
+ name: `attempt-${String(entry.attempt)}.json`,
81
+ value,
82
+ }));
83
+ return saved;
84
+ };
85
+ return {
86
+ progress: (snapshot) => {
87
+ progress = snapshot;
88
+ return save();
89
+ },
90
+ running: async (identifier) => {
91
+ processId = identifier;
92
+ await written(attempts.start.folder, {
93
+ name: "started.json",
94
+ value: {
95
+ ...entry,
96
+ startedAt: attempts.startedAt,
97
+ phase: "running",
98
+ processId,
99
+ },
100
+ });
101
+ await save();
102
+ },
103
+ };
104
+ }
105
+ export async function recordedEnd(attempts, completion) {
106
+ const { start, ends, options } = attempts;
107
+ const { processId, end } = completion;
108
+ const attempt = ends.length;
109
+ const selected = attemptCommand(attempts, attempt);
110
+ const name = `attempt-${String(attempt)}.json`;
111
+ const record = await readRecord(start.folder, name);
112
+ const started = typeof record === "object" && record !== null ? record : {};
113
+ const startedAt = Reflect.get(started, "startedAt");
114
+ if (typeof startedAt !== "string")
115
+ throw new Error("attempt-start-time-missing");
116
+ await written(start.folder, {
117
+ name,
118
+ value: {
119
+ ...started,
120
+ ...options.metadata,
121
+ turnStartCommit: attempts.turnStartCommit,
122
+ ...attemptUsage(attempts, { end, attempt }),
123
+ ...(selected.fallbackReason === undefined
124
+ ? {}
125
+ : { fallbackReason: selected.fallbackReason }),
126
+ attempt,
127
+ processId,
128
+ startedAt,
129
+ endedAt: new Date().toISOString(),
130
+ exitCode: end.exitCode,
131
+ capacity: capacityRefusal(end.result),
132
+ sessionCostUsd: end.result?.costUsd ?? null,
133
+ turns: end.result?.turns ?? null,
134
+ },
135
+ });
136
+ }
@@ -0,0 +1,47 @@
1
+ import { usageOf, type WorkerAttemptUsage } from "../worker-usage.ts";
2
+ import { type TokenPrices } from "../token-prices.ts";
3
+ import { type TurnEnd, type TurnStart } from "./claude-turn.ts";
4
+ import type { TurnResume } from "./claude-recovery.ts";
5
+ export interface RetrySettings {
6
+ readonly tokenPrices?: TokenPrices;
7
+ readonly fallbackModels?: readonly string[];
8
+ readonly retryDelay?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
9
+ }
10
+ export interface RetryOptions extends RetrySettings {
11
+ readonly resume?: TurnResume;
12
+ readonly stopping?: AbortController;
13
+ readonly stopMilliseconds?: number;
14
+ readonly metadata: Readonly<Record<string, unknown>>;
15
+ }
16
+ export interface Attempts {
17
+ failure?: string;
18
+ readonly start: TurnStart;
19
+ readonly turnStartCommit: string | null;
20
+ readonly startedAt: string;
21
+ readonly options: RetryOptions;
22
+ readonly stopping: AbortController;
23
+ readonly grace: {
24
+ milliseconds: number;
25
+ };
26
+ readonly ends: TurnEnd[];
27
+ }
28
+ export declare function total(values: readonly (number | null)[]): number | null;
29
+ export declare function combined(attempts: Attempts): TurnEnd;
30
+ export declare function attemptCommand(attempts: Attempts, attempt: number): {
31
+ fallbackReason?: string;
32
+ model: string | null;
33
+ budgetUsd?: number;
34
+ command: readonly string[];
35
+ };
36
+ export declare function attemptUsage(attempts: Attempts, completion: {
37
+ readonly end: TurnEnd;
38
+ readonly attempt: number;
39
+ }): WorkerAttemptUsage;
40
+ export declare function sessionCost(ends: readonly TurnEnd[]): number | null;
41
+ export declare function attemptCost(ends: readonly TurnEnd[], index: number): number | null;
42
+ export declare function attemptEstimate(attempts: Attempts, result: {
43
+ readonly end: TurnEnd;
44
+ readonly model: string | null;
45
+ readonly usage: ReturnType<typeof usageOf>;
46
+ }): number | null;
47
+ export declare function kindOf(attempts: Attempts, end: TurnEnd): import("../worker-usage.ts").RetryKind | null;
@@ -0,0 +1,166 @@
1
+ import { priceOf, sumUsage, usageOf, } from "../worker-usage.js";
2
+ import { commandModel, replaceCommandModel, estimatedCostUsd, priceForModel, } from "../token-prices.js";
3
+ import { capacityRefusal, retryKind, } from "./claude-turn.js";
4
+ import { nativeHarness } from "../harness-defaults.js";
5
+ import { profileCommand } from "../turn-profile.js";
6
+ export function total(values) {
7
+ if (values.includes(null))
8
+ return null;
9
+ return priceOf(values.reduce((sum, value) => sum + (value ?? 0), 0));
10
+ }
11
+ export function combined(attempts) {
12
+ const { ends } = attempts;
13
+ const last = ends.at(-1) ?? { exitCode: null, result: undefined };
14
+ const result = last.result ?? ends.find((end) => end.result)?.result;
15
+ if (result === undefined)
16
+ return last;
17
+ return {
18
+ ...last,
19
+ result: {
20
+ ...result,
21
+ attempts: ends.map((end, index) => attemptUsage(attempts, { end, attempt: index + 1 })),
22
+ ...(last.result === undefined ? { failed: true, text: "" } : {}),
23
+ usage: sumUsage(ends.map((end) => end.result?.usage ?? usageOf(null))),
24
+ costUsd: (attempts.start.worker ?? "claude") === "claude"
25
+ ? sessionCost(ends)
26
+ : total(ends.map((end) => end.result?.costUsd ?? null)),
27
+ turns: total(ends.map((end) => end.result?.turns ?? null)),
28
+ },
29
+ };
30
+ }
31
+ function selectedCommand(attempts, attempt) {
32
+ const { start, options } = attempts;
33
+ const original = start.command;
34
+ const previous = attempts.ends[attempt - 2];
35
+ if (options.resume !== undefined &&
36
+ attempt === options.resume.ends.length + 1) {
37
+ const model = previous?.result?.model;
38
+ return {
39
+ command: model == null ? original : replaceCommandModel(original, model),
40
+ fallback: undefined,
41
+ };
42
+ }
43
+ const ordinal = attempt -
44
+ attempts.ends
45
+ .slice(0, attempt - 1)
46
+ .filter((end) => end.resumedAfter !== undefined).length;
47
+ const fallback = previous !== undefined && kindOf(attempts, previous) === "capacity"
48
+ ? options.fallbackModels?.[ordinal - 3]
49
+ : undefined;
50
+ return {
51
+ command: fallback === undefined
52
+ ? original
53
+ : replaceCommandModel(original, fallback),
54
+ fallback,
55
+ };
56
+ }
57
+ export function attemptCommand(attempts, attempt) {
58
+ const { start } = attempts;
59
+ const { command: selected, fallback } = selectedCommand(attempts, attempt);
60
+ const budgetUsd = remainingBudget(attempts);
61
+ const command = budgetUsd === undefined
62
+ ? selected
63
+ : profileCommand(selected, { maxBudgetUsd: budgetUsd });
64
+ const model = start.output === "text" ? null : commandModel(command);
65
+ return {
66
+ command,
67
+ ...(budgetUsd === undefined ? {} : { budgetUsd }),
68
+ model,
69
+ ...(fallback !== undefined && model === null
70
+ ? { fallbackReason: "fallback-model-unavailable" }
71
+ : {}),
72
+ };
73
+ }
74
+ export function attemptUsage(attempts, completion) {
75
+ const { end, attempt } = completion;
76
+ const result = end.result ?? {
77
+ model: null,
78
+ usage: usageOf(null),
79
+ costUsd: null,
80
+ pricingModel: undefined,
81
+ };
82
+ const model = result.model ?? attemptCommand(attempts, attempt).model;
83
+ const usage = result.usage;
84
+ return {
85
+ attempt,
86
+ ...(end.resumedAfter === undefined
87
+ ? {}
88
+ : { resumedAfter: end.resumedAfter }),
89
+ retryKind: kindOf(attempts, end),
90
+ model,
91
+ ...(end.result?.models === undefined ? {} : { models: end.result.models }),
92
+ usage,
93
+ costUsd: (attempts.start.worker ?? "claude") === "claude"
94
+ ? attemptCost(attempts.ends, attempt - 1)
95
+ : result.costUsd,
96
+ estimatedCostUsd: attemptEstimate(attempts, { end, model, usage }),
97
+ };
98
+ }
99
+ export function sessionCost(ends) {
100
+ const sessions = new Map();
101
+ ends.forEach((end, index) => {
102
+ sessions.set(end.result?.sessionId ?? index, end.result?.costUsd ?? null);
103
+ });
104
+ return total([...sessions.values()]);
105
+ }
106
+ export function attemptCost(ends, index) {
107
+ const result = ends[index]?.result;
108
+ if (result?.costUsd == null)
109
+ return null;
110
+ const earlier = result.sessionId === null
111
+ ? undefined
112
+ : ends
113
+ .slice(0, index)
114
+ .findLast((end) => end.result?.sessionId === result.sessionId);
115
+ if (earlier === undefined)
116
+ return result.costUsd;
117
+ const cost = earlier.result?.costUsd;
118
+ return cost == null
119
+ ? null
120
+ : priceOf(Number((result.costUsd - cost).toFixed(12)));
121
+ }
122
+ function remainingBudget(attempts) {
123
+ if ((attempts.start.worker ?? "claude") !== "claude" ||
124
+ attempts.start.output === "text")
125
+ return undefined;
126
+ const budget = commandBudget(attempts.start.command);
127
+ if (budget === undefined)
128
+ return undefined;
129
+ const spent = sessionCost(attempts.ends);
130
+ return Math.max(0, Number((budget - (spent ?? 0)).toFixed(12)));
131
+ }
132
+ function commandBudget(original) {
133
+ const separator = original.indexOf("--");
134
+ const command = separator < 0 ? original : original.slice(0, separator);
135
+ const index = command.findLastIndex((part) => part === "--max-budget-usd" || part.startsWith("--max-budget-usd="));
136
+ if (index < 0)
137
+ return undefined;
138
+ const argument = command[index] ?? "";
139
+ const budget = Number(argument.includes("=") ? argument.split("=")[1] : command[index + 1]);
140
+ if (!Number.isFinite(budget) || budget < 0)
141
+ return undefined;
142
+ return budget;
143
+ }
144
+ export function attemptEstimate(attempts, result) {
145
+ const worker = attempts.start.worker ?? "claude";
146
+ if (!nativeHarness(worker))
147
+ return null;
148
+ const models = result.end.result?.models;
149
+ const prices = attempts.options.tokenPrices ?? {};
150
+ return estimatedCostUsd(result.usage, worker === "gemini" && models !== undefined
151
+ ? { worker, models, prices }
152
+ : {
153
+ worker,
154
+ price: priceForModel(prices, result.end.result?.pricingModel === undefined
155
+ ? result.model
156
+ : result.end.result.pricingModel),
157
+ });
158
+ }
159
+ export function kindOf(attempts, end) {
160
+ const { worker, output } = attempts.start;
161
+ if (output === "text" || !["claude", "codex"].includes(worker ?? "claude"))
162
+ return null;
163
+ if (worker !== "codex")
164
+ return end.retryKind ?? retryKind(end.result);
165
+ return capacityRefusal(end.result) ? "capacity" : null;
166
+ }
@@ -0,0 +1,4 @@
1
+ import { type SweepSettings } from "./record-sweep.ts";
2
+ import { type RunTurns, type TurnDetails } from "../record-retention.ts";
3
+ export type TurnDetailsSettings = Pick<SweepSettings, "directory" | "retention" | "runs" | "now">;
4
+ export declare function turnDetailsPlace(settings: TurnDetailsSettings): (turns: RunTurns) => Promise<TurnDetails | undefined>;