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
@@ -9,8 +9,9 @@ export declare function knownMerge(operation: Operation, expected: ReviewedPull
9
9
  readonly updated: string;
10
10
  }): Promise<{
11
11
  readonly head: string;
12
+ readonly open: boolean;
12
13
  readonly merged: string | undefined;
13
14
  }>;
14
15
  export declare function mergePull(operation: Operation, pull: ReviewedPull & {
15
16
  readonly updated: string;
16
- }): Promise<string>;
17
+ }): Promise<string | Error>;
@@ -15,11 +15,12 @@ export async function knownMerge(operation, expected) {
15
15
  `${repositoryPath}/pulls/${String(expected.number)}`,
16
16
  ]));
17
17
  const head = commitOf(field(pull, "head"), "sha");
18
+ const open = field(pull, "state") === "open";
18
19
  if (field(pull, "merged") !== true)
19
- return { head, merged: undefined };
20
+ return { head, open, merged: undefined };
20
21
  if (head !== expected.commit && head !== expected.updated)
21
22
  throw new Error("merged-other-commit");
22
- return { head, merged: commitOf(pull, "merge_commit_sha") };
23
+ return { head, open, merged: commitOf(pull, "merge_commit_sha") };
23
24
  }
24
25
  async function mergedNow(operation, pull) {
25
26
  const reply = JSON.parse(await operation.calls.gh([
@@ -63,11 +64,17 @@ export function mergePull(operation, pull) {
63
64
  },
64
65
  statuses: pull.updated === pull.commit ? [] : [405, 409],
65
66
  }).catch(async (error) => {
66
- if (!(error instanceof Error) || error.message !== "github-network-failed")
67
+ if (!(error instanceof Error))
68
+ throw error;
69
+ const refused = error.message === "github-call-failed" &&
70
+ [405, 409].includes(Number(field(error, "status")));
71
+ if (error.message !== "github-network-failed" && !refused)
67
72
  throw error;
68
73
  const known = await knownMerge(operation, pull);
69
74
  if (known.merged !== undefined)
70
75
  return known.merged;
76
+ if (refused && known.open)
77
+ return error;
71
78
  throw error;
72
79
  });
73
80
  }
@@ -136,35 +136,64 @@ async function readyHead(operation, pull) {
136
136
  let recorded = pull.recorded;
137
137
  let remote = pull.remote;
138
138
  for (let attempt = 0; attempt < 3; attempt += 1) {
139
- const updated = await refreshed(operation, {
139
+ const updated = await pushedHead(operation, {
140
+ ...pull,
140
141
  tree,
141
- commit: pull.commit,
142
142
  recorded,
143
- check: pull.check,
143
+ remote,
144
144
  });
145
- if (updated !== pull.commit && recorded !== updated)
146
- await writeRecord(operation.folder, {
147
- name: "updated-head.json",
148
- value: { commit: pull.commit, updated },
149
- });
150
- if (updated !== pull.commit && remote !== updated)
151
- await operation.calls.git(tree.path, [
152
- "push",
153
- "--quiet",
154
- "origin",
155
- `${updated}:refs/heads/${tree.branch}`,
156
- ]);
157
145
  const ci = await waitForCi(operation, updated);
158
146
  if (ci !== undefined)
159
147
  return ci;
160
- const newest = await fetched(operation, await defaultBranch(operation));
161
- if ((await operation.calls.git(tree.path, ["merge-base", updated, newest])).trim() === newest)
162
- return updated;
163
148
  recorded = updated;
164
149
  remote = updated;
150
+ if (!(await containsBase(operation, updated)))
151
+ continue;
152
+ const merged = await mergePull(operation, { ...pull, updated });
153
+ if (typeof merged === "string")
154
+ return { updated, merged };
155
+ if (await containsBase(operation, updated))
156
+ throw merged;
157
+ await recordRefusal(operation, { error: merged, updated, attempt });
165
158
  }
166
159
  throw new Error("base-moved");
167
160
  }
161
+ async function recordRefusal(operation, refusal) {
162
+ const observation = await operation.observe?.({
163
+ condition: "working",
164
+ reason: "github-merge-refused",
165
+ evidence: `github-merge/HTTP-${String(field(refusal.error, "status"))}/head-${refusal.updated}/merge-main`,
166
+ attempt: refusal.attempt + 1,
167
+ limit: 3,
168
+ });
169
+ if (observation !== undefined &&
170
+ !["accepted", "duplicate"].includes(observation.kind))
171
+ throw new Error("github-call-failed");
172
+ }
173
+ async function pushedHead(operation, pull) {
174
+ const updated = await refreshed(operation, pull);
175
+ if (updated !== pull.commit && pull.recorded !== updated)
176
+ await writeRecord(operation.folder, {
177
+ name: "updated-head.json",
178
+ value: { commit: pull.commit, updated },
179
+ });
180
+ if (updated !== pull.commit && pull.remote !== updated)
181
+ await operation.calls.git(pull.tree.path, [
182
+ "push",
183
+ "--quiet",
184
+ "origin",
185
+ `${updated}:refs/heads/${pull.tree.branch}`,
186
+ ]);
187
+ return updated;
188
+ }
189
+ async function containsBase(operation, updated) {
190
+ const newest = await fetched(operation, await defaultBranch(operation));
191
+ return ((await operation.calls.git(existingTree(operation).path, [
192
+ "merge-base",
193
+ updated,
194
+ newest,
195
+ ])).trim() === newest);
196
+ }
168
197
  function checkOutput(cause) {
169
198
  return commandOutput(cause).slice(-6_000);
170
199
  }
@@ -209,12 +238,11 @@ async function completedMerge(operation, pull) {
209
238
  ...pull,
210
239
  updated: recorded ?? pull.commit,
211
240
  });
212
- const updated = known.merged === undefined
241
+ const result = known.merged === undefined
213
242
  ? await readyHead(operation, { ...pull, recorded, remote: known.head })
214
- : (recorded ?? pull.commit);
215
- if (typeof updated !== "string")
216
- return updated;
217
- const merged = known.merged ?? (await mergePull(operation, { ...pull, updated }));
243
+ : { updated: recorded ?? pull.commit, merged: known.merged };
244
+ if ("reason" in result)
245
+ return result;
218
246
  await removed(operation, place);
219
- return { number: pull.number, commit: pull.commit, updated, merged };
247
+ return { number: pull.number, commit: pull.commit, ...result };
220
248
  }
@@ -2,15 +2,20 @@ import { setTimeout as delay } from "node:timers/promises";
2
2
  import { appendFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { findingsOf, scoreOf, } from "./github-calls.js";
5
+ import { attachAsset } from "./github-attach.js";
5
6
  import { closeIssue, partialIssue } from "./github-ticket-status.js";
6
7
  import { merge } from "./github-merge.js";
7
- import { createIssue, discard } from "./github-issue-methods.js";
8
+ import { captureDraft, createIssue, discard, repositoryName, } from "./github-issue-methods.js";
8
9
  import { existingTree, defaultBranch, changeChecked, field, githubTiming, repositoryPath, text, } from "./github-operation.js";
9
10
  import { workTree } from "./work-tree.js";
10
11
  const triggerText = "@greptileai";
11
12
  const maximumReviewRequests = 3;
12
13
  export const methodReasons = new Set([
14
+ "attachment-not-available",
15
+ "attachment-too-large",
13
16
  "draft-not-available",
17
+ "draft-changed",
18
+ "draft-too-large",
14
19
  "invalid-draft",
15
20
  "post-uncertain",
16
21
  "private-texts-not-set",
@@ -77,7 +82,10 @@ function labels(operation, name) {
77
82
  });
78
83
  }
79
84
  async function label(operation) {
80
- const repository = `${text(operation, "owner")}/${text(operation, "repository")}`;
85
+ const repository = !Object.hasOwn(operation.payload, "owner") &&
86
+ !Object.hasOwn(operation.payload, "repository")
87
+ ? repositoryName(await operation.calls.gh(["repo", "view", "--json", "nameWithOwner"]))
88
+ : `${text(operation, "owner")}/${text(operation, "repository")}`;
81
89
  const number = integer(operation, "number");
82
90
  if (!/^[\w.-]+\/[\w.-]+$/.test(repository) || !Number.isSafeInteger(number))
83
91
  throw new Error("invalid-payload");
@@ -262,8 +270,10 @@ export const methods = new Map([
262
270
  ["partial-issue", partialIssue],
263
271
  ["label", label],
264
272
  ["create-issue", createIssue],
273
+ ["capture-draft", captureDraft],
265
274
  ["discard", discard],
266
275
  ["open-pr", openPull],
276
+ ["attach-asset", attachAsset],
267
277
  ["wait-review", waitReview],
268
278
  [
269
279
  "merge",
@@ -1,4 +1,5 @@
1
1
  import type { CallSettings, Calls } from "./github-calls.ts";
2
+ import type { ObservationReport } from "../service/worker-port.ts";
2
3
  export interface GithubTiming {
3
4
  readonly pollMilliseconds: number;
4
5
  readonly triggerMilliseconds: number;
@@ -20,6 +21,9 @@ export interface Operation {
20
21
  readonly payload: Readonly<Record<string, unknown>>;
21
22
  readonly signal: AbortSignal;
22
23
  readonly folder: string;
24
+ readonly observe?: (report: Pick<ObservationReport, "condition" | "reason" | "evidence" | "attempt" | "limit">) => Promise<{
25
+ readonly kind: string;
26
+ } | undefined>;
23
27
  }
24
28
  export interface Place {
25
29
  readonly path: string;
@@ -1,6 +1,8 @@
1
1
  import { homedir } from "node:os";
2
2
  import { existsSync } from "node:fs";
3
3
  import { join } from "node:path";
4
+ import { rm } from "node:fs/promises";
5
+ import { attachmentFolder } from "./attachments.js";
4
6
  import { treePlace } from "./work-tree.js";
5
7
  export const githubTiming = {
6
8
  pollMilliseconds: 30_000,
@@ -32,6 +34,10 @@ export async function removeWorktree(operation, place) {
32
34
  await repository(["worktree", "remove", "--force", place.path]);
33
35
  if ((await repository(["branch", "--list", place.branch])).trim() !== "")
34
36
  await repository(["branch", "-D", place.branch]);
37
+ await rm(attachmentFolder({
38
+ worktrees: operation.settings.worktrees,
39
+ target: operation.target,
40
+ }), { recursive: true, force: true });
35
41
  }
36
42
  export async function defaultBranch(operation) {
37
43
  const reference = await operation.calls.git(operation.settings.repository, [
@@ -1,4 +1,5 @@
1
1
  import type { Delivery } from "../broker/actor/delivery-intents.ts";
2
+ import type { ObservationReport } from "../service/worker-port.ts";
2
3
  import { type MethodSettings } from "./github-methods.ts";
3
4
  import { type WorkerReport } from "./operation-journal.ts";
4
5
  export type { GithubTiming } from "./github-methods.ts";
@@ -6,6 +7,9 @@ export interface GithubWorkerSettings extends MethodSettings {
6
7
  readonly journal: string;
7
8
  readonly document: (digest: string) => Promise<string | undefined>;
8
9
  readonly report: (report: WorkerReport) => Promise<unknown>;
10
+ readonly observe?: (report: ObservationReport) => Promise<{
11
+ readonly kind: string;
12
+ }>;
9
13
  readonly operationStatus: (operationId: string) => Promise<string | undefined>;
10
14
  readonly runStatus: (runId: string) => Promise<string | undefined>;
11
15
  }
@@ -47,6 +47,12 @@ async function outcome(parts, run) {
47
47
  target: intent.target,
48
48
  payload,
49
49
  signal,
50
+ observe: async (observation) => settings.observe?.({
51
+ ...observation,
52
+ runId: intent.runId,
53
+ operationId: intent.operationId,
54
+ commandId: `github:${run.key}:merge-refused:${String(observation.attempt)}`,
55
+ }),
50
56
  });
51
57
  return {
52
58
  outcome: "completed",
@@ -4,7 +4,7 @@ interface QueueSettings {
4
4
  readonly intervalMilliseconds: number;
5
5
  readonly lanes?: number;
6
6
  readonly resetQueue?: boolean;
7
- readonly workflowId?: string;
7
+ readonly workflowId: string;
8
8
  }
9
9
  export declare function issueQueue(settings: QueueSettings): {
10
10
  readonly stop: () => Promise<void>;
@@ -1,4 +1,4 @@
1
- import { activeQueueRuns } from "./queue-status.js";
1
+ import { queueStatus, spendNotice } from "./queue-status.js";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { readFile, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
@@ -155,7 +155,7 @@ async function submit(settings, pending) {
155
155
  const reply = await send(settings.runtimeDirectory, {
156
156
  operation: "run",
157
157
  parameters: {
158
- workflowId: settings.workflowId ?? "develop-issue",
158
+ workflowId: settings.workflowId,
159
159
  source: "ticket",
160
160
  submission: { ticket: "next" },
161
161
  commandId,
@@ -178,6 +178,7 @@ async function submit(settings, pending) {
178
178
  "workflow-active",
179
179
  "ticket-active",
180
180
  "ticket-dependency-open",
181
+ "queue-spend-limit",
181
182
  ].includes(reply.error.code))
182
183
  throw new Error(reply.error.code);
183
184
  pending.commands.delete(commandId);
@@ -242,7 +243,13 @@ async function cycle(settings, signal) {
242
243
  pending.failures.length = 0;
243
244
  await pending.save();
244
245
  }
245
- const holding = updateHold(settings.directory, pending);
246
+ const update = updateHold(settings.directory, pending);
247
+ const notice = spendNotice();
248
+ const holding = async (activeRuns = 0) => {
249
+ const updating = await update(activeRuns);
250
+ const spend = notice(await queueStatus(settings));
251
+ return updating || spend;
252
+ };
246
253
  await rm(join(settings.directory, "queue-submission"), { force: true });
247
254
  await recover(settings, pending);
248
255
  const stopped = () => signal.aborted;
@@ -252,15 +259,13 @@ async function cycle(settings, signal) {
252
259
  return;
253
260
  const pendingRuns = await completed(settings, pending);
254
261
  const lanes = settings.lanes ?? 1;
255
- if (pendingRuns >= lanes) {
256
- await holding(pendingRuns);
257
- continue;
258
- }
259
- const activeRuns = await activeQueueRuns(settings);
260
- const held = await holding(activeRuns);
261
- if (activeRuns >= lanes || activeRuns < pendingRuns)
262
+ const status = await queueStatus(settings);
263
+ const spend = notice(status);
264
+ const updating = await update(status.busy);
265
+ if (Math.max(pendingRuns, status.busy) >= lanes ||
266
+ status.busy < pendingRuns)
262
267
  continue;
263
- if (held)
268
+ if (updating || spend)
264
269
  continue;
265
270
  if (stopped())
266
271
  return;
@@ -0,0 +1,6 @@
1
+ import { type NotifyEvent } from "./notify-message.ts";
2
+ export type OutcomeCache = Map<string, {
3
+ readonly latestSequence: number;
4
+ readonly event: NotifyEvent | undefined;
5
+ }>;
6
+ export declare function notificationEvents(runtimeDirectory: string, cache: OutcomeCache): Promise<readonly NotifyEvent[]>;
@@ -0,0 +1,84 @@
1
+ import { send } from "../cli/client.js";
2
+ import { record } from "../protocol.js";
3
+ import { decisionNotification, outcomeNotification, scheduleStopNotifications, } from "./notify-message.js";
4
+ async function request(runtimeDirectory, request) {
5
+ const reply = await send(runtimeDirectory, request);
6
+ if (reply.kind === "error")
7
+ throw new Error(reply.error.code);
8
+ return reply.result;
9
+ }
10
+ function rows(value) {
11
+ if (!Array.isArray(value))
12
+ throw new Error("invalid-notify-list");
13
+ return value.map((item) => {
14
+ const row = record(item);
15
+ if (row === undefined)
16
+ throw new Error("invalid-notify-row");
17
+ return row;
18
+ });
19
+ }
20
+ async function scheduleNotifications(runtimeDirectory) {
21
+ const reply = await send(runtimeDirectory, {
22
+ operation: "schedule",
23
+ parameters: { action: "list" },
24
+ });
25
+ if (reply.kind !== "error")
26
+ return rows(reply.result["stops"]).flatMap(scheduleStopNotifications);
27
+ if (reply.error.code === "schedules-unavailable")
28
+ return [];
29
+ throw new Error(reply.error.code);
30
+ }
31
+ async function observedOutcome(summary, source) {
32
+ const { runtimeDirectory, cache } = source;
33
+ const latestSequence = summary["latestSequence"];
34
+ if (typeof latestSequence !== "number")
35
+ throw new Error("invalid-notify-sequence");
36
+ const runId = String(summary["runId"]);
37
+ const previous = cache.get(runId);
38
+ if (previous !== undefined && previous.latestSequence === latestSequence)
39
+ return previous.event;
40
+ const status = await request(runtimeDirectory, {
41
+ operation: "status",
42
+ parameters: { runId },
43
+ });
44
+ const run = record(status["run"]);
45
+ if (run === undefined)
46
+ throw new Error("invalid-notify-status");
47
+ const event = outcomeNotification(run);
48
+ cache.set(runId, { latestSequence, event });
49
+ return event;
50
+ }
51
+ export async function notificationEvents(runtimeDirectory, cache) {
52
+ const found = [];
53
+ const runs = new Map();
54
+ let after = "";
55
+ do {
56
+ const page = await request(runtimeDirectory, {
57
+ operation: "status",
58
+ parameters: { after, limit: 500 },
59
+ });
60
+ for (const summary of rows(page["runs"])) {
61
+ runs.set(String(summary["runId"]), summary);
62
+ const outcome = await observedOutcome(summary, {
63
+ runtimeDirectory,
64
+ cache,
65
+ });
66
+ if (outcome !== undefined)
67
+ found.push(outcome);
68
+ }
69
+ const next = page["next"];
70
+ if (next !== null && (typeof next !== "string" || next <= after))
71
+ throw new Error("invalid-notify-page");
72
+ after = next;
73
+ } while (after !== null);
74
+ const questions = await request(runtimeDirectory, {
75
+ operation: "questions",
76
+ parameters: {},
77
+ });
78
+ for (const decision of rows(questions["decisions"])) {
79
+ const run = runs.get(String(decision["runId"]));
80
+ if (run !== undefined)
81
+ found.push(decisionNotification(run, decision));
82
+ }
83
+ return [...found, ...(await scheduleNotifications(runtimeDirectory))];
84
+ }
@@ -46,7 +46,7 @@ function notification(value) {
46
46
  const message = record(value);
47
47
  if (message === undefined)
48
48
  return false;
49
- return (["decision", "blocked", "failed"].includes(String(message["event"])) &&
49
+ return (["decision", "blocked", "failed", "schedule-stopped"].includes(String(message["event"])) &&
50
50
  ["event", "runId", "workflowId", "subject", "body"].every((field) => typeof message[field] === "string"));
51
51
  }
52
52
  function deliveryState(value) {
@@ -1,10 +1,11 @@
1
1
  import { type Fields } from "../protocol.ts";
2
2
  export interface Notification {
3
- readonly event: "decision" | "blocked" | "failed";
3
+ readonly event: "decision" | "blocked" | "failed" | "schedule-stopped";
4
4
  readonly runId: string;
5
5
  readonly workflowId: string;
6
6
  readonly subject: string;
7
7
  readonly body: string;
8
+ readonly failedRunIds?: readonly string[];
8
9
  }
9
10
  export interface NotifyEvent {
10
11
  readonly key: string;
@@ -12,3 +13,5 @@ export interface NotifyEvent {
12
13
  }
13
14
  export declare function decisionNotification(run: Fields, decision: Fields): NotifyEvent;
14
15
  export declare function outcomeNotification(run: Fields): NotifyEvent | undefined;
16
+ export declare function stoppedScheduleNotification(schedule: Fields): NotifyEvent | undefined;
17
+ export declare function scheduleStopNotifications(schedule: Fields): readonly NotifyEvent[];
@@ -47,3 +47,39 @@ export function outcomeNotification(run) {
47
47
  }),
48
48
  };
49
49
  }
50
+ export function stoppedScheduleNotification(schedule) {
51
+ if (schedule["state"] !== "stopped")
52
+ return undefined;
53
+ const failedRunIds = schedule["failedRunIds"];
54
+ if (!Array.isArray(failedRunIds) || failedRunIds.length !== 3)
55
+ throw new Error("invalid-stopped-schedule");
56
+ const ids = failedRunIds.map((runId) => String(runId));
57
+ const workflowId = String(schedule["workflowId"]);
58
+ return {
59
+ key: `schedule-stopped:${workflowId}:${String(schedule["stoppedSlot"])}`,
60
+ message: {
61
+ ...message({ workflowId, runId: ids[2] }, {
62
+ event: "schedule-stopped",
63
+ body: body(`Schedule stopped after three failed runs:\n${ids.join("\n")}`, [`cloving schedule resume ${workflowId}`]),
64
+ }),
65
+ failedRunIds: ids,
66
+ },
67
+ };
68
+ }
69
+ export function scheduleStopNotifications(schedule) {
70
+ const stops = schedule["stops"];
71
+ if (stops === undefined) {
72
+ const event = stoppedScheduleNotification(schedule);
73
+ return event === undefined ? [] : [event];
74
+ }
75
+ if (!Array.isArray(stops))
76
+ throw new Error("invalid-stopped-schedule");
77
+ return stops.flatMap((stop) => {
78
+ const event = stoppedScheduleNotification({
79
+ ...record(stop),
80
+ workflowId: schedule["workflowId"],
81
+ state: "stopped",
82
+ });
83
+ return event === undefined ? [] : [event];
84
+ });
85
+ }
@@ -1,4 +1,4 @@
1
- import { type Notification } from "./notify-message.ts";
1
+ import type { Notification } from "./notify-message.ts";
2
2
  interface NotifySettings {
3
3
  readonly directory: string;
4
4
  readonly runtimeDirectory: string;
@@ -1,27 +1,9 @@
1
1
  import { recordedNotifications, saveNotifications, } from "./notify-journal.js";
2
2
  import { spawn } from "node:child_process";
3
3
  import { join } from "node:path";
4
- import { send } from "../cli/client.js";
5
4
  import { deliveryBackoffMilliseconds } from "../delivery-backoff.js";
6
- import { record } from "../protocol.js";
7
- import { decisionNotification, outcomeNotification, } from "./notify-message.js";
5
+ import { notificationEvents } from "./notify-events.js";
8
6
  const retentionMilliseconds = 7 * 24 * 60 * 60_000;
9
- async function request(runtimeDirectory, request) {
10
- const reply = await send(runtimeDirectory, request);
11
- if (reply.kind === "error")
12
- throw new Error(reply.error.code);
13
- return reply.result;
14
- }
15
- function rows(value) {
16
- if (!Array.isArray(value))
17
- throw new Error("invalid-notify-list");
18
- return value.map((item) => {
19
- const row = record(item);
20
- if (row === undefined)
21
- throw new Error("invalid-notify-row");
22
- return row;
23
- });
24
- }
25
7
  async function flushNotifications(journal) {
26
8
  if (journal.unsaved.size === 0)
27
9
  return;
@@ -36,60 +18,6 @@ async function finishDelivery(journal, entry) {
36
18
  journal.unsaved.set(entry.key, entry);
37
19
  await flushNotifications(journal);
38
20
  }
39
- async function observedOutcome(summary, source) {
40
- const { runtimeDirectory, cache } = source;
41
- const latestSequence = summary["latestSequence"];
42
- if (typeof latestSequence !== "number")
43
- throw new Error("invalid-notify-sequence");
44
- const runId = String(summary["runId"]);
45
- const previous = cache.get(runId);
46
- if (previous !== undefined && previous.latestSequence === latestSequence)
47
- return previous.event;
48
- const status = await request(runtimeDirectory, {
49
- operation: "status",
50
- parameters: { runId },
51
- });
52
- const run = record(status["run"]);
53
- if (run === undefined)
54
- throw new Error("invalid-notify-status");
55
- const event = outcomeNotification(run);
56
- cache.set(runId, { latestSequence, event });
57
- return event;
58
- }
59
- async function events(runtimeDirectory, cache) {
60
- const found = [];
61
- const runs = new Map();
62
- let after = "";
63
- do {
64
- const page = await request(runtimeDirectory, {
65
- operation: "status",
66
- parameters: { after, limit: 500 },
67
- });
68
- for (const summary of rows(page["runs"])) {
69
- runs.set(String(summary["runId"]), summary);
70
- const outcome = await observedOutcome(summary, {
71
- runtimeDirectory,
72
- cache,
73
- });
74
- if (outcome !== undefined)
75
- found.push(outcome);
76
- }
77
- const next = page["next"];
78
- if (next !== null && (typeof next !== "string" || next <= after))
79
- throw new Error("invalid-notify-page");
80
- after = next;
81
- } while (after !== null);
82
- const questions = await request(runtimeDirectory, {
83
- operation: "questions",
84
- parameters: {},
85
- });
86
- for (const decision of rows(questions["decisions"])) {
87
- const run = runs.get(String(decision["runId"]));
88
- if (run !== undefined)
89
- found.push(decisionNotification(run, decision));
90
- }
91
- return found;
92
- }
93
21
  export function notifyCommand(command, notification) {
94
22
  return new Promise((resolve, reject) => {
95
23
  const [executable = "", ...argumentsList] = command;
@@ -210,7 +138,7 @@ async function check(settings, journal) {
210
138
  journal.retiredKeys.add(key);
211
139
  }
212
140
  }
213
- for (const event of await events(settings.runtimeDirectory, journal.cache)) {
141
+ for (const event of await notificationEvents(settings.runtimeDirectory, journal.cache)) {
214
142
  if (journal.entries.has(event.key) || journal.retiredKeys.has(event.key))
215
143
  continue;
216
144
  const entry = {
@@ -237,12 +165,12 @@ export async function notifyRuns(settings) {
237
165
  unsaved: new Map(),
238
166
  };
239
167
  if (recorded === undefined) {
240
- for (const event of await events(settings.runtimeDirectory, cache))
168
+ for (const event of await notificationEvents(settings.runtimeDirectory, cache))
241
169
  journal.entries.set(event.key, {
242
170
  ...event,
243
- state: "sent",
171
+ state: event.message.event === "schedule-stopped" ? "pending" : "sent",
244
172
  attempts: 0,
245
- lastAttemptAt: Date.now(),
173
+ lastAttemptAt: event.message.event === "schedule-stopped" ? null : Date.now(),
246
174
  lastFailure: null,
247
175
  });
248
176
  }
@@ -11,6 +11,7 @@ export interface WorkerReport {
11
11
  readonly reason?: string;
12
12
  }
13
13
  export interface Recorded {
14
+ readonly stoppedBy?: "daemon-shutdown";
14
15
  readonly outcome: WorkerReport["outcome"];
15
16
  readonly result?: string;
16
17
  readonly reason?: string;
@@ -1,4 +1,10 @@
1
- export declare function activeQueueRuns(settings: {
1
+ export declare function queueStatus(settings: {
2
2
  readonly runtimeDirectory: string;
3
- readonly workflowId?: string;
4
- }): Promise<number>;
3
+ readonly workflowId: string;
4
+ }): Promise<{
5
+ readonly busy: number;
6
+ readonly holding: boolean;
7
+ }>;
8
+ export declare function spendNotice(): (status: {
9
+ readonly holding: boolean;
10
+ }) => boolean;