cloving 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. package/README.md +329 -215
  2. package/dist/src/agent-harness-shell.d.ts +2 -1
  3. package/dist/src/agent-harness-shell.js +8 -5
  4. package/dist/src/authority/command-wait-checks.d.ts +8 -0
  5. package/dist/src/authority/command-wait-checks.js +88 -0
  6. package/dist/src/authority/command-wait-results.d.ts +15 -0
  7. package/dist/src/authority/command-wait-results.js +73 -0
  8. package/dist/src/authority/command-wait-view.d.ts +21 -0
  9. package/dist/src/authority/command-wait-view.js +34 -0
  10. package/dist/src/authority/command-waits.d.ts +39 -0
  11. package/dist/src/authority/command-waits.js +97 -0
  12. package/dist/src/authority/commands.js +22 -1
  13. package/dist/src/authority/dispatch-decision.d.ts +8 -0
  14. package/dist/src/authority/dispatch-decision.js +26 -1
  15. package/dist/src/authority/effect-requests.js +6 -3
  16. package/dist/src/authority/effect-results.js +4 -2
  17. package/dist/src/authority/history-state.d.ts +2 -0
  18. package/dist/src/authority/history-state.js +13 -1
  19. package/dist/src/authority/instants.d.ts +1 -0
  20. package/dist/src/authority/instants.js +21 -0
  21. package/dist/src/authority/reduction-state.d.ts +2 -0
  22. package/dist/src/authority/reduction-state.js +5 -0
  23. package/dist/src/authority/reduction.js +24 -0
  24. package/dist/src/authority/status-input.d.ts +2 -0
  25. package/dist/src/authority/status.d.ts +2 -0
  26. package/dist/src/authority/status.js +1 -0
  27. package/dist/src/authority/stop-sequence.d.ts +1 -0
  28. package/dist/src/authority/stop-sequence.js +2 -1
  29. package/dist/src/authority/transitions.d.ts +6 -4
  30. package/dist/src/authority/transitions.js +7 -0
  31. package/dist/src/broker/actor/authority-health.d.ts +9 -0
  32. package/dist/src/broker/actor/authority-health.js +24 -0
  33. package/dist/src/broker/actor/authority-queries.d.ts +2 -1
  34. package/dist/src/broker/actor/authority-queries.js +14 -5
  35. package/dist/src/broker/actor/authority-receipts.js +1 -1
  36. package/dist/src/broker/actor/authority-runtime.d.ts +4 -2
  37. package/dist/src/broker/actor/authority-runtime.js +29 -20
  38. package/dist/src/broker/actor/authority-session.d.ts +6 -19
  39. package/dist/src/broker/actor/authority-session.js +66 -88
  40. package/dist/src/broker/actor/authority-settings.d.ts +2 -1
  41. package/dist/src/broker/actor/authority-settings.js +6 -3
  42. package/dist/src/broker/actor/authority-upgrades.d.ts +23 -2
  43. package/dist/src/broker/actor/authority-upgrades.js +8 -2
  44. package/dist/src/broker/actor/authority-watchdog.d.ts +6 -2
  45. package/dist/src/broker/actor/authority-watchdog.js +31 -9
  46. package/dist/src/broker/actor/authority.js +3 -1
  47. package/dist/src/broker/actor/delivery-intents.js +2 -0
  48. package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
  49. package/dist/src/broker/actor/effect-delivery.js +15 -2
  50. package/dist/src/broker/actor/effect-plan.js +11 -2
  51. package/dist/src/broker/actor/effect-queries.d.ts +4 -0
  52. package/dist/src/broker/actor/effect-queries.js +9 -1
  53. package/dist/src/broker/actor/effect-turn.js +2 -0
  54. package/dist/src/broker/actor/projection-memory.d.ts +43 -0
  55. package/dist/src/broker/actor/projection-memory.js +207 -0
  56. package/dist/src/broker/actor/runtime-parts.d.ts +5 -0
  57. package/dist/src/broker/actor/runtime-parts.js +8 -3
  58. package/dist/src/broker/actor/stop-plan.js +9 -3
  59. package/dist/src/broker/actor/stop-turn.d.ts +2 -0
  60. package/dist/src/broker/actor/stop-turn.js +24 -11
  61. package/dist/src/broker/actor/turn-draft.d.ts +1 -0
  62. package/dist/src/broker/actor/turn-draft.js +4 -0
  63. package/dist/src/broker/actor/turn-state.js +5 -1
  64. package/dist/src/broker/authority-admission.js +60 -0
  65. package/dist/src/broker/authority-restore.d.ts +2 -0
  66. package/dist/src/broker/authority-restore.js +35 -1
  67. package/dist/src/broker/command-wait-restore.d.ts +31 -0
  68. package/dist/src/broker/command-wait-restore.js +86 -0
  69. package/dist/src/broker/decision-restore.d.ts +1 -1
  70. package/dist/src/broker/decision-restore.js +1 -0
  71. package/dist/src/broker/effect-upgrade.d.ts +3 -0
  72. package/dist/src/broker/effect-upgrade.js +11 -2
  73. package/dist/src/cli/arguments.d.ts +13 -0
  74. package/dist/src/cli/arguments.js +43 -3
  75. package/dist/src/cli/chat-stores.d.ts +2 -0
  76. package/dist/src/cli/chat-stores.js +113 -0
  77. package/dist/src/cli/client.d.ts +7 -2
  78. package/dist/src/cli/client.js +13 -7
  79. package/dist/src/cli/command-requests.d.ts +46 -0
  80. package/dist/src/cli/command-requests.js +84 -0
  81. package/dist/src/cli/command-waits.d.ts +9 -0
  82. package/dist/src/cli/command-waits.js +51 -0
  83. package/dist/src/cli/commands.js +70 -88
  84. package/dist/src/cli/config-file.d.ts +2 -2
  85. package/dist/src/cli/config-file.js +4 -2
  86. package/dist/src/cli/config-notice.js +5 -2
  87. package/dist/src/cli/doctor-retention.d.ts +2 -0
  88. package/dist/src/cli/doctor-retention.js +93 -0
  89. package/dist/src/cli/doctor-workflows.d.ts +5 -2
  90. package/dist/src/cli/doctor-workflows.js +12 -7
  91. package/dist/src/cli/doctor.js +11 -9
  92. package/dist/src/cli/harness-probes.d.ts +2 -0
  93. package/dist/src/cli/harness-probes.js +1 -1
  94. package/dist/src/cli/harness-processes.d.ts +6 -0
  95. package/dist/src/cli/harness-processes.js +36 -0
  96. package/dist/src/cli/init-command.d.ts +9 -0
  97. package/dist/src/cli/init-command.js +52 -0
  98. package/dist/src/cli/init-prompt-command.d.ts +10 -0
  99. package/dist/src/cli/init-prompt-command.js +145 -0
  100. package/dist/src/cli/init-prompt.d.ts +35 -0
  101. package/dist/src/cli/init-prompt.js +74 -0
  102. package/dist/src/cli/init-selection.d.ts +13 -0
  103. package/dist/src/cli/init-selection.js +75 -0
  104. package/dist/src/cli/main.d.ts +2 -0
  105. package/dist/src/cli/main.js +37 -7
  106. package/dist/src/cli/mcp-server.d.ts +1 -0
  107. package/dist/src/cli/mcp-server.js +156 -0
  108. package/dist/src/cli/mcp-tools.d.ts +15 -0
  109. package/dist/src/cli/mcp-tools.js +242 -0
  110. package/dist/src/cli/queue-arguments.d.ts +15 -0
  111. package/dist/src/cli/queue-arguments.js +31 -0
  112. package/dist/src/cli/queue-render.d.ts +3 -0
  113. package/dist/src/cli/queue-render.js +26 -0
  114. package/dist/src/cli/reload-render.d.ts +2 -0
  115. package/dist/src/cli/reload-render.js +12 -0
  116. package/dist/src/cli/render.d.ts +1 -1
  117. package/dist/src/cli/render.js +54 -38
  118. package/dist/src/cli/report-ci-jobs.d.ts +23 -0
  119. package/dist/src/cli/report-ci-jobs.js +103 -0
  120. package/dist/src/cli/report-ci-usage.d.ts +9 -0
  121. package/dist/src/cli/report-ci-usage.js +185 -0
  122. package/dist/src/cli/report-ci.d.ts +13 -0
  123. package/dist/src/cli/report-ci.js +74 -0
  124. package/dist/src/cli/report-closures.d.ts +6 -0
  125. package/dist/src/cli/report-closures.js +97 -0
  126. package/dist/src/cli/report-flow.d.ts +7 -0
  127. package/dist/src/cli/report-flow.js +122 -0
  128. package/dist/src/cli/report-github-reader.d.ts +29 -0
  129. package/dist/src/cli/report-github-reader.js +157 -0
  130. package/dist/src/cli/report-github.d.ts +15 -8
  131. package/dist/src/cli/report-github.js +131 -150
  132. package/dist/src/cli/report-operator.d.ts +3 -0
  133. package/dist/src/cli/report-operator.js +40 -0
  134. package/dist/src/cli/report-ready.d.ts +3 -0
  135. package/dist/src/cli/report-ready.js +96 -0
  136. package/dist/src/cli/report-text.d.ts +9 -0
  137. package/dist/src/cli/report-text.js +33 -0
  138. package/dist/src/cli/report.d.ts +1 -0
  139. package/dist/src/cli/report.js +104 -27
  140. package/dist/src/cli/runtime-arguments.d.ts +18 -3
  141. package/dist/src/cli/runtime-arguments.js +29 -20
  142. package/dist/src/cli/schedule-arguments.d.ts +14 -0
  143. package/dist/src/cli/schedule-arguments.js +26 -0
  144. package/dist/src/cli/schedule-render.d.ts +22 -0
  145. package/dist/src/cli/schedule-render.js +73 -0
  146. package/dist/src/cli/terminal-text.d.ts +3 -0
  147. package/dist/src/cli/terminal-text.js +28 -0
  148. package/dist/src/cli/toolchain.d.ts +1 -0
  149. package/dist/src/cli/toolchain.js +1 -0
  150. package/dist/src/cli/usage-render.d.ts +1 -0
  151. package/dist/src/cli/usage-render.js +28 -1
  152. package/dist/src/cli/usage.d.ts +2 -2
  153. package/dist/src/cli/usage.js +89 -11
  154. package/dist/src/cli/watch-actions.js +2 -2
  155. package/dist/src/cli/watch-api-document.d.ts +430 -0
  156. package/dist/src/cli/watch-api-document.js +291 -0
  157. package/dist/src/cli/watch-api-run.d.ts +56 -0
  158. package/dist/src/cli/watch-api-run.js +112 -0
  159. package/dist/src/cli/watch-api.d.ts +17 -0
  160. package/dist/src/cli/watch-api.js +230 -0
  161. package/dist/src/cli/watch-board-view.js +19 -2
  162. package/dist/src/cli/watch-board.d.ts +4 -2
  163. package/dist/src/cli/watch-board.js +53 -43
  164. package/dist/src/cli/watch-card-forms.d.ts +1 -1
  165. package/dist/src/cli/watch-card-forms.js +11 -10
  166. package/dist/src/cli/watch-client.d.ts +1 -1
  167. package/dist/src/cli/watch-client.js +2 -11
  168. package/dist/src/cli/watch-header-view.d.ts +1 -5
  169. package/dist/src/cli/watch-header-view.js +17 -21
  170. package/dist/src/cli/watch-model.d.ts +5 -1
  171. package/dist/src/cli/watch-model.js +20 -11
  172. package/dist/src/cli/watch-page.js +15 -15
  173. package/dist/src/cli/watch-phases.d.ts +12 -3
  174. package/dist/src/cli/watch-phases.js +68 -11
  175. package/dist/src/cli/watch-pr-board.js +1 -1
  176. package/dist/src/cli/watch-pr-command.d.ts +1 -0
  177. package/dist/src/cli/watch-pull-request.js +18 -8
  178. package/dist/src/cli/watch-reads.d.ts +3 -0
  179. package/dist/src/cli/watch-reads.js +22 -20
  180. package/dist/src/cli/watch-render.d.ts +15 -0
  181. package/dist/src/cli/watch-run-input.d.ts +0 -1
  182. package/dist/src/cli/watch-run-input.js +0 -13
  183. package/dist/src/cli/watch-server.js +24 -10
  184. package/dist/src/cli/watch-view.d.ts +0 -3
  185. package/dist/src/cli/watch-view.js +13 -13
  186. package/dist/src/cli.js +73 -12
  187. package/dist/src/command-wait.d.ts +4 -0
  188. package/dist/src/command-wait.js +45 -0
  189. package/dist/src/configuration-change.d.ts +7 -0
  190. package/dist/src/configuration-change.js +14 -0
  191. package/dist/src/configuration-display.js +2 -0
  192. package/dist/src/configuration-schema.d.ts +14 -0
  193. package/dist/src/configuration-schema.js +6 -2
  194. package/dist/src/daemon/attachment-file.d.ts +6 -0
  195. package/dist/src/daemon/attachment-file.js +86 -0
  196. package/dist/src/daemon/attachments.d.ts +14 -0
  197. package/dist/src/daemon/attachments.js +17 -0
  198. package/dist/src/daemon/claude-recovery.d.ts +50 -0
  199. package/dist/src/daemon/claude-recovery.js +208 -0
  200. package/dist/src/daemon/claude-stream.d.ts +27 -0
  201. package/dist/src/daemon/claude-stream.js +63 -0
  202. package/dist/src/daemon/claude-turn.d.ts +11 -25
  203. package/dist/src/daemon/claude-turn.js +64 -81
  204. package/dist/src/daemon/claude-worker.d.ts +5 -4
  205. package/dist/src/daemon/claude-worker.js +127 -126
  206. package/dist/src/daemon/daemon-adapters.d.ts +9 -0
  207. package/dist/src/daemon/daemon-adapters.js +33 -5
  208. package/dist/src/daemon/daemon-loops.d.ts +5 -1
  209. package/dist/src/daemon/daemon-loops.js +18 -10
  210. package/dist/src/daemon/daemon.js +80 -61
  211. package/dist/src/daemon/github-attach.d.ts +2 -0
  212. package/dist/src/daemon/github-attach.js +222 -0
  213. package/dist/src/daemon/github-calls.js +1 -1
  214. package/dist/src/daemon/github-ci-filters.d.ts +6 -0
  215. package/dist/src/daemon/github-ci-filters.js +138 -0
  216. package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
  217. package/dist/src/daemon/github-ci-workflows.js +148 -0
  218. package/dist/src/daemon/github-ci.js +22 -4
  219. package/dist/src/daemon/github-issue-methods.d.ts +2 -0
  220. package/dist/src/daemon/github-issue-methods.js +37 -2
  221. package/dist/src/daemon/github-merge-call.d.ts +2 -1
  222. package/dist/src/daemon/github-merge-call.js +10 -3
  223. package/dist/src/daemon/github-merge.js +52 -24
  224. package/dist/src/daemon/github-methods.js +18 -4
  225. package/dist/src/daemon/github-operation.d.ts +4 -0
  226. package/dist/src/daemon/github-operation.js +6 -0
  227. package/dist/src/daemon/github-worker.d.ts +4 -0
  228. package/dist/src/daemon/github-worker.js +6 -0
  229. package/dist/src/daemon/issue-queue.d.ts +4 -1
  230. package/dist/src/daemon/issue-queue.js +76 -78
  231. package/dist/src/daemon/merge-turns.d.ts +10 -0
  232. package/dist/src/daemon/merge-turns.js +37 -0
  233. package/dist/src/daemon/notify-events.d.ts +6 -0
  234. package/dist/src/daemon/notify-events.js +84 -0
  235. package/dist/src/daemon/notify-journal.js +1 -1
  236. package/dist/src/daemon/notify-message.d.ts +4 -1
  237. package/dist/src/daemon/notify-message.js +36 -0
  238. package/dist/src/daemon/notify.d.ts +1 -1
  239. package/dist/src/daemon/notify.js +5 -77
  240. package/dist/src/daemon/operation-journal.d.ts +1 -0
  241. package/dist/src/daemon/queue-control.d.ts +13 -0
  242. package/dist/src/daemon/queue-control.js +86 -0
  243. package/dist/src/daemon/queue-journal.d.ts +20 -0
  244. package/dist/src/daemon/queue-journal.js +89 -0
  245. package/dist/src/daemon/queue-status.d.ts +9 -3
  246. package/dist/src/daemon/queue-status.js +17 -4
  247. package/dist/src/daemon/record-archive.d.ts +19 -0
  248. package/dist/src/daemon/record-archive.js +82 -0
  249. package/dist/src/daemon/record-sweep.d.ts +24 -0
  250. package/dist/src/daemon/record-sweep.js +147 -0
  251. package/dist/src/daemon/resume-index-lock.d.ts +13 -0
  252. package/dist/src/daemon/resume-index-lock.js +160 -0
  253. package/dist/src/daemon/resume-worktree.d.ts +7 -0
  254. package/dist/src/daemon/resume-worktree.js +29 -0
  255. package/dist/src/daemon/retrying-turn.d.ts +2 -12
  256. package/dist/src/daemon/retrying-turn.js +98 -172
  257. package/dist/src/daemon/schedule-control.d.ts +26 -0
  258. package/dist/src/daemon/schedule-control.js +110 -0
  259. package/dist/src/daemon/schedule-journal.d.ts +2 -15
  260. package/dist/src/daemon/schedule-journal.js +67 -4
  261. package/dist/src/daemon/settings-reload.d.ts +26 -0
  262. package/dist/src/daemon/settings-reload.js +82 -0
  263. package/dist/src/daemon/ticket-registration.d.ts +2 -7
  264. package/dist/src/daemon/ticket-registration.js +15 -81
  265. package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
  266. package/dist/src/daemon/turn-attempt-journal.js +136 -0
  267. package/dist/src/daemon/turn-attempts.d.ts +47 -0
  268. package/dist/src/daemon/turn-attempts.js +166 -0
  269. package/dist/src/daemon/turn-details.d.ts +4 -0
  270. package/dist/src/daemon/turn-details.js +33 -0
  271. package/dist/src/daemon/turn-report.d.ts +8 -1
  272. package/dist/src/daemon/turn-report.js +39 -0
  273. package/dist/src/daemon/work-tree.d.ts +9 -0
  274. package/dist/src/daemon/work-tree.js +20 -0
  275. package/dist/src/daemon/worker-profile.d.ts +9 -0
  276. package/dist/src/daemon/worker-profile.js +44 -0
  277. package/dist/src/daemon/workflow-generations.d.ts +7 -4
  278. package/dist/src/daemon/workflow-generations.js +22 -14
  279. package/dist/src/daemon/workflow-reload.d.ts +41 -0
  280. package/dist/src/daemon/workflow-reload.js +244 -0
  281. package/dist/src/daemon/workflow-replay.d.ts +2 -1
  282. package/dist/src/daemon/workflow-replay.js +7 -3
  283. package/dist/src/daemon/workflow-schedules.d.ts +3 -0
  284. package/dist/src/daemon/workflow-schedules.js +98 -45
  285. package/dist/src/daemon/worktree-processes.d.ts +9 -0
  286. package/dist/src/daemon/worktree-processes.js +151 -0
  287. package/dist/src/doctor-report.d.ts +4 -6
  288. package/dist/src/doctor-report.js +8 -13
  289. package/dist/src/harness-start.d.ts +15 -0
  290. package/dist/src/harness-start.js +37 -0
  291. package/dist/src/host/command-wait.d.ts +38 -0
  292. package/dist/src/host/command-wait.js +115 -0
  293. package/dist/src/host/start-delivery.d.ts +5 -7
  294. package/dist/src/host/start-delivery.js +3 -15
  295. package/dist/src/host/step-bridge-host.d.ts +2 -0
  296. package/dist/src/host/step-bridge-host.js +21 -0
  297. package/dist/src/operation-identity.d.ts +1 -0
  298. package/dist/src/operation-identity.js +4 -0
  299. package/dist/src/private-config.schema.json +71 -0
  300. package/dist/src/project-config.schema.json +40 -0
  301. package/dist/src/project-settings.d.ts +16 -2
  302. package/dist/src/project-settings.js +35 -1
  303. package/dist/src/queue-spend.d.ts +4 -0
  304. package/dist/src/queue-spend.js +21 -0
  305. package/dist/src/queue-state.d.ts +26 -0
  306. package/dist/src/queue-state.js +34 -0
  307. package/dist/src/record-retention.d.ts +46 -0
  308. package/dist/src/record-retention.js +81 -0
  309. package/dist/src/relay/relay-service.d.ts +3 -0
  310. package/dist/src/relay/relay-service.js +5 -3
  311. package/dist/src/report-ci.d.ts +164 -0
  312. package/dist/src/report-ci.js +32 -0
  313. package/dist/src/report-effects.d.ts +15 -0
  314. package/dist/src/report-effects.js +212 -0
  315. package/dist/src/report-flow-types.d.ts +38 -0
  316. package/dist/src/report-flow-types.js +7 -0
  317. package/dist/src/report-flow.d.ts +43 -0
  318. package/dist/src/report-flow.js +193 -0
  319. package/dist/src/report-operator.d.ts +67 -0
  320. package/dist/src/report-operator.js +25 -0
  321. package/dist/src/report-quality.d.ts +221 -0
  322. package/dist/src/report-quality.js +94 -0
  323. package/dist/src/report-ready.d.ts +23 -0
  324. package/dist/src/report-ready.js +117 -0
  325. package/dist/src/report-statistics.d.ts +2 -1
  326. package/dist/src/report-statistics.js +40 -4
  327. package/dist/src/report.d.ts +588 -47
  328. package/dist/src/report.js +156 -41
  329. package/dist/src/schedule-progress.d.ts +33 -0
  330. package/dist/src/schedule-progress.js +45 -0
  331. package/dist/src/service/active-tickets.js +11 -6
  332. package/dist/src/service/command-waits.d.ts +34 -0
  333. package/dist/src/service/command-waits.js +86 -0
  334. package/dist/src/service/dispatcher.d.ts +4 -0
  335. package/dist/src/service/dispatcher.js +33 -0
  336. package/dist/src/service/expiry.js +2 -0
  337. package/dist/src/service/gateway.js +3 -1
  338. package/dist/src/service/queue-handlers.d.ts +4 -0
  339. package/dist/src/service/queue-handlers.js +32 -0
  340. package/dist/src/service/queue-spend.d.ts +6 -0
  341. package/dist/src/service/queue-spend.js +68 -0
  342. package/dist/src/service/registry.d.ts +28 -2
  343. package/dist/src/service/registry.js +48 -0
  344. package/dist/src/service/replies.d.ts +22 -8
  345. package/dist/src/service/replies.js +16 -2
  346. package/dist/src/service/run-handlers.js +37 -12
  347. package/dist/src/service/run-metadata.d.ts +15 -1
  348. package/dist/src/service/run-metadata.js +93 -8
  349. package/dist/src/service/service.d.ts +11 -3
  350. package/dist/src/service/service.js +22 -37
  351. package/dist/src/service/submission-handler.js +18 -4
  352. package/dist/src/service/worker-port.js +9 -1
  353. package/dist/src/service/worker-totals.d.ts +6 -0
  354. package/dist/src/service/worker-totals.js +8 -1
  355. package/dist/src/service/workflow-reload.d.ts +35 -0
  356. package/dist/src/service/workflow-reload.js +52 -0
  357. package/dist/src/step-bridge.d.ts +20 -0
  358. package/dist/src/steps/command-wait.d.ts +12 -0
  359. package/dist/src/steps/command-wait.js +26 -0
  360. package/dist/src/steps/open-decision-wait.d.ts +2 -0
  361. package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
  362. package/dist/src/steps/review-by-person.js +4 -1
  363. package/dist/src/steps/wait-for-command.d.ts +3 -0
  364. package/dist/src/steps/wait-for-command.js +17 -0
  365. package/dist/src/steps/wait-for-decision.js +1 -1
  366. package/dist/src/storage/command-wait-rows.d.ts +30 -0
  367. package/dist/src/storage/command-wait-rows.js +96 -0
  368. package/dist/src/storage/decision-snapshots.d.ts +8 -2
  369. package/dist/src/storage/decision-snapshots.js +16 -8
  370. package/dist/src/storage/domain-changes.d.ts +3 -1
  371. package/dist/src/storage/domain-changes.js +4 -0
  372. package/dist/src/storage/domain-schema.d.ts +16 -1
  373. package/dist/src/storage/domain-schema.js +35 -4
  374. package/dist/src/storage/effect-schema.d.ts +2 -0
  375. package/dist/src/storage/effect-schema.js +9 -0
  376. package/dist/src/storage/projection-changes.d.ts +12 -0
  377. package/dist/src/storage/projection-changes.js +194 -0
  378. package/dist/src/storage/projection-lookups.d.ts +7 -0
  379. package/dist/src/storage/projection-lookups.js +30 -0
  380. package/dist/src/testing-requests.d.ts +15 -0
  381. package/dist/src/testing-requests.js +93 -0
  382. package/dist/src/testing.d.ts +4 -10
  383. package/dist/src/testing.js +33 -86
  384. package/dist/src/worker-usage.d.ts +1 -0
  385. package/dist/src/worker-usage.js +3 -0
  386. package/dist/src/workflow-candidate.d.ts +1 -0
  387. package/dist/src/workflow-candidate.js +12 -1
  388. package/dist/src/workflow-contracts.d.ts +1 -0
  389. package/dist/src/workflow-contracts.js +9 -2
  390. package/dist/src/workflow-declaration.d.ts +1 -0
  391. package/dist/src/workflow-declaration.js +3 -0
  392. package/dist/src/workflow-discovery.d.ts +2 -13
  393. package/dist/src/workflow-discovery.js +1 -13
  394. package/dist/src/workflow-refusals.js +0 -1
  395. package/dist/src/workflows.d.ts +1 -1
  396. package/dist/src/workflows.js +1 -1
  397. package/dist/tools/compile-workflows.js +3 -0
  398. package/dist/tools/project-configuration.d.ts +7 -2
  399. package/dist/tools/project-configuration.js +30 -1
  400. package/dist/tools/red-green-command.d.ts +1 -0
  401. package/dist/tools/red-green-command.js +174 -0
  402. package/dist/tools/red-green-process.d.ts +10 -0
  403. package/dist/tools/red-green-process.js +59 -0
  404. package/dist/tools/self-host-processes.d.ts +2 -0
  405. package/dist/tools/self-host-processes.js +69 -26
  406. package/dist/tools/self-host-project.d.ts +2 -0
  407. package/dist/tools/self-host-project.js +30 -77
  408. package/dist/tools/self-host-runtime.js +1 -1
  409. package/dist/tools/self-host.js +76 -34
  410. package/dist/tools/template-command.d.ts +1 -0
  411. package/dist/tools/template-command.js +160 -0
  412. package/dist/tools/template-copy.d.ts +11 -0
  413. package/dist/tools/template-copy.js +130 -0
  414. package/dist/tools/template-files.d.ts +17 -0
  415. package/dist/tools/template-files.js +74 -0
  416. package/dist/tools/workflow-bundles.js +1 -0
  417. package/dist/tools/workflow-candidate-counts.js +2 -2
  418. package/dist/tools/workflow-candidate-program.d.ts +4 -2
  419. package/dist/tools/workflow-candidate-program.js +30 -11
  420. package/dist/tools/workflow-candidate-shape.d.ts +3 -0
  421. package/dist/tools/workflow-candidate-shape.js +90 -0
  422. package/dist/tools/workflow-candidate-source.d.ts +1 -0
  423. package/dist/tools/workflow-candidate-source.js +26 -4
  424. package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
  425. package/dist/tools/workflow-candidate-syntax.js +24 -94
  426. package/dist/tools/workflow-command.js +1 -2
  427. package/dist/tools/workflow-folders.d.ts +2 -3
  428. package/dist/tools/workflow-folders.js +1 -1
  429. package/package.json +17 -9
  430. package/templates/develop/README.md +93 -4
  431. package/templates/develop/develop/flow-tests.ts +38 -1
  432. package/templates/develop/develop/interruption-tests.ts +157 -0
  433. package/templates/develop/develop/local.ts +1 -0
  434. package/templates/develop/develop/option-tests.ts +138 -9
  435. package/templates/develop/develop/pull.ts +5 -1
  436. package/templates/develop/develop/red-green.ts +55 -0
  437. package/templates/develop/develop/refusal-tests.ts +77 -0
  438. package/templates/develop/develop/report.ts +31 -11
  439. package/templates/develop/develop/round.ts +1 -0
  440. package/templates/develop/develop/scenarios.ts +27 -0
  441. package/templates/develop/develop/turn.ts +28 -7
  442. package/templates/develop/develop.declaration.json +1 -1
  443. package/templates/develop/develop.test.ts +4 -0
  444. package/templates/develop/template.json +29 -2
  445. package/templates/idea-to-issue/README.md +27 -0
  446. package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
  447. package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
  448. package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
  449. package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
  450. package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
  451. package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
  452. package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
  453. package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
  454. package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
  455. package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
  456. package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
  457. package/templates/idea-to-issue/idea-to-issue.ts +49 -0
  458. package/templates/idea-to-issue/template.json +81 -0
  459. package/templates/review-day/README.md +97 -0
  460. package/templates/review-day/review-day/critique.ts +58 -0
  461. package/templates/review-day/review-day/decision.ts +29 -0
  462. package/templates/review-day/review-day/facts.ts +69 -0
  463. package/templates/review-day/review-day/label.ts +29 -0
  464. package/templates/review-day/review-day/next.ts +28 -0
  465. package/templates/review-day/review-day/post.ts +27 -0
  466. package/templates/review-day/review-day/report.ts +98 -0
  467. package/templates/review-day/review-day/rules.ts +12 -0
  468. package/templates/review-day/review-day/scenarios.ts +76 -0
  469. package/templates/review-day/review-day/turn.ts +73 -0
  470. package/templates/review-day/review-day.declaration.json +16 -0
  471. package/templates/review-day/review-day.test.ts +362 -0
  472. package/templates/review-day/review-day.ts +37 -0
  473. package/templates/review-day/template.json +56 -0
  474. package/dist/src/cli/watch-start-view.d.ts +0 -18
  475. package/dist/src/cli/watch-start-view.js +0 -77
  476. package/dist/src/steps/decision-gate.d.ts +0 -3
  477. package/dist/workflows/develop-prd.d.ts +0 -7
  478. package/dist/workflows/develop-prd.js +0 -165
  479. package/dist/workflows/develop-ticket.d.ts +0 -9
  480. package/dist/workflows/develop-ticket.js +0 -207
  481. package/dist/workflows/issue-labels.d.ts +0 -16
  482. package/dist/workflows/issue-labels.js +0 -70
  483. package/dist/workflows/ticket-prompts.d.ts +0 -35
  484. package/dist/workflows/ticket-prompts.js +0 -147
@@ -0,0 +1,33 @@
1
+ import { stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { located } from "./operation-journal.js";
4
+ import { archiveFolder } from "./record-sweep.js";
5
+ import { turnDetails, } from "../record-retention.js";
6
+ function absent(error) {
7
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
8
+ }
9
+ async function present(journal, operationIds) {
10
+ const found = await Promise.all(operationIds.map((operationId) => stat(located(journal, operationId).folder).then(() => true, (error) => (absent(error) ? false : undefined))));
11
+ if (found.includes(undefined))
12
+ return undefined;
13
+ return found.filter(Boolean).length;
14
+ }
15
+ export function turnDetailsPlace(settings) {
16
+ return async ({ runId, operationIds }) => {
17
+ const archive = join(archiveFolder(settings), "journal");
18
+ const runs = await settings.runs([runId]);
19
+ const archived = await present(archive, operationIds);
20
+ const kept = await present(join(settings.directory, "journal"), operationIds);
21
+ if (archived === undefined || kept === undefined)
22
+ return undefined;
23
+ return turnDetails({
24
+ turns: operationIds.length,
25
+ kept,
26
+ archived: archived === 0 ? undefined : archive,
27
+ }, {
28
+ run: Object.hasOwn(runs, runId) ? runs[runId] : undefined,
29
+ retention: settings.retention,
30
+ now: settings.now(),
31
+ });
32
+ };
33
+ }
@@ -1,5 +1,6 @@
1
+ import type { Recorded } from "./operation-journal.ts";
1
2
  import { type WorkTree } from "./work-tree.ts";
2
- import type { StreamResult } from "./claude-turn.ts";
3
+ import { type StreamResult, type TurnEnd } from "./claude-turn.ts";
3
4
  interface ReportLimits {
4
5
  readonly summaryCharacters: number;
5
6
  readonly resultBytes: number;
@@ -15,4 +16,10 @@ export declare function turnReport(start: {
15
16
  readonly text?: string;
16
17
  readonly reason?: string;
17
18
  }>;
19
+ export declare function turnOutcome(running: Parameters<typeof turnReport>[0] & {
20
+ readonly stopping: {
21
+ readonly requested: boolean;
22
+ readonly stoppedBy?: "daemon-shutdown";
23
+ };
24
+ }, end: TurnEnd): Promise<Recorded>;
18
25
  export {};
@@ -2,6 +2,7 @@ import { ticketStatus } from "../ticket-status.js";
2
2
  import { reviewReport } from "../review-subject.js";
3
3
  import { sumPrices } from "../worker-usage.js";
4
4
  import { changes } from "./work-tree.js";
5
+ import { succeeded } from "./claude-turn.js";
5
6
  function tailReport(fields, limit) {
6
7
  let text = JSON.stringify({ ...fields, summary: "" });
7
8
  if (Buffer.byteLength(text) > limit)
@@ -77,3 +78,41 @@ export async function turnReport(start, result) {
77
78
  turns: result.turns,
78
79
  }, { ...harness, limit: limits.resultBytes });
79
80
  }
81
+ export async function turnOutcome(running, end) {
82
+ const endedAt = new Date().toISOString();
83
+ if (end.stopped === true && running.stopping.stoppedBy === "daemon-shutdown")
84
+ return stoppedOutcome(running.stopping, endedAt);
85
+ const { result } = end;
86
+ const report = result === undefined
87
+ ? {}
88
+ : await turnReport({
89
+ tree: running.tree,
90
+ harness: running.harness,
91
+ limits: running.limits,
92
+ }, result);
93
+ const { text, reason } = report;
94
+ if (succeeded(end) && reason === undefined && text !== undefined)
95
+ return { outcome: "completed", result: text, endedAt };
96
+ if (running.stopping.requested)
97
+ return stoppedOutcome(running.stopping, endedAt);
98
+ return failedOutcome(end, { ...report, endedAt });
99
+ }
100
+ function failedOutcome(end, report) {
101
+ const { text, reason, endedAt } = report;
102
+ return {
103
+ outcome: "failed",
104
+ reason: end.reason ?? reason ?? "claude-turn-failed",
105
+ ...(end.detail === undefined ? {} : { detail: end.detail }),
106
+ ...(text === undefined ? {} : { result: text }),
107
+ endedAt,
108
+ };
109
+ }
110
+ function stoppedOutcome(stopping, endedAt) {
111
+ return {
112
+ outcome: "stopped",
113
+ endedAt,
114
+ ...(stopping.stoppedBy === undefined
115
+ ? {}
116
+ : { stoppedBy: stopping.stoppedBy }),
117
+ };
118
+ }
@@ -25,3 +25,12 @@ export declare function treePlace(request: Pick<TreeRequest, "worktrees" | "targ
25
25
  export declare function workTree(request: TreeRequest): Promise<WorkTree>;
26
26
  export declare function treeFailure(error: unknown): string;
27
27
  export declare function changes(tree: WorkTree): Promise<Changes>;
28
+ export declare function firstTurn(settings: {
29
+ readonly journal: string;
30
+ }, opening: {
31
+ readonly tree: WorkTree;
32
+ readonly intent: {
33
+ readonly target: string;
34
+ readonly runId: string;
35
+ };
36
+ }): Promise<WorkTree>;
@@ -1,3 +1,4 @@
1
+ import { readRecord, writeRecord, operationKey } from "./operation-journal.js";
1
2
  import { execFile, spawn } from "node:child_process";
2
3
  import { existsSync } from "node:fs";
3
4
  import { mkdir, realpath } from "node:fs/promises";
@@ -207,3 +208,22 @@ async function changeLines(call) {
207
208
  .slice(0, lineLimit)
208
209
  .map((line) => line.slice(0, lineLength));
209
210
  }
211
+ export async function firstTurn(settings, opening) {
212
+ const { tree, intent } = opening;
213
+ const { target, runId } = intent;
214
+ const folder = target.startsWith("branch:")
215
+ ? join(settings.journal, "runs", operationKey(runId), "targets")
216
+ : join(settings.journal, "targets");
217
+ const name = `${operationKey(target)}.json`;
218
+ const record = await readRecord(folder, name);
219
+ const startCommit = typeof record === "object" && record !== null
220
+ ? Reflect.get(record, "startCommit")
221
+ : undefined;
222
+ if (typeof startCommit === "string")
223
+ return { ...tree, startCommit };
224
+ await writeRecord(folder, {
225
+ name,
226
+ value: { target, startCommit: tree.startCommit },
227
+ });
228
+ return tree;
229
+ }
@@ -0,0 +1,9 @@
1
+ import { type HarnessSettings } from "../harness-defaults.ts";
2
+ import type { TurnProfile, TurnProfiles } from "../turn-profile.ts";
3
+ import type { ProtectedIntent } from "../broker/actor/delivery-intents.ts";
4
+ export interface WorkerProfiles extends HarnessSettings {
5
+ readonly profiles?: TurnProfiles;
6
+ readonly workflowId?: (runId: string) => Promise<string | undefined>;
7
+ }
8
+ export declare function checkedProfiles(settings: HarnessSettings, profiles: TurnProfiles): void;
9
+ export declare function selectedProfile(settings: WorkerProfiles, intent: ProtectedIntent): Promise<TurnProfile | string>;
@@ -0,0 +1,44 @@
1
+ import { turnHarness } from "../harness-defaults.js";
2
+ async function runWorkflow(settings, runId) {
3
+ try {
4
+ return await settings.workflowId?.(runId);
5
+ }
6
+ catch {
7
+ return undefined;
8
+ }
9
+ }
10
+ function unsupportedProfile(profile, harness) {
11
+ if (harness.output === "text" && profile.model !== undefined)
12
+ return "profile-model-not-supported";
13
+ if (harness.worker === "claude")
14
+ return undefined;
15
+ return [
16
+ profile.allowedTools,
17
+ profile.permissionMode,
18
+ profile.maxBudgetUsd,
19
+ ].some((value) => value !== undefined)
20
+ ? "profile-needs-claude"
21
+ : undefined;
22
+ }
23
+ export function checkedProfiles(settings, profiles) {
24
+ for (const profile of Object.values(profiles))
25
+ turnHarness(settings, profile);
26
+ }
27
+ export async function selectedProfile(settings, intent) {
28
+ if (intent.method === "run-turn")
29
+ return {};
30
+ const name = intent.method.slice("run-turn:".length);
31
+ const profiles = settings.profiles ?? {};
32
+ const profile = Object.hasOwn(profiles, name) ? profiles[name] : undefined;
33
+ if (profile === undefined)
34
+ return "unknown-profile";
35
+ const unsupported = unsupportedProfile(profile, turnHarness(settings, profile));
36
+ if (unsupported !== undefined)
37
+ return unsupported;
38
+ if (profile.workflows === undefined)
39
+ return profile;
40
+ const workflowId = await runWorkflow(settings, intent.runId);
41
+ if (workflowId === undefined || !profile.workflows.includes(workflowId))
42
+ return "profile-not-allowed";
43
+ return profile;
44
+ }
@@ -8,16 +8,18 @@ export interface WorkflowGeneration {
8
8
  readonly handler: WorkflowHandler;
9
9
  }
10
10
  export type WorkflowBundleLoader = (directory: string) => Promise<WorkflowGeneration>;
11
- export declare function workflowGenerations(settings: {
12
- readonly directory: string;
13
- readonly repository: string;
11
+ export interface CurrentGeneration {
14
12
  readonly registrations: readonly WorkflowRegistration[];
15
13
  readonly table: readonly {
16
14
  readonly workflowId: string;
17
15
  readonly functionName: string;
18
16
  }[];
19
- readonly workflows: Readonly<Record<string, WorkflowFunction | undefined>>;
17
+ readonly workflows: Readonly<Record<string, unknown>>;
20
18
  readonly handler: WorkflowHandler;
19
+ }
20
+ export declare function workflowGenerations(settings: CurrentGeneration & {
21
+ readonly directory: string;
22
+ readonly repository: string;
21
23
  readonly loadBundle?: WorkflowBundleLoader;
22
24
  }): {
23
25
  resolve: (manifest: ExecutionManifest | undefined) => Promise<{
@@ -25,6 +27,7 @@ export declare function workflowGenerations(settings: {
25
27
  handler: WorkflowHandler;
26
28
  } | undefined>;
27
29
  available: (manifest: ExecutionManifest) => Promise<ExecutionManifest | undefined>;
30
+ replace: (source: CurrentGeneration) => void;
28
31
  };
29
32
  export declare function prepareWorkflowGenerations(ports: {
30
33
  readonly state: HostPorts["state"];
@@ -1,26 +1,31 @@
1
1
  import { join } from "node:path";
2
2
  import { workflowRegistry, } from "../service/registry.js";
3
3
  import { workflowPin } from "../broker/workflow-pin.js";
4
+ function isWorkflowFunction(value) {
5
+ return typeof value === "function";
6
+ }
4
7
  export function workflowGenerations(settings) {
5
- const functions = Object.fromEntries(settings.table.map((row) => [
6
- row.workflowId,
7
- settings.workflows[row.functionName],
8
- ]));
9
- const registry = workflowRegistry(settings.registrations, {
10
- workflowBundles: {
11
- directory: join(settings.directory, "workflow-bundles"),
12
- repository: settings.repository,
13
- },
8
+ const workflowBundles = {
9
+ directory: join(settings.directory, "workflow-bundles"),
10
+ repository: settings.repository,
11
+ };
12
+ const generation = (source) => ({
13
+ functions: new Map(source.table.map((row) => [
14
+ row.workflowId,
15
+ source.workflows[row.functionName],
16
+ ])),
17
+ registry: workflowRegistry(source.registrations, { workflowBundles }),
18
+ handler: source.handler,
14
19
  });
20
+ let current = generation(settings);
15
21
  const resolve = async (manifest) => {
16
22
  if (manifest === undefined)
17
23
  return undefined;
24
+ const { functions, registry, handler } = current;
18
25
  const registered = registry.byPin(workflowPin(manifest));
19
26
  if (registered !== undefined) {
20
- const workflow = functions[registered.workflowId];
21
- return workflow === undefined
22
- ? undefined
23
- : { workflow, handler: settings.handler };
27
+ const workflow = functions.get(registered.workflowId);
28
+ return isWorkflowFunction(workflow) ? { workflow, handler } : undefined;
24
29
  }
25
30
  if (manifest.bundleDigest === undefined ||
26
31
  settings.loadBundle === undefined)
@@ -30,7 +35,7 @@ export function workflowGenerations(settings) {
30
35
  return undefined;
31
36
  try {
32
37
  const generation = await settings.loadBundle(directory);
33
- const workflow = Object.values(generation.workflows).find((candidate) => typeof candidate === "function" &&
38
+ const workflow = Object.values(generation.workflows).find((candidate) => isWorkflowFunction(candidate) &&
34
39
  Reflect.get(candidate, "workflowId") === manifest.workflowId);
35
40
  return workflow === undefined
36
41
  ? undefined
@@ -43,6 +48,9 @@ export function workflowGenerations(settings) {
43
48
  return {
44
49
  resolve,
45
50
  available: async (manifest) => (await resolve(manifest)) === undefined ? undefined : manifest,
51
+ replace: (source) => {
52
+ current = generation(source);
53
+ },
46
54
  };
47
55
  }
48
56
  export async function prepareWorkflowGenerations(ports, generations) {
@@ -0,0 +1,41 @@
1
+ import type { WorkflowReloadPort } from "../service/workflow-reload.ts";
2
+ import { type DeclaredWorkflow } from "../workflow-declaration.ts";
3
+ import type { DaemonSettings } from "./daemon-adapters.ts";
4
+ import type { WorkflowBundleLoader, workflowGenerations } from "./workflow-generations.ts";
5
+ import { type TurnSettingsSource } from "./settings-reload.ts";
6
+ export declare function queueWorkflowId(settings: {
7
+ readonly declarations?: readonly DeclaredWorkflow[];
8
+ }): string | undefined;
9
+ export declare function daemonRegistrations(settings: DaemonSettings): Promise<{
10
+ table: readonly import("./ticket-registration.ts").TicketRegistration[];
11
+ admitted: {
12
+ readonly kind: "rejected";
13
+ readonly detail: string;
14
+ } | {
15
+ registrations: {
16
+ admission?: "when-idle" | number;
17
+ queue?: boolean;
18
+ workflowId: string;
19
+ manifest: import("../workflow-admission.ts").ExecutionManifest;
20
+ availability: "available" | "unavailable";
21
+ submission: import("../submission.ts").SubmissionContract;
22
+ resolver: import("../service/registry.ts").Resolver;
23
+ effectLimit?: number;
24
+ stages?: readonly import("../workflow-declaration.ts").WorkflowStage[];
25
+ handoffs?: readonly string[];
26
+ commands?: readonly string[];
27
+ commandWaits?: import("../workflow-declaration.ts").CommandWaits;
28
+ }[];
29
+ kind: "admitted";
30
+ };
31
+ }>;
32
+ type ReloadSettings = DaemonSettings & {
33
+ readonly reloadCommand: readonly string[];
34
+ readonly loadBundle: WorkflowBundleLoader;
35
+ readonly turnSettings: TurnSettingsSource;
36
+ };
37
+ type Generations = Pick<ReturnType<typeof workflowGenerations>, "replace">;
38
+ export declare function workflowReload(settings: ReloadSettings & {
39
+ readonly generations: Generations;
40
+ }): WorkflowReloadPort;
41
+ export {};
@@ -0,0 +1,244 @@
1
+ import { execFile } from "node:child_process";
2
+ import { join } from "node:path";
3
+ import { promisify } from "node:util";
4
+ import { record } from "../protocol.js";
5
+ import { serviceLimits } from "../service/service.js";
6
+ import { isWorkflowDeclaration, } from "../workflow-declaration.js";
7
+ import { workflowRefusals, } from "../workflow-refusals.js";
8
+ import { ticketRegistrations, ticketRegistrationTable, } from "./ticket-registration.js";
9
+ import { scheduledDeclarations } from "./workflow-schedules.js";
10
+ import { keptDigests, profileRefusal, reloadedSettings, settingChanges, } from "./settings-reload.js";
11
+ const executed = promisify(execFile);
12
+ function refused(code, detail) {
13
+ return { kind: "refused", code, detail };
14
+ }
15
+ export function queueWorkflowId(settings) {
16
+ return settings.declarations?.find((declaration) => declaration.queue === true)?.workflowId;
17
+ }
18
+ export async function daemonRegistrations(settings) {
19
+ const conflict = settings.workflowRefusals?.find((refusal) => refusal.codes.includes("queue-workflow-conflict"));
20
+ if (conflict !== undefined)
21
+ return {
22
+ table: [],
23
+ admitted: {
24
+ kind: "rejected",
25
+ detail: `queue-workflow-conflict: ${conflict.scope} ${conflict.label}`,
26
+ },
27
+ };
28
+ const table = ticketRegistrationTable({
29
+ repository: settings.repository,
30
+ command: settings.ticketCommand,
31
+ nextCommand: settings.nextCommand,
32
+ githubCommand: settings.githubCommand,
33
+ }, settings.declarations);
34
+ const admitted = await ticketRegistrations(settings.manifests, {
35
+ table,
36
+ commands: settings.commands ?? {},
37
+ ...(settings.bundleDigest === undefined
38
+ ? {}
39
+ : { bundleDigest: settings.bundleDigest }),
40
+ });
41
+ return {
42
+ table,
43
+ admitted: admitted.kind === "rejected"
44
+ ? admitted
45
+ : {
46
+ ...admitted,
47
+ registrations: admitted.registrations.map((registration) => ({
48
+ ...registration,
49
+ ...(settings.queueMilliseconds !== undefined &&
50
+ registration.workflowId === queueWorkflowId(settings)
51
+ ? { admission: settings.queueLanes ?? 1, queue: true }
52
+ : {}),
53
+ })),
54
+ },
55
+ };
56
+ }
57
+ function declaredWorkflows(value) {
58
+ if (!Array.isArray(value))
59
+ return undefined;
60
+ const declarations = [];
61
+ for (const entry of value) {
62
+ const { functionName, ...declaration } = record(entry) ?? {};
63
+ if (typeof functionName !== "string" || !isWorkflowDeclaration(declaration))
64
+ return undefined;
65
+ declarations.push({ ...declaration, functionName });
66
+ }
67
+ return declarations;
68
+ }
69
+ function manifestPaths(value) {
70
+ const fields = record(value);
71
+ if (fields === undefined)
72
+ return undefined;
73
+ const entries = Object.entries(fields);
74
+ const paths = entries.filter((entry) => typeof entry[1] === "string");
75
+ return paths.length === entries.length
76
+ ? Object.fromEntries(paths)
77
+ : undefined;
78
+ }
79
+ function parsedOutput(output) {
80
+ try {
81
+ return record(JSON.parse(output));
82
+ }
83
+ catch {
84
+ return undefined;
85
+ }
86
+ }
87
+ function outputRefusal(value) {
88
+ const error = value?.["error"];
89
+ if (typeof error === "string")
90
+ return refused("reload-failed", error);
91
+ const refusal = record(value?.["refusal"]);
92
+ const code = refusal?.["code"];
93
+ const detail = refusal?.["detail"];
94
+ return typeof code === "string" && typeof detail === "string"
95
+ ? refused(code, detail)
96
+ : undefined;
97
+ }
98
+ function preparedBundle(output) {
99
+ const value = parsedOutput(output);
100
+ const refusal = outputRefusal(value);
101
+ if (refusal !== undefined)
102
+ return refusal;
103
+ const bundleDigest = value?.["bundleDigest"];
104
+ const manifests = manifestPaths(value?.["manifests"]);
105
+ const declarations = declaredWorkflows(value?.["declarations"]);
106
+ const settings = reloadedSettings(value);
107
+ if (typeof bundleDigest !== "string" ||
108
+ manifests === undefined ||
109
+ declarations === undefined ||
110
+ settings === undefined)
111
+ return refused("reload-failed", "The reload command printed no workflow bundle.");
112
+ return {
113
+ kind: "prepared",
114
+ bundleDigest,
115
+ manifests,
116
+ declarations,
117
+ workflowRefusals: workflowRefusals(value?.["workflowRefusals"]),
118
+ ...settings,
119
+ };
120
+ }
121
+ async function prepared(command) {
122
+ const [executable = "", ...fixed] = command;
123
+ const output = await executed(executable, fixed, {
124
+ encoding: "utf8",
125
+ maxBuffer: 16 * 1024 * 1024,
126
+ }).then((result) => result.stdout, (error) => String(Reflect.get(Object(error), "stdout")));
127
+ return preparedBundle(output);
128
+ }
129
+ function restartFacts(declarations) {
130
+ const schedules = new Map(declarations
131
+ .filter((declaration) => declaration.schedule !== undefined)
132
+ .map((declaration) => [declaration.workflowId, declaration.schedule]));
133
+ return JSON.stringify({
134
+ queue: queueWorkflowId({ declarations }) ?? null,
135
+ schedules: [...schedules.keys()]
136
+ .sort()
137
+ .map((workflowId) => [workflowId, schedules.get(workflowId)]),
138
+ });
139
+ }
140
+ function refusalName(refusal) {
141
+ return `${refusal.scope} ${refusal.label}`;
142
+ }
143
+ function addedRefusals(current, next) {
144
+ const known = new Set(current.map(refusalName));
145
+ const added = next.filter((refusal) => !known.has(refusalName(refusal)));
146
+ if (added.length === 0)
147
+ return undefined;
148
+ const reasons = added.map((refusal) => `${refusalName(refusal)}: ${refusal.codes.join(", ")}`);
149
+ return refused("reload-failed", `The reload gives new workflow refusals: ${reasons.join("; ")}`);
150
+ }
151
+ async function reloaded(settings, bundle) {
152
+ const scheduled = scheduledDeclarations({ declarations: bundle.declarations, schedules: settings.schedules }, {
153
+ repository: settings.repository,
154
+ documentBytes: serviceLimits.documentBytes,
155
+ });
156
+ if (scheduled.kind === "refused")
157
+ return refused("reload-failed", `${scheduled.reason}: ${scheduled.detail}`);
158
+ if (restartFacts(scheduled.declarations) !==
159
+ restartFacts(settings.declarations ?? []))
160
+ return refused("reload-needs-restart", "The queue workflow or a schedule changed. Restart the service.");
161
+ let generation;
162
+ try {
163
+ generation = await settings.loadBundle(join(settings.directory, "workflow-bundles", bundle.bundleDigest));
164
+ }
165
+ catch (error) {
166
+ return refused("reload-failed", `The new bundle did not load: ${String(error)}`);
167
+ }
168
+ const { table, admitted } = await daemonRegistrations({
169
+ ...settings,
170
+ bundleDigest: bundle.bundleDigest,
171
+ manifests: bundle.manifests,
172
+ declarations: scheduled.declarations,
173
+ workflowRefusals: bundle.workflowRefusals,
174
+ });
175
+ if (admitted.kind === "rejected")
176
+ return refused("reload-failed", admitted.detail);
177
+ settings.generations.replace({
178
+ registrations: admitted.registrations,
179
+ table,
180
+ workflows: generation.workflows,
181
+ handler: generation.handler,
182
+ });
183
+ return {
184
+ kind: "reloaded",
185
+ bundleDigest: bundle.bundleDigest,
186
+ workflows: admitted.registrations,
187
+ workflowRefusals: bundle.workflowRefusals,
188
+ };
189
+ }
190
+ function reloadLine(outcome, digests) {
191
+ if (outcome.kind === "refused")
192
+ return `Workflow reload: refused ${outcome.code}: ${outcome.detail}\n`;
193
+ return `Workflow reload: ${outcome.kind} ${String(digests.previous)} -> ${String(digests.current)}\n`;
194
+ }
195
+ async function workflowPart(settings, prepared) {
196
+ const { state, bundle } = prepared;
197
+ const added = addedRefusals(state.workflowRefusals, bundle.workflowRefusals);
198
+ if (added !== undefined)
199
+ return added;
200
+ if (bundle.bundleDigest === state.bundleDigest)
201
+ return { kind: "unchanged", workflowRefusals: bundle.workflowRefusals };
202
+ return reloaded(settings, bundle);
203
+ }
204
+ async function reloadOutcome(settings, state) {
205
+ const kept = (outcome) => ({ outcome, state });
206
+ const bundle = await prepared(settings.reloadCommand);
207
+ if (bundle.kind === "refused")
208
+ return kept(bundle);
209
+ const profiles = profileRefusal(settings, bundle.turnSettings);
210
+ if (profiles !== undefined)
211
+ return kept(refused(profiles.code, profiles.detail));
212
+ const workflows = await workflowPart(settings, { state, bundle });
213
+ if (workflows.kind === "refused")
214
+ return kept(workflows);
215
+ const changes = settingChanges(state.settingDigests, bundle.settingDigests);
216
+ settings.turnSettings.replace(bundle.turnSettings);
217
+ return {
218
+ outcome: { ...workflows, ...changes },
219
+ state: {
220
+ bundleDigest: workflows.kind === "reloaded"
221
+ ? workflows.bundleDigest
222
+ : state.bundleDigest,
223
+ workflowRefusals: workflows.workflowRefusals,
224
+ settingDigests: keptDigests(state.settingDigests, {
225
+ digests: bundle.settingDigests,
226
+ reloadedFields: changes.reloadedFields,
227
+ }),
228
+ },
229
+ };
230
+ }
231
+ export function workflowReload(settings) {
232
+ let state = {
233
+ bundleDigest: settings.bundleDigest,
234
+ workflowRefusals: workflowRefusals(settings.workflowRefusals),
235
+ settingDigests: settings.settingDigests ?? {},
236
+ };
237
+ return async () => {
238
+ const previous = state.bundleDigest;
239
+ const step = await reloadOutcome(settings, state);
240
+ state = step.state;
241
+ process.stdout.write(reloadLine(step.outcome, { previous, current: state.bundleDigest }));
242
+ return step.outcome;
243
+ };
244
+ }
@@ -4,8 +4,9 @@ interface ReplayRun {
4
4
  readonly runId: string;
5
5
  readonly workflowId?: string;
6
6
  }
7
+ type ReplayState = Pick<AuthorityState, "details" | "runs">;
7
8
  interface ReplayPorts {
8
- readonly state: () => Promise<Pick<AuthorityState, "details">>;
9
+ readonly state: () => Promise<ReplayState>;
9
10
  readonly run: (receipt: string) => Promise<ReplayRun | undefined>;
10
11
  readonly available: (runId: string, workflowId?: string) => Promise<boolean>;
11
12
  readonly submit: (command: Readonly<Record<string, unknown>>) => Promise<{
@@ -18,8 +18,8 @@ async function located(ports, receipt) {
18
18
  return undefined;
19
19
  }
20
20
  async function observedReplay(ports, replay) {
21
- const { runId, receipt, available } = replay;
22
- const observation = (await ports.state()).details[runId]?.observation;
21
+ const { state, runId, receipt, available } = replay;
22
+ const observation = state.details[runId]?.observation;
23
23
  const unavailable = observation?.reason === "pinned-workflow-unavailable";
24
24
  if (available !== unavailable)
25
25
  return true;
@@ -49,7 +49,11 @@ export function pinnedWorkflowHandler(handler, ports) {
49
49
  if (run === undefined)
50
50
  return new Response("unknown-world-run", { status: 503 });
51
51
  const available = await ports.available(run.runId, run.workflowId);
52
- if (!(await observedReplay(ports, { runId: run.runId, receipt, available })))
52
+ const state = await ports.state();
53
+ if (state.runs[run.runId]?.status === "cancelled")
54
+ return Response.json({ ok: true });
55
+ const replay = { state, runId: run.runId, receipt, available };
56
+ if (!(await observedReplay(ports, replay)))
53
57
  return new Response("workflow-observation-unavailable", { status: 503 });
54
58
  if (available)
55
59
  return handler(request, run.runId);
@@ -1,10 +1,12 @@
1
1
  import type { WorkerPort } from "../service/worker-port.ts";
2
2
  import type { DeclaredWorkflow } from "../workflow-declaration.ts";
3
+ import type { SchedulePort } from "../schedule-progress.ts";
3
4
  interface ScheduleSettings {
4
5
  readonly directory: string;
5
6
  readonly runtimeDirectory: string;
6
7
  readonly declarations?: readonly DeclaredWorkflow[];
7
8
  readonly scheduleClock?: () => number;
9
+ readonly scheduleObservationClock?: () => number;
8
10
  readonly submit: WorkerPort["submit"];
9
11
  }
10
12
  export declare function scheduledDeclarations(settings: {
@@ -23,5 +25,6 @@ export declare function scheduledDeclarations(settings: {
23
25
  };
24
26
  export declare function workflowSchedules(settings: ScheduleSettings): Promise<{
25
27
  readonly stop: () => Promise<void>;
28
+ readonly request: SchedulePort;
26
29
  }>;
27
30
  export {};