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
@@ -1,23 +1,22 @@
1
- import { eligibleIntents, } from "../../authority/reducer.js";
2
- import { loadOperationSnapshot, loadProjections, } from "../../storage/decision-snapshots.js";
3
1
  import { loadEvents } from "../../storage/domain-rows.js";
4
2
  import { pinnedResumption } from "../authority-admission.js";
5
- import { currentState, intentKind, storedDefinitions, storedEvents, } from "../authority-restore.js";
3
+ import { storedDefinitions, storedEvents, } from "../authority-restore.js";
6
4
  import { checkedRequest } from "./authority-actor.js";
7
5
  import { subscriptions, } from "./authority-changes.js";
8
6
  import { authorityQueries, guardedRead, } from "./authority-queries.js";
9
7
  import { effectQueries } from "./effect-queries.js";
10
8
  import { backupInto } from "../../storage/domain-schema.js";
11
9
  import { observeSettings, } from "./authority-connection.js";
10
+ import { authorityHealth } from "./authority-health.js";
12
11
  import { failed, serializable, storeReceipt, invalidCommand, oversized, tooLarge, unserializable, } from "./authority-receipts.js";
12
+ export { operationRecords } from "./projection-memory.js";
13
13
  export function authoritySession(parts) {
14
14
  const session = {
15
15
  parts,
16
16
  stopping: new AbortController(),
17
17
  delivering: false,
18
18
  failure: null,
19
- condition: null,
20
- describing: null,
19
+ health: authorityHealth(parts),
21
20
  closed: false,
22
21
  running: Promise.resolve(),
23
22
  invocations: new Set(),
@@ -33,18 +32,18 @@ export function authoritySession(parts) {
33
32
  });
34
33
  return {
35
34
  execute: (command, context) => executeCommand(session, { command, context }),
36
- state: async () => currentState(await projected(session)),
35
+ state: async () => (await projected(session)).state(),
37
36
  events: async () => {
38
37
  await refreshed(session);
39
38
  available(session);
40
39
  return storedEvents(await parts.reader.connection(loadEvents));
41
40
  },
42
- eligibleIntents: async () => eligible(await projected(session)),
43
- operations: async () => operationRecords(await read(loadOperationSnapshot)),
41
+ eligibleIntents: async () => (await projected(session)).eligible(),
42
+ operations: async () => (await projected(session)).operations(),
44
43
  resumePinned: async (runId, manifest) => {
45
- const snapshot = await projected(session);
46
- return pinnedResumption(currentState(snapshot), {
47
- definitions: storedDefinitions(snapshot),
44
+ const current = await projected(session);
45
+ return pinnedResumption(current.state(), {
46
+ definitions: storedDefinitions(current.snapshot),
48
47
  runId,
49
48
  available: manifest,
50
49
  });
@@ -56,7 +55,11 @@ export function authoritySession(parts) {
56
55
  },
57
56
  epoch: parts.epoch,
58
57
  recoveryLimit: parts.recoveryLimit,
59
- queries: authorityQueries(read),
58
+ queries: {
59
+ ...authorityQueries(read),
60
+ sequences: async () => (await projected(session)).sequences(),
61
+ workflowIds: async (runIds) => (await projected(session)).workflowIds(runIds),
62
+ },
60
63
  effects: effectQueries(read, { stopLimit: parts.stopLimit }),
61
64
  deliver: (signal) => deliver(session, signal),
62
65
  changes: { subscribe: session.changes.add },
@@ -82,29 +85,16 @@ async function stopped(session) {
82
85
  }
83
86
  }
84
87
  async function refreshed(session) {
85
- if (session.parts.unhealthy() === undefined)
88
+ if (session.failure !== null || session.closed)
86
89
  return;
87
- await failClosed(session, "authority failure");
90
+ await session.health.refresh();
88
91
  }
89
- async function failClosed(session, failure) {
92
+ function failClosed(session, failure) {
90
93
  session.failure ??= failure;
91
- await conditionRead(session);
92
- close(session).catch(() => undefined);
93
- }
94
- async function conditionRead(session) {
95
- if (session.condition !== null && session.describing === null)
96
- return;
97
- session.describing ??= described(session).finally(() => {
98
- session.describing = null;
99
- });
100
- await session.describing;
94
+ close(session).catch(ignored);
101
95
  }
102
- async function described(session) {
103
- const detected = session.parts.unhealthy();
104
- if (detected === undefined)
105
- return;
106
- session.condition = detected;
107
- session.condition = (await session.parts.condition()) ?? detected;
96
+ function ignored() {
97
+ return undefined;
108
98
  }
109
99
  async function backup(session, target) {
110
100
  await refreshed(session);
@@ -116,36 +106,43 @@ async function backup(session, target) {
116
106
  throw new Error(`backup-failed: ${String(Reflect.get(Object(error), "message"))}`, { cause: error });
117
107
  }
118
108
  }
119
- function available(session) {
120
- const failure = session.condition ?? session.failure;
121
- if (failure !== null)
122
- throw new Error(`authority-unavailable: ${failure}`);
109
+ function opened(session) {
110
+ if (session.failure !== null)
111
+ throw new Error(`authority-unavailable: ${session.failure}`);
123
112
  if (session.closed)
124
113
  throw new Error("authority-unavailable: closed");
125
114
  }
115
+ function available(session) {
116
+ opened(session);
117
+ const condition = session.health.condition();
118
+ if (condition !== null)
119
+ throw new Error(`authority-unavailable: ${condition}`);
120
+ }
126
121
  function unavailableReceipt(session) {
127
- const failure = session.condition ?? session.failure;
128
- if (failure !== null)
122
+ if (session.failure !== null)
129
123
  return {
130
124
  kind: "failed",
131
125
  reason: "storage-unavailable",
132
- detail: `closed after ${failure}`,
126
+ detail: `closed after ${session.failure}`,
133
127
  };
134
128
  if (session.closed)
135
129
  return { kind: "failed", reason: "storage-unavailable", detail: "closed" };
136
- return undefined;
130
+ const condition = session.health.condition();
131
+ return condition === null
132
+ ? undefined
133
+ : { kind: "failed", reason: "authority-unavailable", detail: condition };
137
134
  }
138
135
  async function projected(session) {
139
136
  await refreshed(session);
140
137
  available(session);
141
- return session.parts.reader.connection(loadProjections);
138
+ return session.parts.memory.read(session.parts.database);
142
139
  }
143
140
  async function deliver(session, signal) {
144
141
  if (!session.parts.deliveryConfigured)
145
142
  throw new Error("delivery-unconfigured");
146
143
  if (session.delivering)
147
144
  throw new Error("delivery-already-running");
148
- available(session);
145
+ opened(session);
149
146
  session.delivering = true;
150
147
  try {
151
148
  await delivered(session, signal);
@@ -154,21 +151,19 @@ async function deliver(session, signal) {
154
151
  session.delivering = false;
155
152
  }
156
153
  await refreshed(session);
157
- const failure = session.condition ?? session.failure;
154
+ const failure = session.failure ?? session.health.condition();
158
155
  if (failure !== null)
159
156
  throw new Error(`authority-unavailable: ${failure}`);
160
157
  }
161
158
  async function delivered(session, signal) {
162
159
  if (!(await session.parts.handlersSettled()))
163
160
  throw new Error("delivery-handler-in-flight");
164
- available(session);
165
- const watch = new AbortController();
161
+ opened(session);
166
162
  const timer = setInterval(() => {
167
- if (session.parts.unhealthy() !== undefined)
168
- watch.abort();
163
+ refreshed(session).catch(ignored);
169
164
  }, session.parts.watchMilliseconds);
170
165
  try {
171
- session.running = session.parts.run(AbortSignal.any([signal, session.stopping.signal, watch.signal]));
166
+ session.running = session.parts.run(AbortSignal.any([signal, session.stopping.signal]));
172
167
  await session.running;
173
168
  }
174
169
  finally {
@@ -177,8 +172,7 @@ async function delivered(session, signal) {
177
172
  }
178
173
  async function executeCommand(session, input) {
179
174
  const { command, context } = input;
180
- await refreshed(session);
181
- const unavailable = unavailableReceipt(session);
175
+ const unavailable = await refusal(session);
182
176
  if (unavailable !== undefined)
183
177
  return unavailable;
184
178
  const given = serializable({
@@ -196,15 +190,32 @@ async function executeCommand(session, input) {
196
190
  if (oversized(request))
197
191
  return tooLarge;
198
192
  try {
199
- return await healthyReceipt(session, await invoked(session, request));
193
+ return storeReceipt(await invoked(session, request));
200
194
  }
201
195
  catch (error) {
202
- const receipt = failed(error);
203
- await failClosed(session, receipt.reason === "storage-failure"
204
- ? "storage failure"
205
- : "authority failure");
206
- return receipt;
196
+ return failedReceipt(session, error);
197
+ }
198
+ }
199
+ async function refusal(session) {
200
+ try {
201
+ await refreshed(session);
207
202
  }
203
+ catch (error) {
204
+ return failed(error);
205
+ }
206
+ return unavailableReceipt(session);
207
+ }
208
+ function failedReceipt(session, error) {
209
+ const receipt = failed(error);
210
+ if (timedOut(error))
211
+ return receipt;
212
+ failClosed(session, receipt.reason === "storage-failure"
213
+ ? "storage failure"
214
+ : "authority failure");
215
+ return receipt;
216
+ }
217
+ function timedOut(error) {
218
+ return error instanceof Error && error.name === "SyncTimeout";
208
219
  }
209
220
  async function invoked(session, request) {
210
221
  const invocation = session.parts.execute(request);
@@ -216,36 +227,3 @@ async function invoked(session, request) {
216
227
  session.invocations.delete(invocation);
217
228
  }
218
229
  }
219
- async function healthyReceipt(session, value) {
220
- const receipt = storeReceipt(value);
221
- await refreshed(session);
222
- return receipt;
223
- }
224
- export function operationRecords(snapshot) {
225
- const deliveries = Map.groupBy(snapshot.deliveries, (row) => row.operationId);
226
- return snapshot.outbox.map((row) => ({
227
- operationId: row.operationId,
228
- kind: intentKind(row.kind),
229
- runId: row.runId,
230
- createdSequence: row.createdSequence,
231
- releasedSequence: row.releasedSequence,
232
- deliveries: (deliveries.get(row.operationId) ?? []).map(({ effectId, outcome, receipt, purpose, epoch }) => ({
233
- effectId,
234
- outcome,
235
- receipt,
236
- purpose,
237
- epoch,
238
- })),
239
- }));
240
- }
241
- function eligible(snapshot) {
242
- return eligibleIntents({
243
- ...currentState(snapshot),
244
- effects: {
245
- operations: Object.fromEntries(snapshot.pending.map((operationId) => [
246
- operationId,
247
- { status: "dispatch-pending" },
248
- ])),
249
- },
250
- });
251
- }
@@ -1,4 +1,4 @@
1
- import type { SolidObjectsConfiguration } from "solid-objects";
1
+ import type { Logger, SolidObjectsConfiguration } from "solid-objects";
2
2
  export interface AuthorityTiming {
3
3
  readonly leaseMilliseconds: number;
4
4
  readonly renewalMilliseconds: number;
@@ -30,4 +30,5 @@ export declare function effectConfiguration(options: {
30
30
  readonly stop?: unknown;
31
31
  };
32
32
  }): PlanSettings;
33
+ export declare function authorityLogger(log: ((line: string) => void) | undefined): Logger;
33
34
  export declare function librarySettings(timing: AuthorityTiming, log: ((line: string) => void) | undefined): Partial<SolidObjectsConfiguration>;
@@ -47,14 +47,17 @@ export function effectConfiguration(options) {
47
47
  function standardError(line) {
48
48
  process.stderr.write(line);
49
49
  }
50
+ export function authorityLogger(log) {
51
+ return lineLogger(log ?? standardError);
52
+ }
50
53
  export function librarySettings(timing, log) {
51
54
  return {
52
55
  tableNamePrefix: "solid_",
53
56
  maxAttempts: 1,
54
57
  maxActivationDurationMilliseconds: 50,
55
- maxPayloadBytes: 900_000 + commandLimits.stdoutBytes * 6,
56
- maxResultBytes: 900_000 + commandLimits.stdoutBytes * 6,
57
- logger: lineLogger(log ?? standardError),
58
+ maxPayloadBytes: 900_000 + commandLimits.stdoutBytes * 12,
59
+ maxResultBytes: 900_000 + commandLimits.stdoutBytes * 12,
60
+ logger: authorityLogger(log),
58
61
  leaseDurationMilliseconds: timing.leaseMilliseconds,
59
62
  leaseRenewalIntervalMilliseconds: timing.renewalMilliseconds,
60
63
  processHeartbeatIntervalMilliseconds: timing.heartbeatMilliseconds,
@@ -1,7 +1,8 @@
1
- import { loadDecided } from "../../storage/decision-snapshots.ts";
1
+ import { upgradeCommandWaits, upgradeCommandWaitChecks } from "../command-wait-restore.ts";
2
+ import { loadDecided, loadEffected, loadWaiting, loadCurrent } from "../../storage/decision-snapshots.ts";
2
3
  import { loadSnapshot } from "../../storage/domain-rows.ts";
3
4
  import { upgradeDecisions } from "../decision-upgrade.ts";
4
- import { upgradeEffects } from "../effect-upgrade.ts";
5
+ import { upgradeEffects, upgradeEventIndexes, upgradeRunIndexes, upgradeSpendingIndexes } from "../effect-upgrade.ts";
5
6
  declare const upgrades: readonly [{
6
7
  readonly from: "adopted";
7
8
  readonly load: typeof loadSnapshot;
@@ -10,6 +11,26 @@ declare const upgrades: readonly [{
10
11
  readonly from: "decided";
11
12
  readonly load: typeof loadDecided;
12
13
  readonly apply: typeof upgradeEffects;
14
+ }, {
15
+ readonly from: "effected";
16
+ readonly load: typeof loadEffected;
17
+ readonly apply: typeof upgradeCommandWaits;
18
+ }, {
19
+ readonly from: "waiting";
20
+ readonly load: typeof loadWaiting;
21
+ readonly apply: typeof upgradeCommandWaitChecks;
22
+ }, {
23
+ readonly from: "checked";
24
+ readonly load: typeof loadCurrent;
25
+ readonly apply: typeof upgradeSpendingIndexes;
26
+ }, {
27
+ readonly from: "indexed";
28
+ readonly load: typeof loadCurrent;
29
+ readonly apply: typeof upgradeEventIndexes;
30
+ }, {
31
+ readonly from: "event-indexed";
32
+ readonly load: typeof loadCurrent;
33
+ readonly apply: typeof upgradeRunIndexes;
13
34
  }];
14
35
  export type UpgradeStep = (typeof upgrades)[number];
15
36
  export declare function upgradeSteps(kind: string): readonly UpgradeStep[];
@@ -1,10 +1,16 @@
1
- import { loadDecided } from "../../storage/decision-snapshots.js";
1
+ import { upgradeCommandWaits, upgradeCommandWaitChecks, } from "../command-wait-restore.js";
2
+ import { loadDecided, loadEffected, loadWaiting, loadCurrent, } from "../../storage/decision-snapshots.js";
2
3
  import { loadSnapshot } from "../../storage/domain-rows.js";
3
4
  import { upgradeDecisions } from "../decision-upgrade.js";
4
- import { upgradeEffects } from "../effect-upgrade.js";
5
+ import { upgradeEffects, upgradeEventIndexes, upgradeRunIndexes, upgradeSpendingIndexes, } from "../effect-upgrade.js";
5
6
  const upgrades = [
6
7
  { from: "adopted", load: loadSnapshot, apply: upgradeDecisions },
7
8
  { from: "decided", load: loadDecided, apply: upgradeEffects },
9
+ { from: "effected", load: loadEffected, apply: upgradeCommandWaits },
10
+ { from: "waiting", load: loadWaiting, apply: upgradeCommandWaitChecks },
11
+ { from: "checked", load: loadCurrent, apply: upgradeSpendingIndexes },
12
+ { from: "indexed", load: loadCurrent, apply: upgradeEventIndexes },
13
+ { from: "event-indexed", load: loadCurrent, apply: upgradeRunIndexes },
8
14
  ];
9
15
  export function upgradeSteps(kind) {
10
16
  const first = upgrades.findIndex((step) => step.from === kind);
@@ -3,10 +3,14 @@ export interface WatchedEvent {
3
3
  readonly messageId: string | null;
4
4
  readonly attributes: Readonly<Record<string, unknown>>;
5
5
  }
6
+ export interface WatchReport {
7
+ readonly kind: "stranded" | "dead-lettered";
8
+ readonly messageId: string;
9
+ }
10
+ export type MessageRuns = (messageIds: readonly string[]) => Promise<ReadonlyMap<string, string>>;
6
11
  export interface StrandingWatchdog {
7
12
  readonly observe: (event: WatchedEvent) => void;
8
- readonly stranded: () => string | undefined;
9
- readonly deadLettered: () => string | undefined;
13
+ readonly report: (runs: MessageRuns) => Promise<WatchReport | undefined>;
10
14
  }
11
15
  export declare function strandingWatchdog(bound: {
12
16
  readonly boundMilliseconds: number;
@@ -1,3 +1,4 @@
1
+ import { terminal } from "../../authority/transitions.js";
1
2
  const callbacks = ["deliveryCompleted", "deliveryFailed"];
2
3
  const finished = [
3
4
  "solid_objects.message.completed",
@@ -7,33 +8,54 @@ const finished = [
7
8
  export function strandingWatchdog(bound) {
8
9
  const clock = bound.clock ?? monotonic;
9
10
  const lost = new Map();
10
- const dead = [];
11
- let reported;
11
+ const dead = new Set();
12
12
  return {
13
13
  observe: (event) => {
14
14
  const { messageId } = event;
15
15
  if (messageId === null)
16
16
  return;
17
17
  if (deadCallback(event))
18
- dead.push(messageId);
18
+ dead.add(messageId);
19
19
  if (event.name === "solid_objects.activation.lost" &&
20
20
  !lost.has(messageId))
21
21
  lost.set(messageId, clock());
22
22
  if (finished.includes(event.name))
23
23
  lost.delete(messageId);
24
24
  },
25
- stranded: () => {
26
- reported ??= overdue(lost, clock() - bound.boundMilliseconds);
27
- return reported;
25
+ report: async (runs) => {
26
+ const overdue = overdueMessages(lost, clock() - bound.boundMilliseconds);
27
+ const suspects = [...dead, ...overdue];
28
+ if (suspects.length === 0)
29
+ return undefined;
30
+ const statuses = await runs(suspects);
31
+ const released = suspects.filter((messageId) => settled(statuses.get(messageId)));
32
+ for (const messageId of released) {
33
+ lost.delete(messageId);
34
+ dead.delete(messageId);
35
+ }
36
+ return firstReport({ dead: [...dead], stranded: overdue, lost });
28
37
  },
29
- deadLettered: () => dead[0],
30
38
  };
31
39
  }
32
40
  function monotonic() {
33
41
  return performance.now();
34
42
  }
35
- function overdue(lost, limit) {
36
- return [...lost].find(([, at]) => at < limit)?.[0];
43
+ function overdueMessages(lost, limit) {
44
+ return [...lost]
45
+ .filter(([, at]) => at < limit)
46
+ .map(([messageId]) => messageId);
47
+ }
48
+ function settled(status) {
49
+ return terminal.some((candidate) => candidate === status);
50
+ }
51
+ function firstReport(found) {
52
+ const deadLetter = found.dead[0];
53
+ if (deadLetter !== undefined)
54
+ return { kind: "dead-lettered", messageId: deadLetter };
55
+ const stranded = found.stranded.find((messageId) => found.lost.has(messageId));
56
+ return stranded === undefined
57
+ ? undefined
58
+ : { kind: "stranded", messageId: stranded };
37
59
  }
38
60
  function deadCallback(event) {
39
61
  return (event.name === "solid_objects.dead_letter.created" &&
@@ -76,6 +76,7 @@ async function begun(opening) {
76
76
  reason: "unresolved-delivery",
77
77
  detail: condition,
78
78
  };
79
+ await parts.memory.load(owned.database);
79
80
  return integer(opened, "epoch");
80
81
  }
81
82
  async function start(opening) {
@@ -99,6 +100,7 @@ async function start(opening) {
99
100
  authority: authoritySession({
100
101
  database,
101
102
  reader: parts.reader,
103
+ memory: parts.memory,
102
104
  execute: (request) => authority.execute(json(request)),
103
105
  run: (signal) => parts.runtime.run(signal),
104
106
  stop: parts.stop,
@@ -106,8 +108,8 @@ async function start(opening) {
106
108
  deliveryConfigured: options.delivery !== undefined,
107
109
  epoch,
108
110
  ...parts.limits,
109
- unhealthy: parts.unhealthy,
110
111
  condition: parts.condition,
112
+ logger: parts.logger,
111
113
  watchMilliseconds: parts.watchMilliseconds,
112
114
  subscribe: (listener) => parts.subscribe(actorId, listener),
113
115
  }),
@@ -1,3 +1,4 @@
1
+ import { commandWaitDeadline } from "../command-wait-restore.js";
1
2
  import { createHash } from "node:crypto";
2
3
  import { delivers, isSettled } from "../../authority/gates.js";
3
4
  import { eligibleIntents, } from "../../authority/reducer.js";
@@ -26,6 +27,7 @@ export function protectedIntent(state, attempt) {
26
27
  .filter((lease) => lease.resourceKey === operation.leaseKey)
27
28
  .map((lease) => ({
28
29
  ...intent,
30
+ ...commandWaitDeadline(state.commandWaits ?? {}, operation.operationId),
29
31
  workflow,
30
32
  purpose,
31
33
  inputDigest: operation.inputDigest,
@@ -16,4 +16,4 @@ export interface Attempt {
16
16
  readonly effectId: string;
17
17
  }
18
18
  export declare function deliverEffect(parts: EffectDelivery, attempt: Attempt): Promise<JsonObject>;
19
- export declare function protectedArguments(value: JsonObject): EffectArguments;
19
+ export declare function protectedArguments(value: JsonObject): EffectArguments & Pick<ProtectedIntent, "commandDeadline">;
@@ -1,3 +1,4 @@
1
+ import { dispatchCommandWait, readCommandWaitDeadline, } from "../command-wait-restore.js";
1
2
  import { dispatchDecision, } from "../../authority/dispatch-decision.js";
2
3
  import { integer, optionalInteger, optionalText, text, } from "../../storage/domain-rows.js";
3
4
  import { budgetRow } from "../../storage/effect-rows.js";
@@ -16,11 +17,16 @@ const absent = {
16
17
  budget: undefined,
17
18
  };
18
19
  async function dispatchRead(connection, attempt) {
19
- const row = await connection.get("SELECT d.outcome, d.input_digest, a.lease_generation, o.released_sequence, r.status, r.workflow, p.status AS operation_status, p.capability, p.units, l.operation_id AS lease_owner, l.generation, l.expires_at, l.state AS lease_state, b.run_id, b.effect_limit, b.spent, b.capabilities, b.exhausted_sequence FROM deliveries d JOIN outbox o ON o.operation_id = d.operation_id JOIN runs r ON r.run_id = o.run_id JOIN dispatch_attempts a ON a.effect_id = d.effect_id JOIN operations p ON p.operation_id = d.operation_id JOIN leases l ON l.resource_key = p.lease_key JOIN run_budgets b ON b.run_id = o.run_id WHERE d.effect_id = ? AND d.operation_id = ?", [attempt.effectId, attempt.intent.operationId]);
20
+ const row = await connection.get("SELECT d.outcome, d.input_digest, a.lease_generation, o.released_sequence, r.status, r.workflow, p.status AS operation_status, p.capability, p.units, p.method, p.target, p.payload, l.operation_id AS lease_owner, l.generation, l.expires_at, l.state AS lease_state, b.run_id, b.effect_limit, b.spent, b.capabilities, b.exhausted_sequence FROM deliveries d JOIN outbox o ON o.operation_id = d.operation_id JOIN runs r ON r.run_id = o.run_id JOIN dispatch_attempts a ON a.effect_id = d.effect_id JOIN operations p ON p.operation_id = d.operation_id JOIN leases l ON l.resource_key = p.lease_key JOIN run_budgets b ON b.run_id = o.run_id WHERE d.effect_id = ? AND d.operation_id = ?", [attempt.effectId, attempt.intent.operationId]);
20
21
  if (row === undefined)
21
22
  return absent;
22
23
  const workflow = text(row, "workflow");
23
24
  return {
25
+ ...(await dispatchCommandWait(connection, {
26
+ runId: attempt.intent.runId,
27
+ workflow,
28
+ operationId: attempt.intent.operationId,
29
+ })),
24
30
  attempt: {
25
31
  outcome: optionalText(row, "outcome"),
26
32
  inputDigest: text(row, "input_digest"),
@@ -37,6 +43,9 @@ async function dispatchRead(connection, attempt) {
37
43
  status: text(row, "operation_status"),
38
44
  capability: text(row, "capability"),
39
45
  units: integer(row, "units"),
46
+ method: text(row, "method"),
47
+ target: text(row, "target"),
48
+ payload: text(row, "payload"),
40
49
  },
41
50
  budget: storedBudget(budgetRow(row)),
42
51
  lease: {
@@ -52,7 +61,8 @@ async function called(parts, call) {
52
61
  const adapterCall = parts.delivery[name]?.bind(parts.delivery);
53
62
  if (adapterCall === undefined)
54
63
  return { kind: "unknown", reason: "stop-not-supported" };
55
- return settlement(await parts.calls.call(intent.operationId, (signal) => adapterCall(intent, signal)), intent.capability === "command"
64
+ const deadline = await parts.reader.connection((connection) => readCommandWaitDeadline(connection, intent));
65
+ return settlement(await parts.calls.call(intent.operationId, (signal) => adapterCall({ ...intent, ...deadline }, signal)), intent.capability === "command"
56
66
  ? commandLimits.resultBytes
57
67
  : parts.effects.resultBytes);
58
68
  }
@@ -126,5 +136,8 @@ export function protectedArguments(value) {
126
136
  method: text(value, "method"),
127
137
  target: text(value, "target"),
128
138
  payload: text(value, "payload"),
139
+ ...(typeof value["commandDeadline"] === "string"
140
+ ? { commandDeadline: value["commandDeadline"] }
141
+ : {}),
129
142
  };
130
143
  }
@@ -1,3 +1,5 @@
1
+ import { operationPhase } from "../../operation-identity.js";
2
+ import { endedCommandWaitCheck } from "../../authority/command-waits.js";
1
3
  import { isInstant } from "../../authority/instants.js";
2
4
  import { promotions } from "../../authority/leases.js";
3
5
  import { execute } from "../../authority/reducer.js";
@@ -45,7 +47,9 @@ function closure(state, operation) {
45
47
  return ["run-ended"];
46
48
  const exhausted = (state.effects.budgets[operation.runId]?.exhaustedSequence ?? null) !==
47
49
  null;
48
- return exhausted ? ["budget-exhausted"] : [];
50
+ return exhausted && operationPhase(operation.operationId) !== "command-wait"
51
+ ? ["budget-exhausted"]
52
+ : [];
49
53
  }
50
54
  function unblocked(state, followUp) {
51
55
  const steps = [];
@@ -95,6 +99,9 @@ const outcomes = {
95
99
  }),
96
100
  completed: (attempt) => stated({
97
101
  outcome: "completed",
102
+ ...(attempt.worker === "command"
103
+ ? { commandOutput: attempt.result }
104
+ : {}),
98
105
  result: attempt.result === null ? null : documentDigest(attempt.result),
99
106
  reason: attempt.reason,
100
107
  ...identified(attempt),
@@ -155,7 +162,9 @@ function acceptedNow(reconciling) {
155
162
  export function reconciliations(state, reconciling) {
156
163
  const accepted = acceptedNow(reconciling);
157
164
  const rejected = rejectedReports(reconciling.results);
158
- const due = (operation) => state.runs[operation.runId]?.status !== "cancelled" && live(operation);
165
+ const due = (operation) => state.runs[operation.runId]?.status !== "cancelled" &&
166
+ !endedCommandWaitCheck(state.commandWaits ?? {}, operation.operationId) &&
167
+ live(operation);
159
168
  const live = (operation) => (operation.status === "recovering" &&
160
169
  !accepted.has(operation.operationId)) ||
161
170
  (operation.status === "blocked" && rejected.has(operation.operationId));
@@ -8,6 +8,10 @@ export interface OperationView extends OperationRow {
8
8
  }
9
9
  export type StoredDisposition = Omit<Evidence, "sequence">;
10
10
  export interface EffectQueries {
11
+ readonly workerTurns: (window: {
12
+ readonly after: string;
13
+ readonly through: string;
14
+ }) => Promise<readonly OperationView[]>;
11
15
  readonly operation: (operationId: string) => Promise<OperationView | undefined>;
12
16
  readonly operations: (runId: string) => Promise<readonly OperationView[]>;
13
17
  readonly evidence: (runId: string) => Promise<readonly number[]>;
@@ -34,7 +34,9 @@ const viewColumns = operationColumns
34
34
  .map((name) => `o.${name}`)
35
35
  .join(", ");
36
36
  const waitCause = "CASE WHEN o.status != 'waiting' THEN NULL WHEN r.status != 'running' THEN 'run-not-running' WHEN EXISTS (SELECT 1 FROM leases h WHERE h.resource_key = o.lease_key AND h.state != 'released') THEN 'resource' ELSE 'ready' END";
37
- const viewed = `SELECT ${viewColumns}, l.generation AS lease_generation, ${waitCause} AS wait_cause FROM operations o JOIN runs r ON r.run_id = o.run_id LEFT JOIN leases l ON l.resource_key = o.lease_key AND l.operation_id = o.operation_id AND l.state != 'released'`;
37
+ const viewSelection = `SELECT ${viewColumns}, l.generation AS lease_generation, ${waitCause} AS wait_cause`;
38
+ const viewJoins = "JOIN runs r ON r.run_id = o.run_id LEFT JOIN leases l ON l.resource_key = o.lease_key AND l.operation_id = o.operation_id AND l.state != 'released'";
39
+ const viewed = `${viewSelection} FROM operations o ${viewJoins}`;
38
40
  function operationView(row) {
39
41
  return {
40
42
  ...operationRow(row),
@@ -52,6 +54,11 @@ async function operations(connection, runId) {
52
54
  const rows = await connection.all(`${viewed} WHERE o.run_id = ? ORDER BY o.requested_sequence`, [runId]);
53
55
  return rows.map(operationView);
54
56
  }
57
+ async function workerTurns(connection, window) {
58
+ const settled = await connection.all(`${viewSelection} FROM events e CROSS JOIN operations o ${viewJoins} WHERE o.settled_sequence = e.sequence AND o.capability = 'claude' AND julianday(e.recorded_at) > julianday(?) AND julianday(e.recorded_at) <= julianday(?)`, [window.after, window.through]);
59
+ const open = await connection.all(`${viewSelection} FROM operations o INDEXED BY operations_worker_open ${viewJoins} WHERE o.capability = 'claude' AND o.settled_sequence IS NULL AND o.status NOT IN ('refused', 'completed', 'failed', 'stopped', 'cancelled')`);
60
+ return [...settled, ...open].map(operationView);
61
+ }
55
62
  async function evidence(connection, runId) {
56
63
  const rows = await connection.all("SELECT e.sequence FROM effect_evidence e JOIN events v ON v.sequence = e.sequence WHERE e.run_id = ? AND (e.disposition IN ('rejected', 'denied', 'refused') OR (v.type = 'operation.reconciled' AND json_extract(v.payload, '$.outcome') = 'unknown')) ORDER BY e.sequence", [runId]);
57
64
  return rows.map((row) => integer(row, "sequence"));
@@ -74,6 +81,7 @@ async function budget(connection, runId) {
74
81
  }
75
82
  export function effectQueries(read, settings) {
76
83
  return {
84
+ workerTurns: (window) => read((connection) => workerTurns(connection, window)),
77
85
  stops: (runId) => read((connection) => stops(connection, runId)),
78
86
  closure: (runId) => read((connection) => storedClosure(connection, { runId, stopLimit: settings.stopLimit })),
79
87
  settledAt: (runId) => read((connection) => settledAt(connection, runId)),
@@ -1,3 +1,4 @@
1
+ import { readCommandWaitDeadline } from "../command-wait-restore.js";
1
2
  import { detailColumns, detailRow } from "../../storage/decision-rows.js";
2
3
  import { integer, runRow, text, } from "../../storage/domain-rows.js";
3
4
  import { storedRun } from "../authority-restore.js";
@@ -57,6 +58,7 @@ export async function pendingEffect(connection, attempt) {
57
58
  return {
58
59
  ...intent,
59
60
  purpose,
61
+ ...(await readCommandWaitDeadline(connection, intent)),
60
62
  inputDigest: text(row, "input_digest"),
61
63
  leaseGeneration: integer(row, "generation"),
62
64
  capability: text(row, "capability"),