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
@@ -36,3 +36,24 @@ export function notBefore(value, bound) {
36
36
  export function isAfter(value, bound) {
37
37
  return notBefore(value, bound) && !notBefore(bound, value);
38
38
  }
39
+ function leapDaysBefore(year) {
40
+ const previous = year - 1;
41
+ return (Math.floor(previous / 4) -
42
+ Math.floor(previous / 100) +
43
+ Math.floor(previous / 400));
44
+ }
45
+ export function instantMilliseconds(value) {
46
+ if (!isInstant(value))
47
+ throw new Error("invalid-instant");
48
+ const year = Number(value.slice(0, 4));
49
+ const month = Number(value.slice(5, 7));
50
+ let days = Number(value.slice(8, 10)) - 1;
51
+ for (let preceding = 1; preceding < month; preceding += 1)
52
+ days += daysIn(year, preceding);
53
+ days += 365 * (year - 1970) + leapDaysBefore(year) - leapDaysBefore(1970);
54
+ return (days * 86_400_000 +
55
+ Number(value.slice(11, 13)) * 3_600_000 +
56
+ Number(value.slice(14, 16)) * 60_000 +
57
+ Number(value.slice(17, 19)) * 1000 +
58
+ Number(value.slice(20, 23)));
59
+ }
@@ -1,3 +1,4 @@
1
+ import { type CommandWaitsState } from "./command-waits.ts";
1
2
  import { type RunDetails } from "./details.ts";
2
3
  import { type GateState } from "./gates.ts";
3
4
  import { type Disposition, type EffectState } from "./operations.ts";
@@ -20,6 +21,7 @@ export interface Recorded {
20
21
  }
21
22
  export interface Change extends Recorded {
22
23
  readonly moved?: RunState;
24
+ readonly commandWaits?: CommandWaitsState;
23
25
  readonly gates?: readonly GateState[];
24
26
  readonly added?: readonly EffectIntent[];
25
27
  readonly questions?: number;
@@ -1,3 +1,4 @@
1
+ import { closedCommandWaits } from "./command-waits.js";
1
2
  import { operationIdentity } from "../operation-identity.js";
2
3
  import { continued } from "./details.js";
3
4
  import { gateKey } from "./gates.js";
@@ -40,12 +41,16 @@ function nextDetails(change) {
40
41
  }
41
42
  export function applied(state, change) {
42
43
  const { event } = change;
44
+ const waits = change.commandWaits ?? state.commandWaits;
43
45
  return {
44
46
  kind: "applied",
45
47
  ...(change.disposition === undefined
46
48
  ? {}
47
49
  : { disposition: change.disposition }),
48
50
  state: {
51
+ ...(waits === undefined
52
+ ? {}
53
+ : { commandWaits: closedCommandWaits(waits, event) }),
49
54
  sequence: event.sequence,
50
55
  runs: change.moved
51
56
  ? { ...state.runs, [event.runId]: change.moved }
@@ -1,3 +1,6 @@
1
+ import { checkedCommandWait } from "./command-wait-checks.js";
2
+ import { waitEffectTime, waitEffectChange } from "./command-wait-results.js";
3
+ import { commandWaitKey, commandWaitsAfter, validCommandWaitTime, } from "./command-waits.js";
1
4
  import { admittedDetails, observed } from "./details.js";
2
5
  import { settled } from "./gates.js";
3
6
  import { admittedBudgets } from "./budgets.js";
@@ -57,6 +60,8 @@ function dispatched(state, recorded) {
57
60
  function effect(rule) {
58
61
  return (state, recorded) => {
59
62
  const { event, run } = recorded;
63
+ if (!waitEffectTime(state.commandWaits ?? {}, event))
64
+ return invalid("invalid-recorded-time");
60
65
  const result = rule(state.effects, { event, runStatus: run.status });
61
66
  if (result.kind === "invalid")
62
67
  return result;
@@ -64,6 +69,7 @@ function effect(rule) {
64
69
  return applied(state, {
65
70
  ...recorded,
66
71
  effects: result.effects,
72
+ ...waitEffectChange(state, { event, result }),
67
73
  ...(result.released === undefined ? {} : { released: result.released }),
68
74
  ...(result.disposition === undefined
69
75
  ? {}
@@ -78,8 +84,24 @@ function effect(rule) {
78
84
  });
79
85
  };
80
86
  }
87
+ const changeCommandWait = (state, recorded) => {
88
+ const { event, run } = recorded;
89
+ const waits = state.commandWaits ?? {};
90
+ const key = commandWaitKey(event.runId, event.payload["waitName"] ?? "");
91
+ if (event.type === "command-wait.opened" &&
92
+ waits[key] === undefined &&
93
+ run.status !== "running")
94
+ return invalid("command-wait-run-not-running");
95
+ const result = commandWaitsAfter(waits, event);
96
+ return result.kind === "invalid"
97
+ ? result
98
+ : applied(state, { ...recorded, commandWaits: result.waits });
99
+ };
81
100
  const handlers = {
82
101
  "schedule.skipped": applied,
102
+ "command-wait.opened": changeCommandWait,
103
+ "command-wait.checked": checkedCommandWait,
104
+ "command-wait.expired": changeCommandWait,
83
105
  "effect.requested": effect(requested),
84
106
  "lease.granted": effect(granted),
85
107
  "lease.expired": effect(leaseExpired),
@@ -146,6 +168,8 @@ function created(state, recorded) {
146
168
  };
147
169
  }
148
170
  export function reduce(state, event) {
171
+ if (!validCommandWaitTime(state.commandWaits ?? {}, event))
172
+ return invalid("invalid-command-wait-time");
149
173
  if (event.sequence !== state.sequence + 1)
150
174
  return invalid("sequence-gap");
151
175
  if (state.commands[event.commandId])
@@ -1,3 +1,4 @@
1
+ import type { CommandWaitView } from "./command-wait-view.ts";
1
2
  import type { RunDetails } from "./details.ts";
2
3
  import type { GateState } from "./gates.ts";
3
4
  import type { RunClosure } from "./stop-sequence.ts";
@@ -21,6 +22,7 @@ export interface BudgetSummary {
21
22
  readonly spent: number;
22
23
  }
23
24
  export interface StatusInput {
25
+ readonly commandWaits: readonly CommandWaitView[];
24
26
  readonly run: RunState;
25
27
  readonly details: RunDetails | undefined;
26
28
  readonly gates: readonly GateState[];
@@ -1,3 +1,4 @@
1
+ import type { CommandWaitView } from "./command-wait-view.ts";
1
2
  import { type EffectView, type Recovery } from "./status-effects.ts";
2
3
  import { type BudgetSummary, type StatusInput } from "./status-input.ts";
3
4
  import type { RunStatus } from "./transitions.ts";
@@ -5,6 +6,7 @@ export { unresolved, unresolvedEffects } from "./status-closure.ts";
5
6
  export type { EffectView } from "./status-effects.ts";
6
7
  export type { Assessment, BudgetSummary, EffectSummary, OperationSummary, StatusInput, } from "./status-input.ts";
7
8
  export interface RunView {
9
+ readonly commandWaits: readonly CommandWaitView[];
8
10
  readonly runId: string;
9
11
  readonly workflow: string;
10
12
  readonly state: RunStatus;
@@ -266,6 +266,7 @@ export function runView(input) {
266
266
  attempts: observation?.attempt ?? 0,
267
267
  limit: observation?.limit ?? null,
268
268
  },
269
+ commandWaits: input.commandWaits,
269
270
  budget: input.budget,
270
271
  effects: effectViews(input.effects),
271
272
  nextAction: assessment.nextAction,
@@ -5,6 +5,7 @@ export interface AttemptSummary {
5
5
  readonly stagedSequence: number;
6
6
  }
7
7
  export interface StopSubject {
8
+ readonly stopSequence?: number;
8
9
  readonly operationId: string;
9
10
  readonly kind: string;
10
11
  readonly attempts: readonly AttemptSummary[];
@@ -39,7 +39,8 @@ const stopPurposes = ["stop", "reconcile"];
39
39
  export function stopCount(subject, cancelledSequence) {
40
40
  return subject.attempts.filter((attempt) => attempt.outcome !== null &&
41
41
  stopPurposes.includes(attempt.purpose) &&
42
- attempt.stagedSequence >= cancelledSequence).length;
42
+ attempt.stagedSequence >=
43
+ Math.max(cancelledSequence, subject.stopSequence ?? 0)).length;
43
44
  }
44
45
  const uncertainStatuses = ["recovering", "blocked"];
45
46
  function uncertain(subject) {
@@ -1,3 +1,4 @@
1
+ import type { CommandWaitsState } from "./command-waits.ts";
1
2
  import type { RunDetails } from "./details.ts";
2
3
  import type { GateState } from "./gates.ts";
3
4
  import type { EffectState } from "./operations.ts";
@@ -26,9 +27,10 @@ export interface AuthorityState {
26
27
  readonly gates: Readonly<Record<string, GateState>>;
27
28
  readonly details: Readonly<Record<string, RunDetails>>;
28
29
  readonly questions: number;
30
+ readonly commandWaits?: CommandWaitsState;
29
31
  readonly effects: EffectState;
30
32
  }
31
- export declare const eventTypes: readonly ["run.created", "run.started", "gate.opened", "gate.wait-registered", "gate.decided", "gate.expired", "run.paused", "run.resumed", "run.completed", "run.failed", "run.cancelled", "run.observed", "step.dispatched", "effect.requested", "lease.granted", "lease.expired", "effect.reported", "operation.reconciled", "schedule.skipped"];
33
+ export declare const eventTypes: readonly ["run.created", "run.started", "gate.opened", "gate.wait-registered", "gate.decided", "gate.expired", "run.paused", "run.resumed", "run.completed", "run.failed", "run.cancelled", "run.observed", "step.dispatched", "effect.requested", "lease.granted", "lease.expired", "effect.reported", "operation.reconciled", "schedule.skipped", "command-wait.opened", "command-wait.checked", "command-wait.expired"];
32
34
  export type EventType = (typeof eventTypes)[number];
33
35
  export interface AuthorityEvent {
34
36
  readonly sequence: number;
@@ -39,8 +41,8 @@ export interface AuthorityEvent {
39
41
  readonly request: string;
40
42
  readonly payload: Readonly<Record<string, string>>;
41
43
  }
42
- export declare const numberFields: readonly ["expectedRevision", "expectedObservation", "generation", "attempt", "limit", "effectLimit", "units", "recoveryLimit", "leaseGeneration", "sourceGeneration", "capacity", "slot"];
43
- export declare const textFields: readonly ["parentRunId", "chainId", "workflow", "workflowId", "submission", "input", "resolver", "gateId", "gateKind", "waitMode", "subject", "prompt", "expiresAt", "decision", "answer", "condition", "reason", "evidence", "retryAt", "operationId", "receipt", "capabilities", "capability", "method", "target", "payload", "inputDigest", "resource", "transport", "source", "worker", "outcome", "outcomeReason", "promotionId", "ticketStatus", "issueUpdate", "result", "actor"];
44
+ export declare const numberFields: readonly ["expectedRevision", "expectedObservation", "generation", "attempt", "limit", "effectLimit", "units", "recoveryLimit", "leaseGeneration", "sourceGeneration", "capacity", "slot", "maximumWaitSeconds", "pollEverySeconds"];
45
+ export declare const textFields: readonly ["parentRunId", "chainId", "workflow", "workflowId", "submission", "input", "resolver", "gateId", "gateKind", "waitMode", "subject", "prompt", "expiresAt", "decision", "answer", "condition", "reason", "evidence", "retryAt", "operationId", "receipt", "capabilities", "capability", "method", "target", "payload", "inputDigest", "resource", "transport", "source", "worker", "outcome", "outcomeReason", "promotionId", "ticketStatus", "issueUpdate", "result", "actor", "waitName", "commandOutput"];
44
46
  export type NumberField = (typeof numberFields)[number];
45
47
  export type TextField = (typeof textFields)[number];
46
48
  export type AuthorityCommand = {
@@ -48,7 +50,7 @@ export type AuthorityCommand = {
48
50
  readonly commandId: string;
49
51
  readonly runId: string;
50
52
  } & Readonly<Partial<Record<NumberField, number>>> & Readonly<Partial<Record<TextField, string>>>;
51
- export type Move = Exclude<EventType, "run.created" | "step.dispatched" | "gate.wait-registered" | "run.observed" | "effect.requested" | "lease.granted" | "lease.expired" | "effect.reported" | "operation.reconciled" | "schedule.skipped">;
53
+ export type Move = Exclude<EventType, "run.created" | "step.dispatched" | "gate.wait-registered" | "run.observed" | "effect.requested" | "lease.granted" | "lease.expired" | "effect.reported" | "operation.reconciled" | "schedule.skipped" | "command-wait.opened" | "command-wait.checked" | "command-wait.expired">;
52
54
  export declare const terminal: readonly RunStatus[];
53
55
  export type Transition = {
54
56
  readonly kind: "moved";
@@ -18,6 +18,9 @@ export const eventTypes = [
18
18
  "effect.reported",
19
19
  "operation.reconciled",
20
20
  "schedule.skipped",
21
+ "command-wait.opened",
22
+ "command-wait.checked",
23
+ "command-wait.expired",
21
24
  ];
22
25
  export const numberFields = [
23
26
  "expectedRevision",
@@ -32,6 +35,8 @@ export const numberFields = [
32
35
  "sourceGeneration",
33
36
  "capacity",
34
37
  "slot",
38
+ "maximumWaitSeconds",
39
+ "pollEverySeconds",
35
40
  ];
36
41
  export const textFields = [
37
42
  "parentRunId",
@@ -72,6 +77,8 @@ export const textFields = [
72
77
  "issueUpdate",
73
78
  "result",
74
79
  "actor",
80
+ "waitName",
81
+ "commandOutput",
75
82
  ];
76
83
  export const terminal = [
77
84
  "completed",
@@ -33,6 +33,7 @@ export interface CompletionCursor {
33
33
  readonly terminal?: boolean;
34
34
  }
35
35
  export interface RunRecord extends RunState {
36
+ readonly admissionCommandId: string | null;
36
37
  readonly sequence: number;
37
38
  }
38
39
  export interface AuthorityQueries {
@@ -43,7 +44,7 @@ export interface AuthorityQueries {
43
44
  readonly eventsAfter: (cursor: EventCursor) => Promise<EventPage>;
44
45
  readonly latestCompletion: (cursor: CompletionCursor) => Promise<PublishedEvent | undefined>;
45
46
  readonly sequences: () => Promise<Sequences>;
46
- readonly workflowIds: () => Promise<Readonly<Record<string, string>>>;
47
+ readonly workflowIds: (runIds?: readonly string[]) => Promise<Readonly<Record<string, string>>>;
47
48
  readonly runOrigins: () => Promise<RunOrigins>;
48
49
  readonly runLinks: () => Promise<Readonly<Record<string, RunLinks>>>;
49
50
  }
@@ -6,11 +6,15 @@ import { storedEvents, storedRun } from "../authority-restore.js";
6
6
  import { documentDigest } from "../decision-restore.js";
7
7
  import { runLinks, } from "../../authority/handoff-chain.js";
8
8
  async function run(connection, runId) {
9
- const row = await connection.get("SELECT run_id, status, revision, workflow, paused_from, gates, sequence FROM runs WHERE run_id = ?", [runId]);
9
+ const row = await connection.get("SELECT r.run_id, r.status, r.revision, r.workflow, r.paused_from, r.gates, r.sequence, c.command_id AS admission_command_id FROM runs r LEFT JOIN events c ON c.run_id = r.run_id AND c.type = 'run.created' WHERE r.run_id = ? ORDER BY c.sequence LIMIT 1", [runId]);
10
10
  if (row === undefined)
11
11
  return undefined;
12
12
  const record = runRow(row);
13
- return { ...storedRun(record), sequence: record.sequence };
13
+ return {
14
+ ...storedRun(record),
15
+ sequence: record.sequence,
16
+ admissionCommandId: optionalText(row, "admission_command_id"),
17
+ };
14
18
  }
15
19
  async function runOrigins(connection, cursor) {
16
20
  const rows = await connection.all("SELECT run_id, json_extract(payload, '$.parentRunId') AS parent_run_id, coalesce(json_extract(payload, '$.chainId'), run_id) AS chain_id FROM events WHERE type = 'run.created' AND sequence > ? AND sequence <= ? ORDER BY sequence", [cursor.after, cursor.through]);
@@ -84,8 +88,13 @@ async function sequences(connection) {
84
88
  times: Object.fromEntries(rows.map((row) => [text(row, "run_id"), text(row, "recorded_at")])),
85
89
  };
86
90
  }
87
- async function workflowIds(connection) {
88
- const rows = await connection.all("SELECT d.run_id, json_extract(s.body, '$.workflowId') AS workflow_id FROM run_details d JOIN documents s ON s.digest = d.submission WHERE json_valid(s.body) AND json_type(s.body, '$.workflowId') = 'text'");
91
+ async function workflowIds(connection, runIds) {
92
+ if (runIds?.length === 0)
93
+ return {};
94
+ const scoped = runIds === undefined
95
+ ? ""
96
+ : ` AND d.run_id IN (${runIds.map(() => "?").join(", ")})`;
97
+ const rows = await connection.all(`SELECT d.run_id, json_extract(s.body, '$.workflowId') AS workflow_id FROM run_details d JOIN documents s ON s.digest = d.submission WHERE json_valid(s.body) AND json_type(s.body, '$.workflowId') = 'text'${scoped}`, runIds);
89
98
  return Object.fromEntries(rows.map((row) => [text(row, "run_id"), text(row, "workflow_id")]));
90
99
  }
91
100
  function cachedOrigins(read) {
@@ -142,7 +151,7 @@ export function authorityQueries(read) {
142
151
  eventsAfter: (cursor) => read((connection) => eventsAfter(connection, cursor)),
143
152
  latestCompletion: (cursor) => read((connection) => latestCompletion(connection, cursor)),
144
153
  sequences: () => read(sequences),
145
- workflowIds: () => read(workflowIds),
154
+ workflowIds: (runIds) => read((connection) => workflowIds(connection, runIds)),
146
155
  runOrigins: origins,
147
156
  runLinks: currentLinks,
148
157
  };
@@ -24,7 +24,7 @@ export function oversized(request) {
24
24
  command["kind"] === "report-effect" &&
25
25
  command["worker"] === "command";
26
26
  const limit = report
27
- ? maximumRequestBytes + commandLimits.stdoutBytes * 6
27
+ ? maximumRequestBytes + commandLimits.stdoutBytes * 12
28
28
  : maximumRequestBytes;
29
29
  return Buffer.byteLength(JSON.stringify(request)) > limit;
30
30
  }
@@ -52,8 +52,8 @@ export function librarySettings(timing, log) {
52
52
  tableNamePrefix: "solid_",
53
53
  maxAttempts: 1,
54
54
  maxActivationDurationMilliseconds: 50,
55
- maxPayloadBytes: 900_000 + commandLimits.stdoutBytes * 6,
56
- maxResultBytes: 900_000 + commandLimits.stdoutBytes * 6,
55
+ maxPayloadBytes: 900_000 + commandLimits.stdoutBytes * 12,
56
+ maxResultBytes: 900_000 + commandLimits.stdoutBytes * 12,
57
57
  logger: lineLogger(log ?? standardError),
58
58
  leaseDurationMilliseconds: timing.leaseMilliseconds,
59
59
  leaseRenewalIntervalMilliseconds: timing.renewalMilliseconds,
@@ -1,7 +1,8 @@
1
- import { loadDecided } from "../../storage/decision-snapshots.ts";
1
+ import { upgradeCommandWaits, upgradeCommandWaitChecks } from "../command-wait-restore.ts";
2
+ import { loadDecided, loadEffected, loadWaiting, loadCurrent } from "../../storage/decision-snapshots.ts";
2
3
  import { loadSnapshot } from "../../storage/domain-rows.ts";
3
4
  import { upgradeDecisions } from "../decision-upgrade.ts";
4
- import { upgradeEffects } from "../effect-upgrade.ts";
5
+ import { upgradeEffects, upgradeEventIndexes, upgradeSpendingIndexes } from "../effect-upgrade.ts";
5
6
  declare const upgrades: readonly [{
6
7
  readonly from: "adopted";
7
8
  readonly load: typeof loadSnapshot;
@@ -10,6 +11,22 @@ declare const upgrades: readonly [{
10
11
  readonly from: "decided";
11
12
  readonly load: typeof loadDecided;
12
13
  readonly apply: typeof upgradeEffects;
14
+ }, {
15
+ readonly from: "effected";
16
+ readonly load: typeof loadEffected;
17
+ readonly apply: typeof upgradeCommandWaits;
18
+ }, {
19
+ readonly from: "waiting";
20
+ readonly load: typeof loadWaiting;
21
+ readonly apply: typeof upgradeCommandWaitChecks;
22
+ }, {
23
+ readonly from: "checked";
24
+ readonly load: typeof loadCurrent;
25
+ readonly apply: typeof upgradeSpendingIndexes;
26
+ }, {
27
+ readonly from: "indexed";
28
+ readonly load: typeof loadCurrent;
29
+ readonly apply: typeof upgradeEventIndexes;
13
30
  }];
14
31
  export type UpgradeStep = (typeof upgrades)[number];
15
32
  export declare function upgradeSteps(kind: string): readonly UpgradeStep[];
@@ -1,10 +1,15 @@
1
- import { loadDecided } from "../../storage/decision-snapshots.js";
1
+ import { upgradeCommandWaits, upgradeCommandWaitChecks, } from "../command-wait-restore.js";
2
+ import { loadDecided, loadEffected, loadWaiting, loadCurrent, } from "../../storage/decision-snapshots.js";
2
3
  import { loadSnapshot } from "../../storage/domain-rows.js";
3
4
  import { upgradeDecisions } from "../decision-upgrade.js";
4
- import { upgradeEffects } from "../effect-upgrade.js";
5
+ import { upgradeEffects, upgradeEventIndexes, upgradeSpendingIndexes, } from "../effect-upgrade.js";
5
6
  const upgrades = [
6
7
  { from: "adopted", load: loadSnapshot, apply: upgradeDecisions },
7
8
  { from: "decided", load: loadDecided, apply: upgradeEffects },
9
+ { from: "effected", load: loadEffected, apply: upgradeCommandWaits },
10
+ { from: "waiting", load: loadWaiting, apply: upgradeCommandWaitChecks },
11
+ { from: "checked", load: loadCurrent, apply: upgradeSpendingIndexes },
12
+ { from: "indexed", load: loadCurrent, apply: upgradeEventIndexes },
8
13
  ];
9
14
  export function upgradeSteps(kind) {
10
15
  const first = upgrades.findIndex((step) => step.from === kind);
@@ -1,3 +1,4 @@
1
+ import { commandWaitDeadline } from "../command-wait-restore.js";
1
2
  import { createHash } from "node:crypto";
2
3
  import { delivers, isSettled } from "../../authority/gates.js";
3
4
  import { eligibleIntents, } from "../../authority/reducer.js";
@@ -26,6 +27,7 @@ export function protectedIntent(state, attempt) {
26
27
  .filter((lease) => lease.resourceKey === operation.leaseKey)
27
28
  .map((lease) => ({
28
29
  ...intent,
30
+ ...commandWaitDeadline(state.commandWaits ?? {}, operation.operationId),
29
31
  workflow,
30
32
  purpose,
31
33
  inputDigest: operation.inputDigest,
@@ -16,4 +16,4 @@ export interface Attempt {
16
16
  readonly effectId: string;
17
17
  }
18
18
  export declare function deliverEffect(parts: EffectDelivery, attempt: Attempt): Promise<JsonObject>;
19
- export declare function protectedArguments(value: JsonObject): EffectArguments;
19
+ export declare function protectedArguments(value: JsonObject): EffectArguments & Pick<ProtectedIntent, "commandDeadline">;
@@ -1,3 +1,4 @@
1
+ import { dispatchCommandWait, readCommandWaitDeadline, } from "../command-wait-restore.js";
1
2
  import { dispatchDecision, } from "../../authority/dispatch-decision.js";
2
3
  import { integer, optionalInteger, optionalText, text, } from "../../storage/domain-rows.js";
3
4
  import { budgetRow } from "../../storage/effect-rows.js";
@@ -16,11 +17,16 @@ const absent = {
16
17
  budget: undefined,
17
18
  };
18
19
  async function dispatchRead(connection, attempt) {
19
- const row = await connection.get("SELECT d.outcome, d.input_digest, a.lease_generation, o.released_sequence, r.status, r.workflow, p.status AS operation_status, p.capability, p.units, l.operation_id AS lease_owner, l.generation, l.expires_at, l.state AS lease_state, b.run_id, b.effect_limit, b.spent, b.capabilities, b.exhausted_sequence FROM deliveries d JOIN outbox o ON o.operation_id = d.operation_id JOIN runs r ON r.run_id = o.run_id JOIN dispatch_attempts a ON a.effect_id = d.effect_id JOIN operations p ON p.operation_id = d.operation_id JOIN leases l ON l.resource_key = p.lease_key JOIN run_budgets b ON b.run_id = o.run_id WHERE d.effect_id = ? AND d.operation_id = ?", [attempt.effectId, attempt.intent.operationId]);
20
+ const row = await connection.get("SELECT d.outcome, d.input_digest, a.lease_generation, o.released_sequence, r.status, r.workflow, p.status AS operation_status, p.capability, p.units, p.method, p.target, p.payload, l.operation_id AS lease_owner, l.generation, l.expires_at, l.state AS lease_state, b.run_id, b.effect_limit, b.spent, b.capabilities, b.exhausted_sequence FROM deliveries d JOIN outbox o ON o.operation_id = d.operation_id JOIN runs r ON r.run_id = o.run_id JOIN dispatch_attempts a ON a.effect_id = d.effect_id JOIN operations p ON p.operation_id = d.operation_id JOIN leases l ON l.resource_key = p.lease_key JOIN run_budgets b ON b.run_id = o.run_id WHERE d.effect_id = ? AND d.operation_id = ?", [attempt.effectId, attempt.intent.operationId]);
20
21
  if (row === undefined)
21
22
  return absent;
22
23
  const workflow = text(row, "workflow");
23
24
  return {
25
+ ...(await dispatchCommandWait(connection, {
26
+ runId: attempt.intent.runId,
27
+ workflow,
28
+ operationId: attempt.intent.operationId,
29
+ })),
24
30
  attempt: {
25
31
  outcome: optionalText(row, "outcome"),
26
32
  inputDigest: text(row, "input_digest"),
@@ -37,6 +43,9 @@ async function dispatchRead(connection, attempt) {
37
43
  status: text(row, "operation_status"),
38
44
  capability: text(row, "capability"),
39
45
  units: integer(row, "units"),
46
+ method: text(row, "method"),
47
+ target: text(row, "target"),
48
+ payload: text(row, "payload"),
40
49
  },
41
50
  budget: storedBudget(budgetRow(row)),
42
51
  lease: {
@@ -52,7 +61,8 @@ async function called(parts, call) {
52
61
  const adapterCall = parts.delivery[name]?.bind(parts.delivery);
53
62
  if (adapterCall === undefined)
54
63
  return { kind: "unknown", reason: "stop-not-supported" };
55
- return settlement(await parts.calls.call(intent.operationId, (signal) => adapterCall(intent, signal)), intent.capability === "command"
64
+ const deadline = await parts.reader.connection((connection) => readCommandWaitDeadline(connection, intent));
65
+ return settlement(await parts.calls.call(intent.operationId, (signal) => adapterCall({ ...intent, ...deadline }, signal)), intent.capability === "command"
56
66
  ? commandLimits.resultBytes
57
67
  : parts.effects.resultBytes);
58
68
  }
@@ -126,5 +136,8 @@ export function protectedArguments(value) {
126
136
  method: text(value, "method"),
127
137
  target: text(value, "target"),
128
138
  payload: text(value, "payload"),
139
+ ...(typeof value["commandDeadline"] === "string"
140
+ ? { commandDeadline: value["commandDeadline"] }
141
+ : {}),
129
142
  };
130
143
  }
@@ -1,3 +1,5 @@
1
+ import { operationPhase } from "../../operation-identity.js";
2
+ import { endedCommandWaitCheck } from "../../authority/command-waits.js";
1
3
  import { isInstant } from "../../authority/instants.js";
2
4
  import { promotions } from "../../authority/leases.js";
3
5
  import { execute } from "../../authority/reducer.js";
@@ -45,7 +47,9 @@ function closure(state, operation) {
45
47
  return ["run-ended"];
46
48
  const exhausted = (state.effects.budgets[operation.runId]?.exhaustedSequence ?? null) !==
47
49
  null;
48
- return exhausted ? ["budget-exhausted"] : [];
50
+ return exhausted && operationPhase(operation.operationId) !== "command-wait"
51
+ ? ["budget-exhausted"]
52
+ : [];
49
53
  }
50
54
  function unblocked(state, followUp) {
51
55
  const steps = [];
@@ -95,6 +99,9 @@ const outcomes = {
95
99
  }),
96
100
  completed: (attempt) => stated({
97
101
  outcome: "completed",
102
+ ...(attempt.worker === "command"
103
+ ? { commandOutput: attempt.result }
104
+ : {}),
98
105
  result: attempt.result === null ? null : documentDigest(attempt.result),
99
106
  reason: attempt.reason,
100
107
  ...identified(attempt),
@@ -155,7 +162,9 @@ function acceptedNow(reconciling) {
155
162
  export function reconciliations(state, reconciling) {
156
163
  const accepted = acceptedNow(reconciling);
157
164
  const rejected = rejectedReports(reconciling.results);
158
- const due = (operation) => state.runs[operation.runId]?.status !== "cancelled" && live(operation);
165
+ const due = (operation) => state.runs[operation.runId]?.status !== "cancelled" &&
166
+ !endedCommandWaitCheck(state.commandWaits ?? {}, operation.operationId) &&
167
+ live(operation);
159
168
  const live = (operation) => (operation.status === "recovering" &&
160
169
  !accepted.has(operation.operationId)) ||
161
170
  (operation.status === "blocked" && rejected.has(operation.operationId));
@@ -8,6 +8,10 @@ export interface OperationView extends OperationRow {
8
8
  }
9
9
  export type StoredDisposition = Omit<Evidence, "sequence">;
10
10
  export interface EffectQueries {
11
+ readonly workerTurns: (window: {
12
+ readonly after: string;
13
+ readonly through: string;
14
+ }) => Promise<readonly OperationView[]>;
11
15
  readonly operation: (operationId: string) => Promise<OperationView | undefined>;
12
16
  readonly operations: (runId: string) => Promise<readonly OperationView[]>;
13
17
  readonly evidence: (runId: string) => Promise<readonly number[]>;
@@ -34,7 +34,9 @@ const viewColumns = operationColumns
34
34
  .map((name) => `o.${name}`)
35
35
  .join(", ");
36
36
  const waitCause = "CASE WHEN o.status != 'waiting' THEN NULL WHEN r.status != 'running' THEN 'run-not-running' WHEN EXISTS (SELECT 1 FROM leases h WHERE h.resource_key = o.lease_key AND h.state != 'released') THEN 'resource' ELSE 'ready' END";
37
- const viewed = `SELECT ${viewColumns}, l.generation AS lease_generation, ${waitCause} AS wait_cause FROM operations o JOIN runs r ON r.run_id = o.run_id LEFT JOIN leases l ON l.resource_key = o.lease_key AND l.operation_id = o.operation_id AND l.state != 'released'`;
37
+ const viewSelection = `SELECT ${viewColumns}, l.generation AS lease_generation, ${waitCause} AS wait_cause`;
38
+ const viewJoins = "JOIN runs r ON r.run_id = o.run_id LEFT JOIN leases l ON l.resource_key = o.lease_key AND l.operation_id = o.operation_id AND l.state != 'released'";
39
+ const viewed = `${viewSelection} FROM operations o ${viewJoins}`;
38
40
  function operationView(row) {
39
41
  return {
40
42
  ...operationRow(row),
@@ -52,6 +54,11 @@ async function operations(connection, runId) {
52
54
  const rows = await connection.all(`${viewed} WHERE o.run_id = ? ORDER BY o.requested_sequence`, [runId]);
53
55
  return rows.map(operationView);
54
56
  }
57
+ async function workerTurns(connection, window) {
58
+ const settled = await connection.all(`${viewSelection} FROM events e CROSS JOIN operations o ${viewJoins} WHERE o.settled_sequence = e.sequence AND o.capability = 'claude' AND julianday(e.recorded_at) > julianday(?) AND julianday(e.recorded_at) <= julianday(?)`, [window.after, window.through]);
59
+ const open = await connection.all(`${viewSelection} FROM operations o INDEXED BY operations_worker_open ${viewJoins} WHERE o.capability = 'claude' AND o.settled_sequence IS NULL AND o.status NOT IN ('refused', 'completed', 'failed', 'stopped', 'cancelled')`);
60
+ return [...settled, ...open].map(operationView);
61
+ }
55
62
  async function evidence(connection, runId) {
56
63
  const rows = await connection.all("SELECT e.sequence FROM effect_evidence e JOIN events v ON v.sequence = e.sequence WHERE e.run_id = ? AND (e.disposition IN ('rejected', 'denied', 'refused') OR (v.type = 'operation.reconciled' AND json_extract(v.payload, '$.outcome') = 'unknown')) ORDER BY e.sequence", [runId]);
57
64
  return rows.map((row) => integer(row, "sequence"));
@@ -74,6 +81,7 @@ async function budget(connection, runId) {
74
81
  }
75
82
  export function effectQueries(read, settings) {
76
83
  return {
84
+ workerTurns: (window) => read((connection) => workerTurns(connection, window)),
77
85
  stops: (runId) => read((connection) => stops(connection, runId)),
78
86
  closure: (runId) => read((connection) => storedClosure(connection, { runId, stopLimit: settings.stopLimit })),
79
87
  settledAt: (runId) => read((connection) => settledAt(connection, runId)),
@@ -1,3 +1,4 @@
1
+ import { readCommandWaitDeadline } from "../command-wait-restore.js";
1
2
  import { detailColumns, detailRow } from "../../storage/decision-rows.js";
2
3
  import { integer, runRow, text, } from "../../storage/domain-rows.js";
3
4
  import { storedRun } from "../authority-restore.js";
@@ -57,6 +58,7 @@ export async function pendingEffect(connection, attempt) {
57
58
  return {
58
59
  ...intent,
59
60
  purpose,
61
+ ...(await readCommandWaitDeadline(connection, intent)),
60
62
  inputDigest: text(row, "input_digest"),
61
63
  leaseGeneration: integer(row, "generation"),
62
64
  capability: text(row, "capability"),
@@ -1,3 +1,4 @@
1
+ import { endedCommandWaitCheck } from "../../authority/command-waits.js";
1
2
  import { stopAttempts, } from "../../authority/stop-sequence.js";
2
3
  import { observingIntent, protectedIntent, } from "./delivery-intents.js";
3
4
  function present(state, planning) {
@@ -33,9 +34,14 @@ export function presentSubjects(state, planning) {
33
34
  }
34
35
  export function stopIntents(state, planning) {
35
36
  const { runId, stopping } = planning;
36
- if (state.runs[runId]?.status !== "cancelled")
37
- return [];
38
- const subjects = presentSubjects(state, planning);
37
+ const cancelled = state.runs[runId]?.status === "cancelled";
38
+ const subjects = presentSubjects(state, planning).flatMap((subject) => {
39
+ if (endedCommandWaitCheck(state.commandWaits ?? {}, subject.operationId))
40
+ return [
41
+ { ...subject, stopSequence: subject.stopSequence ?? state.sequence },
42
+ ];
43
+ return cancelled ? [subject] : [];
44
+ });
39
45
  return stopAttempts(subjects, {
40
46
  cancelledSequence: planning.cancelledNow[0] ?? stopping.cancelledSequence ?? 0,
41
47
  stopLimit: planning.stopLimit,
@@ -1,4 +1,5 @@
1
1
  import type { StopSubject } from "../../authority/stop-sequence.ts";
2
+ import type { CommandWaitsState } from "../../authority/command-waits.ts";
2
3
  import { type SqlConnection } from "../../storage/domain-rows.ts";
3
4
  export interface Stopping {
4
5
  readonly subjects: readonly StopSubject[];
@@ -10,6 +11,7 @@ export declare function turnStopping(connection: SqlConnection, scope: {
10
11
  readonly runId: string;
11
12
  readonly status: string | undefined;
12
13
  readonly kind: string;
14
+ readonly commandWaits?: CommandWaitsState;
13
15
  }): Promise<Stopping>;
14
16
  export declare function droppedRuns(connection: SqlConnection, rule: {
15
17
  readonly limit: number;