cloving 1.3.0 → 1.4.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 (396) hide show
  1. package/README.md +235 -206
  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-queries.d.ts +2 -1
  32. package/dist/src/broker/actor/authority-queries.js +14 -5
  33. package/dist/src/broker/actor/authority-receipts.js +1 -1
  34. package/dist/src/broker/actor/authority-settings.js +2 -2
  35. package/dist/src/broker/actor/authority-upgrades.d.ts +19 -2
  36. package/dist/src/broker/actor/authority-upgrades.js +7 -2
  37. package/dist/src/broker/actor/delivery-intents.js +2 -0
  38. package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
  39. package/dist/src/broker/actor/effect-delivery.js +15 -2
  40. package/dist/src/broker/actor/effect-plan.js +11 -2
  41. package/dist/src/broker/actor/effect-queries.d.ts +4 -0
  42. package/dist/src/broker/actor/effect-queries.js +9 -1
  43. package/dist/src/broker/actor/effect-turn.js +2 -0
  44. package/dist/src/broker/actor/stop-plan.js +9 -3
  45. package/dist/src/broker/actor/stop-turn.d.ts +2 -0
  46. package/dist/src/broker/actor/stop-turn.js +24 -11
  47. package/dist/src/broker/actor/turn-draft.d.ts +1 -0
  48. package/dist/src/broker/actor/turn-draft.js +4 -0
  49. package/dist/src/broker/actor/turn-state.js +5 -1
  50. package/dist/src/broker/authority-admission.js +60 -0
  51. package/dist/src/broker/authority-restore.d.ts +2 -0
  52. package/dist/src/broker/authority-restore.js +35 -1
  53. package/dist/src/broker/command-wait-restore.d.ts +31 -0
  54. package/dist/src/broker/command-wait-restore.js +86 -0
  55. package/dist/src/broker/decision-restore.d.ts +1 -1
  56. package/dist/src/broker/decision-restore.js +1 -0
  57. package/dist/src/broker/effect-upgrade.d.ts +2 -0
  58. package/dist/src/broker/effect-upgrade.js +8 -2
  59. package/dist/src/cli/arguments.d.ts +13 -0
  60. package/dist/src/cli/arguments.js +42 -3
  61. package/dist/src/cli/chat-stores.d.ts +2 -0
  62. package/dist/src/cli/chat-stores.js +113 -0
  63. package/dist/src/cli/client.d.ts +4 -1
  64. package/dist/src/cli/client.js +9 -3
  65. package/dist/src/cli/command-requests.d.ts +17 -0
  66. package/dist/src/cli/command-requests.js +43 -0
  67. package/dist/src/cli/command-waits.d.ts +9 -0
  68. package/dist/src/cli/command-waits.js +51 -0
  69. package/dist/src/cli/commands.js +14 -41
  70. package/dist/src/cli/config-file.d.ts +2 -2
  71. package/dist/src/cli/config-file.js +4 -2
  72. package/dist/src/cli/doctor-workflows.d.ts +5 -2
  73. package/dist/src/cli/doctor-workflows.js +12 -7
  74. package/dist/src/cli/doctor.js +6 -9
  75. package/dist/src/cli/harness-probes.d.ts +2 -0
  76. package/dist/src/cli/harness-probes.js +1 -1
  77. package/dist/src/cli/harness-processes.d.ts +6 -0
  78. package/dist/src/cli/harness-processes.js +36 -0
  79. package/dist/src/cli/init-command.d.ts +9 -0
  80. package/dist/src/cli/init-command.js +52 -0
  81. package/dist/src/cli/init-prompt-command.d.ts +10 -0
  82. package/dist/src/cli/init-prompt-command.js +145 -0
  83. package/dist/src/cli/init-prompt.d.ts +35 -0
  84. package/dist/src/cli/init-prompt.js +74 -0
  85. package/dist/src/cli/init-selection.d.ts +13 -0
  86. package/dist/src/cli/init-selection.js +75 -0
  87. package/dist/src/cli/main.d.ts +2 -0
  88. package/dist/src/cli/main.js +37 -7
  89. package/dist/src/cli/mcp-server.d.ts +1 -0
  90. package/dist/src/cli/mcp-server.js +156 -0
  91. package/dist/src/cli/mcp-tools.d.ts +15 -0
  92. package/dist/src/cli/mcp-tools.js +80 -0
  93. package/dist/src/cli/render.d.ts +1 -1
  94. package/dist/src/cli/render.js +17 -30
  95. package/dist/src/cli/report-ci-jobs.d.ts +23 -0
  96. package/dist/src/cli/report-ci-jobs.js +103 -0
  97. package/dist/src/cli/report-ci-usage.d.ts +9 -0
  98. package/dist/src/cli/report-ci-usage.js +185 -0
  99. package/dist/src/cli/report-ci.d.ts +13 -0
  100. package/dist/src/cli/report-ci.js +74 -0
  101. package/dist/src/cli/report-closures.d.ts +6 -0
  102. package/dist/src/cli/report-closures.js +97 -0
  103. package/dist/src/cli/report-flow.d.ts +7 -0
  104. package/dist/src/cli/report-flow.js +122 -0
  105. package/dist/src/cli/report-github-reader.d.ts +29 -0
  106. package/dist/src/cli/report-github-reader.js +157 -0
  107. package/dist/src/cli/report-github.d.ts +15 -8
  108. package/dist/src/cli/report-github.js +131 -150
  109. package/dist/src/cli/report-operator.d.ts +3 -0
  110. package/dist/src/cli/report-operator.js +40 -0
  111. package/dist/src/cli/report-ready.d.ts +3 -0
  112. package/dist/src/cli/report-ready.js +96 -0
  113. package/dist/src/cli/report-text.d.ts +9 -0
  114. package/dist/src/cli/report-text.js +33 -0
  115. package/dist/src/cli/report.d.ts +1 -0
  116. package/dist/src/cli/report.js +104 -27
  117. package/dist/src/cli/runtime-arguments.d.ts +2 -1
  118. package/dist/src/cli/runtime-arguments.js +7 -2
  119. package/dist/src/cli/schedule-arguments.d.ts +14 -0
  120. package/dist/src/cli/schedule-arguments.js +26 -0
  121. package/dist/src/cli/schedule-render.d.ts +22 -0
  122. package/dist/src/cli/schedule-render.js +73 -0
  123. package/dist/src/cli/terminal-text.d.ts +3 -0
  124. package/dist/src/cli/terminal-text.js +28 -0
  125. package/dist/src/cli/usage-render.d.ts +1 -0
  126. package/dist/src/cli/usage-render.js +28 -1
  127. package/dist/src/cli/usage.d.ts +1 -1
  128. package/dist/src/cli/usage.js +50 -7
  129. package/dist/src/cli/watch-actions.js +2 -2
  130. package/dist/src/cli/watch-board-view.js +19 -2
  131. package/dist/src/cli/watch-board.d.ts +4 -2
  132. package/dist/src/cli/watch-board.js +53 -43
  133. package/dist/src/cli/watch-card-forms.d.ts +1 -1
  134. package/dist/src/cli/watch-card-forms.js +11 -10
  135. package/dist/src/cli/watch-client.d.ts +1 -1
  136. package/dist/src/cli/watch-client.js +2 -11
  137. package/dist/src/cli/watch-header-view.d.ts +0 -5
  138. package/dist/src/cli/watch-header-view.js +8 -20
  139. package/dist/src/cli/watch-model.d.ts +4 -1
  140. package/dist/src/cli/watch-model.js +17 -11
  141. package/dist/src/cli/watch-page.js +12 -14
  142. package/dist/src/cli/watch-phases.d.ts +12 -3
  143. package/dist/src/cli/watch-phases.js +68 -11
  144. package/dist/src/cli/watch-pr-board.js +1 -1
  145. package/dist/src/cli/watch-pr-command.d.ts +1 -0
  146. package/dist/src/cli/watch-pull-request.js +18 -8
  147. package/dist/src/cli/watch-reads.d.ts +2 -0
  148. package/dist/src/cli/watch-reads.js +17 -16
  149. package/dist/src/cli/watch-render.d.ts +14 -0
  150. package/dist/src/cli/watch-run-input.d.ts +0 -1
  151. package/dist/src/cli/watch-run-input.js +0 -13
  152. package/dist/src/cli/watch-server.js +6 -6
  153. package/dist/src/cli/watch-view.d.ts +0 -3
  154. package/dist/src/cli/watch-view.js +13 -13
  155. package/dist/src/cli.js +59 -5
  156. package/dist/src/command-wait.d.ts +4 -0
  157. package/dist/src/command-wait.js +45 -0
  158. package/dist/src/configuration-change.d.ts +7 -0
  159. package/dist/src/configuration-change.js +14 -0
  160. package/dist/src/configuration-schema.d.ts +9 -0
  161. package/dist/src/configuration-schema.js +6 -2
  162. package/dist/src/daemon/attachment-file.d.ts +6 -0
  163. package/dist/src/daemon/attachment-file.js +86 -0
  164. package/dist/src/daemon/attachments.d.ts +14 -0
  165. package/dist/src/daemon/attachments.js +17 -0
  166. package/dist/src/daemon/claude-recovery.d.ts +50 -0
  167. package/dist/src/daemon/claude-recovery.js +204 -0
  168. package/dist/src/daemon/claude-stream.d.ts +27 -0
  169. package/dist/src/daemon/claude-stream.js +63 -0
  170. package/dist/src/daemon/claude-turn.d.ts +11 -25
  171. package/dist/src/daemon/claude-turn.js +64 -81
  172. package/dist/src/daemon/claude-worker.d.ts +2 -1
  173. package/dist/src/daemon/claude-worker.js +124 -122
  174. package/dist/src/daemon/daemon-adapters.d.ts +2 -0
  175. package/dist/src/daemon/daemon-adapters.js +26 -2
  176. package/dist/src/daemon/daemon-loops.d.ts +3 -1
  177. package/dist/src/daemon/daemon-loops.js +3 -1
  178. package/dist/src/daemon/daemon.js +14 -6
  179. package/dist/src/daemon/github-attach.d.ts +2 -0
  180. package/dist/src/daemon/github-attach.js +149 -0
  181. package/dist/src/daemon/github-ci-filters.d.ts +6 -0
  182. package/dist/src/daemon/github-ci-filters.js +138 -0
  183. package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
  184. package/dist/src/daemon/github-ci-workflows.js +148 -0
  185. package/dist/src/daemon/github-ci.js +22 -4
  186. package/dist/src/daemon/github-issue-methods.d.ts +2 -0
  187. package/dist/src/daemon/github-issue-methods.js +37 -2
  188. package/dist/src/daemon/github-merge-call.d.ts +2 -1
  189. package/dist/src/daemon/github-merge-call.js +10 -3
  190. package/dist/src/daemon/github-merge.js +52 -24
  191. package/dist/src/daemon/github-methods.js +12 -2
  192. package/dist/src/daemon/github-operation.d.ts +4 -0
  193. package/dist/src/daemon/github-operation.js +6 -0
  194. package/dist/src/daemon/github-worker.d.ts +4 -0
  195. package/dist/src/daemon/github-worker.js +6 -0
  196. package/dist/src/daemon/issue-queue.d.ts +1 -1
  197. package/dist/src/daemon/issue-queue.js +16 -11
  198. package/dist/src/daemon/notify-events.d.ts +6 -0
  199. package/dist/src/daemon/notify-events.js +84 -0
  200. package/dist/src/daemon/notify-journal.js +1 -1
  201. package/dist/src/daemon/notify-message.d.ts +4 -1
  202. package/dist/src/daemon/notify-message.js +36 -0
  203. package/dist/src/daemon/notify.d.ts +1 -1
  204. package/dist/src/daemon/notify.js +5 -77
  205. package/dist/src/daemon/operation-journal.d.ts +1 -0
  206. package/dist/src/daemon/queue-status.d.ts +9 -3
  207. package/dist/src/daemon/queue-status.js +17 -4
  208. package/dist/src/daemon/resume-index-lock.d.ts +13 -0
  209. package/dist/src/daemon/resume-index-lock.js +160 -0
  210. package/dist/src/daemon/resume-worktree.d.ts +7 -0
  211. package/dist/src/daemon/resume-worktree.js +29 -0
  212. package/dist/src/daemon/retrying-turn.d.ts +2 -12
  213. package/dist/src/daemon/retrying-turn.js +98 -172
  214. package/dist/src/daemon/schedule-control.d.ts +26 -0
  215. package/dist/src/daemon/schedule-control.js +110 -0
  216. package/dist/src/daemon/schedule-journal.d.ts +2 -15
  217. package/dist/src/daemon/schedule-journal.js +67 -4
  218. package/dist/src/daemon/ticket-registration.d.ts +2 -7
  219. package/dist/src/daemon/ticket-registration.js +15 -81
  220. package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
  221. package/dist/src/daemon/turn-attempt-journal.js +136 -0
  222. package/dist/src/daemon/turn-attempts.d.ts +47 -0
  223. package/dist/src/daemon/turn-attempts.js +166 -0
  224. package/dist/src/daemon/turn-report.d.ts +8 -1
  225. package/dist/src/daemon/turn-report.js +39 -0
  226. package/dist/src/daemon/work-tree.d.ts +9 -0
  227. package/dist/src/daemon/work-tree.js +20 -0
  228. package/dist/src/daemon/worker-profile.d.ts +8 -0
  229. package/dist/src/daemon/worker-profile.js +40 -0
  230. package/dist/src/daemon/workflow-schedules.d.ts +3 -0
  231. package/dist/src/daemon/workflow-schedules.js +98 -45
  232. package/dist/src/daemon/worktree-processes.d.ts +9 -0
  233. package/dist/src/daemon/worktree-processes.js +151 -0
  234. package/dist/src/doctor-report.d.ts +3 -5
  235. package/dist/src/doctor-report.js +6 -13
  236. package/dist/src/harness-start.d.ts +15 -0
  237. package/dist/src/harness-start.js +37 -0
  238. package/dist/src/host/command-wait.d.ts +38 -0
  239. package/dist/src/host/command-wait.js +115 -0
  240. package/dist/src/host/start-delivery.d.ts +5 -7
  241. package/dist/src/host/start-delivery.js +3 -15
  242. package/dist/src/host/step-bridge-host.d.ts +2 -0
  243. package/dist/src/host/step-bridge-host.js +21 -0
  244. package/dist/src/operation-identity.d.ts +1 -0
  245. package/dist/src/operation-identity.js +4 -0
  246. package/dist/src/private-config.schema.json +40 -0
  247. package/dist/src/project-config.schema.json +40 -0
  248. package/dist/src/project-settings.d.ts +2 -2
  249. package/dist/src/project-settings.js +3 -1
  250. package/dist/src/queue-spend.d.ts +4 -0
  251. package/dist/src/queue-spend.js +21 -0
  252. package/dist/src/relay/relay-service.d.ts +3 -0
  253. package/dist/src/relay/relay-service.js +5 -3
  254. package/dist/src/report-ci.d.ts +164 -0
  255. package/dist/src/report-ci.js +32 -0
  256. package/dist/src/report-effects.d.ts +15 -0
  257. package/dist/src/report-effects.js +212 -0
  258. package/dist/src/report-flow-types.d.ts +38 -0
  259. package/dist/src/report-flow-types.js +7 -0
  260. package/dist/src/report-flow.d.ts +43 -0
  261. package/dist/src/report-flow.js +193 -0
  262. package/dist/src/report-operator.d.ts +67 -0
  263. package/dist/src/report-operator.js +25 -0
  264. package/dist/src/report-quality.d.ts +221 -0
  265. package/dist/src/report-quality.js +94 -0
  266. package/dist/src/report-ready.d.ts +23 -0
  267. package/dist/src/report-ready.js +117 -0
  268. package/dist/src/report-statistics.d.ts +2 -1
  269. package/dist/src/report-statistics.js +40 -4
  270. package/dist/src/report.d.ts +588 -47
  271. package/dist/src/report.js +156 -41
  272. package/dist/src/schedule-progress.d.ts +33 -0
  273. package/dist/src/schedule-progress.js +45 -0
  274. package/dist/src/service/active-tickets.js +6 -6
  275. package/dist/src/service/command-waits.d.ts +34 -0
  276. package/dist/src/service/command-waits.js +86 -0
  277. package/dist/src/service/expiry.js +2 -0
  278. package/dist/src/service/gateway.js +3 -1
  279. package/dist/src/service/queue-spend.d.ts +6 -0
  280. package/dist/src/service/queue-spend.js +68 -0
  281. package/dist/src/service/replies.d.ts +8 -1
  282. package/dist/src/service/replies.js +11 -0
  283. package/dist/src/service/run-handlers.js +22 -2
  284. package/dist/src/service/run-metadata.d.ts +15 -1
  285. package/dist/src/service/run-metadata.js +93 -8
  286. package/dist/src/service/service.d.ts +4 -0
  287. package/dist/src/service/service.js +8 -8
  288. package/dist/src/service/submission-handler.js +18 -4
  289. package/dist/src/service/worker-port.js +9 -1
  290. package/dist/src/service/worker-totals.d.ts +2 -0
  291. package/dist/src/service/worker-totals.js +1 -1
  292. package/dist/src/step-bridge.d.ts +20 -0
  293. package/dist/src/steps/command-wait.d.ts +12 -0
  294. package/dist/src/steps/command-wait.js +26 -0
  295. package/dist/src/steps/open-decision-wait.d.ts +2 -0
  296. package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
  297. package/dist/src/steps/review-by-person.js +4 -1
  298. package/dist/src/steps/wait-for-command.d.ts +3 -0
  299. package/dist/src/steps/wait-for-command.js +17 -0
  300. package/dist/src/steps/wait-for-decision.js +1 -1
  301. package/dist/src/storage/command-wait-rows.d.ts +30 -0
  302. package/dist/src/storage/command-wait-rows.js +96 -0
  303. package/dist/src/storage/decision-snapshots.d.ts +8 -1
  304. package/dist/src/storage/decision-snapshots.js +15 -1
  305. package/dist/src/storage/domain-changes.d.ts +2 -0
  306. package/dist/src/storage/domain-changes.js +3 -0
  307. package/dist/src/storage/domain-schema.d.ts +13 -1
  308. package/dist/src/storage/domain-schema.js +31 -4
  309. package/dist/src/storage/effect-schema.d.ts +1 -0
  310. package/dist/src/storage/effect-schema.js +5 -0
  311. package/dist/src/testing-requests.d.ts +15 -0
  312. package/dist/src/testing-requests.js +93 -0
  313. package/dist/src/testing.d.ts +4 -10
  314. package/dist/src/testing.js +33 -86
  315. package/dist/src/worker-usage.d.ts +1 -0
  316. package/dist/src/worker-usage.js +3 -0
  317. package/dist/src/workflow-candidate.d.ts +1 -0
  318. package/dist/src/workflow-candidate.js +12 -1
  319. package/dist/src/workflow-contracts.d.ts +1 -0
  320. package/dist/src/workflow-contracts.js +9 -2
  321. package/dist/src/workflow-discovery.d.ts +2 -13
  322. package/dist/src/workflow-discovery.js +1 -13
  323. package/dist/src/workflow-refusals.js +0 -1
  324. package/dist/src/workflows.d.ts +1 -1
  325. package/dist/src/workflows.js +1 -1
  326. package/dist/tools/red-green-command.d.ts +1 -0
  327. package/dist/tools/red-green-command.js +174 -0
  328. package/dist/tools/red-green-process.d.ts +10 -0
  329. package/dist/tools/red-green-process.js +59 -0
  330. package/dist/tools/self-host-processes.d.ts +2 -0
  331. package/dist/tools/self-host-processes.js +32 -13
  332. package/dist/tools/self-host-project.js +13 -78
  333. package/dist/tools/self-host-runtime.js +1 -1
  334. package/dist/tools/self-host.js +42 -10
  335. package/dist/tools/template-command.d.ts +1 -0
  336. package/dist/tools/template-command.js +160 -0
  337. package/dist/tools/template-copy.d.ts +11 -0
  338. package/dist/tools/template-copy.js +130 -0
  339. package/dist/tools/template-files.d.ts +17 -0
  340. package/dist/tools/template-files.js +74 -0
  341. package/dist/tools/workflow-bundles.js +1 -0
  342. package/dist/tools/workflow-candidate-counts.js +2 -2
  343. package/dist/tools/workflow-candidate-shape.d.ts +3 -0
  344. package/dist/tools/workflow-candidate-shape.js +90 -0
  345. package/dist/tools/workflow-candidate-source.js +15 -1
  346. package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
  347. package/dist/tools/workflow-candidate-syntax.js +24 -94
  348. package/dist/tools/workflow-command.js +1 -2
  349. package/dist/tools/workflow-folders.d.ts +2 -3
  350. package/dist/tools/workflow-folders.js +1 -1
  351. package/package.json +16 -8
  352. package/templates/develop/README.md +12 -0
  353. package/templates/develop/develop/flow-tests.ts +37 -0
  354. package/templates/develop/develop/pull.ts +5 -1
  355. package/templates/develop/develop/refusal-tests.ts +77 -0
  356. package/templates/develop/develop/turn.ts +2 -1
  357. package/templates/idea-to-issue/README.md +27 -0
  358. package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
  359. package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
  360. package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
  361. package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
  362. package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
  363. package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
  364. package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
  365. package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
  366. package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
  367. package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
  368. package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
  369. package/templates/idea-to-issue/idea-to-issue.ts +49 -0
  370. package/templates/idea-to-issue/template.json +81 -0
  371. package/templates/review-day/README.md +97 -0
  372. package/templates/review-day/review-day/critique.ts +58 -0
  373. package/templates/review-day/review-day/decision.ts +29 -0
  374. package/templates/review-day/review-day/facts.ts +69 -0
  375. package/templates/review-day/review-day/label.ts +29 -0
  376. package/templates/review-day/review-day/next.ts +28 -0
  377. package/templates/review-day/review-day/post.ts +27 -0
  378. package/templates/review-day/review-day/report.ts +98 -0
  379. package/templates/review-day/review-day/rules.ts +12 -0
  380. package/templates/review-day/review-day/scenarios.ts +76 -0
  381. package/templates/review-day/review-day/turn.ts +73 -0
  382. package/templates/review-day/review-day.declaration.json +16 -0
  383. package/templates/review-day/review-day.test.ts +362 -0
  384. package/templates/review-day/review-day.ts +37 -0
  385. package/templates/review-day/template.json +56 -0
  386. package/dist/src/cli/watch-start-view.d.ts +0 -18
  387. package/dist/src/cli/watch-start-view.js +0 -77
  388. package/dist/src/steps/decision-gate.d.ts +0 -3
  389. package/dist/workflows/develop-prd.d.ts +0 -7
  390. package/dist/workflows/develop-prd.js +0 -165
  391. package/dist/workflows/develop-ticket.d.ts +0 -9
  392. package/dist/workflows/develop-ticket.js +0 -207
  393. package/dist/workflows/issue-labels.d.ts +0 -16
  394. package/dist/workflows/issue-labels.js +0 -70
  395. package/dist/workflows/ticket-prompts.d.ts +0 -35
  396. package/dist/workflows/ticket-prompts.js +0 -147
@@ -0,0 +1,110 @@
1
+ import { scheduleStops } from "../schedule-progress.js";
2
+ import { runIdentity } from "../service/submission-handler.js";
3
+ import { failed, invalidRequest, result } from "../service/replies.js";
4
+ function summary(workflowId, progress) {
5
+ return {
6
+ workflowId,
7
+ everySeconds: progress.everySeconds,
8
+ state: progress.state,
9
+ failuresInRow: progress.failuresInRow,
10
+ failedRunIds: progress.failedRunIds,
11
+ lastSlot: progress.lastSlot,
12
+ nextAt: progress.state === "active" ? progress.nextAt : null,
13
+ activeRunId: progress.activeCommandId === undefined
14
+ ? null
15
+ : runIdentity(progress.activeCommandId),
16
+ stoppedAt: progress.stoppedAt ?? null,
17
+ stoppedSlot: progress.stoppedSlot ?? null,
18
+ stops: scheduleStops(progress),
19
+ };
20
+ }
21
+ export function scheduleConnection() {
22
+ let port;
23
+ return {
24
+ request: (parameters) => port?.(parameters) ??
25
+ Promise.resolve(failed("schedules-unavailable", {})),
26
+ connect: (connected) => {
27
+ port = connected;
28
+ },
29
+ };
30
+ }
31
+ async function change(settings, command) {
32
+ const { workflowId, action, now } = command;
33
+ const { journal } = settings;
34
+ let prior = journal.entries.get(workflowId);
35
+ if (prior === undefined)
36
+ return failed("unknown-schedule", { workflowId });
37
+ const state = action === "pause" ? "paused" : "active";
38
+ if (prior.state === state)
39
+ return result("schedule", { schedule: summary(workflowId, prior) });
40
+ if (prior.pending !== undefined) {
41
+ prior = await settings.recoverPending({ workflowId, progress: prior });
42
+ journal.entries.set(workflowId, prior);
43
+ await journal.save();
44
+ }
45
+ const rest = { ...prior };
46
+ delete rest.stoppedAt;
47
+ delete rest.stoppedSlot;
48
+ const progress = action === "pause"
49
+ ? { ...prior, state, stops: scheduleStops(prior) }
50
+ : {
51
+ ...rest,
52
+ state,
53
+ failuresInRow: 0,
54
+ failedRunIds: [],
55
+ stops: scheduleStops(prior),
56
+ nextAt: now + prior.everySeconds * 1000,
57
+ };
58
+ journal.entries.set(workflowId, progress);
59
+ try {
60
+ await journal.save();
61
+ }
62
+ catch (error) {
63
+ journal.entries.set(workflowId, prior);
64
+ throw error;
65
+ }
66
+ return result("schedule", { schedule: summary(workflowId, progress) });
67
+ }
68
+ function request(settings, parameters) {
69
+ const { action, workflowId } = parameters;
70
+ const scheduled = settings.declarations.filter((entry) => entry.schedule !== undefined);
71
+ if (action === "list")
72
+ return Promise.resolve(result("schedules", {
73
+ stops: Array.from(settings.journal.entries, ([workflowId, progress]) => ({
74
+ workflowId,
75
+ stops: scheduleStops(progress),
76
+ })),
77
+ schedules: scheduled.flatMap((entry) => {
78
+ const progress = settings.journal.entries.get(entry.workflowId);
79
+ return progress === undefined
80
+ ? []
81
+ : [summary(entry.workflowId, progress)];
82
+ }),
83
+ }));
84
+ if ((action !== "pause" && action !== "resume") ||
85
+ typeof workflowId !== "string")
86
+ return Promise.resolve(invalidRequest("Use list, pause or resume with a workflow ID."));
87
+ if (!scheduled.some((entry) => entry.workflowId === workflowId))
88
+ return Promise.resolve(failed("unknown-schedule", { workflowId }));
89
+ return change(settings, {
90
+ workflowId,
91
+ action,
92
+ now: settings.clock(),
93
+ });
94
+ }
95
+ export function scheduleControl(settings) {
96
+ let running = Promise.resolve();
97
+ const serialized = (operation) => {
98
+ const next = running.then(async () => {
99
+ settings.signal.throwIfAborted();
100
+ return operation();
101
+ });
102
+ running = next.then(() => undefined, () => undefined);
103
+ return next;
104
+ };
105
+ return {
106
+ request: (parameters) => serialized(() => request(settings, parameters)).catch(() => failed("schedules-unavailable", {})),
107
+ tick: () => serialized(settings.tick),
108
+ drain: () => running,
109
+ };
110
+ }
@@ -1,18 +1,5 @@
1
- import { type Fields } from "../protocol.ts";
2
- export type PendingSlot = {
3
- readonly kind: "run";
4
- readonly input: Fields;
5
- } | {
6
- readonly kind: "skip";
7
- readonly runId: string;
8
- };
9
- export interface ScheduleProgress {
10
- readonly everySeconds: number;
11
- readonly nextAt: number;
12
- readonly lastSlot: number;
13
- readonly activeCommandId?: string;
14
- readonly pending?: PendingSlot;
15
- }
1
+ import type { ScheduleProgress } from "../schedule-progress.ts";
2
+ export type { PendingSlot, ScheduleProgress } from "../schedule-progress.ts";
16
3
  export declare function scheduleJournal(directory: string): Promise<{
17
4
  readonly entries: Map<string, ScheduleProgress>;
18
5
  readonly save: () => Promise<void>;
@@ -23,10 +23,68 @@ function isProgress(value) {
23
23
  const fields = record(value);
24
24
  if (fields === undefined)
25
25
  return false;
26
- const { activeCommandId, pending } = fields;
26
+ const { activeCommandId } = fields;
27
27
  return (timing(fields) &&
28
- (activeCommandId === undefined || isCommandId(activeCommandId)) &&
29
- (pending === undefined || pendingSlot(pending)));
28
+ control(fields) &&
29
+ history(fields) &&
30
+ pendingProgress(fields) &&
31
+ (activeCommandId === undefined || isCommandId(activeCommandId)));
32
+ }
33
+ function pendingProgress(fields) {
34
+ const { pending, state } = fields;
35
+ if (pending === undefined)
36
+ return true;
37
+ return (state === undefined || state === "active") && pendingSlot(pending);
38
+ }
39
+ function stopped(fields) {
40
+ const { state, stoppedAt, stoppedSlot } = fields;
41
+ if (stoppedAt === undefined && stoppedSlot === undefined)
42
+ return state !== "stopped";
43
+ return (whole(stoppedAt) &&
44
+ whole(stoppedSlot) &&
45
+ stoppedSlot <= Number(fields["lastSlot"]));
46
+ }
47
+ function failures(fields) {
48
+ const { failuresInRow, failedRunIds } = fields;
49
+ return (whole(failuresInRow) &&
50
+ failuresInRow <= 3 &&
51
+ Array.isArray(failedRunIds) &&
52
+ failedRunIds.length === failuresInRow &&
53
+ failedRunIds.every(isRecordKey) &&
54
+ new Set(failedRunIds).size === failuresInRow);
55
+ }
56
+ function history(fields) {
57
+ const stops = fields["stops"];
58
+ if (stops === undefined)
59
+ return true;
60
+ if (!Array.isArray(stops))
61
+ return false;
62
+ let previousSlot = -1;
63
+ for (const item of stops) {
64
+ const stop = record(item);
65
+ if (stop === undefined)
66
+ return false;
67
+ const slot = stop["stoppedSlot"];
68
+ if (!whole(slot) || !whole(stop["stoppedAt"]))
69
+ return false;
70
+ if (slot <= previousSlot || slot > Number(fields["lastSlot"]))
71
+ return false;
72
+ if (!failures({ ...stop, failuresInRow: 3 }))
73
+ return false;
74
+ previousSlot = slot;
75
+ }
76
+ return true;
77
+ }
78
+ function control(fields) {
79
+ const { state, failuresInRow, failedRunIds } = fields;
80
+ if (state === undefined &&
81
+ failuresInRow === undefined &&
82
+ failedRunIds === undefined)
83
+ return (fields["stoppedAt"] === undefined && fields["stoppedSlot"] === undefined);
84
+ return (["active", "paused", "stopped"].includes(String(state)) &&
85
+ failures(fields) &&
86
+ stopped(fields) &&
87
+ (state !== "stopped" || failuresInRow === 3));
30
88
  }
31
89
  export async function scheduleJournal(directory) {
32
90
  const file = join(directory, "schedules.json");
@@ -42,7 +100,12 @@ export async function scheduleJournal(directory) {
42
100
  for (const [workflowId, value] of Object.entries(parsed)) {
43
101
  if (!isProgress(value))
44
102
  throw new Error("invalid-schedule-state");
45
- entries.set(workflowId, value);
103
+ entries.set(workflowId, {
104
+ ...value,
105
+ state: value.state ?? "active",
106
+ failuresInRow: value.failuresInRow ?? 0,
107
+ failedRunIds: value.failedRunIds ?? [],
108
+ });
46
109
  }
47
110
  return {
48
111
  entries,
@@ -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;