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,3 +1,5 @@
1
+ import { scheduleStatusLine, scheduledText, shownScheduled, } from "./schedule-render.js";
2
+ import * as waitDisplay from "./command-waits.js";
1
3
  import { cardReply } from "./watch-card-reply.js";
2
4
  import { record } from "../protocol.js";
3
5
  import { Commands, commandText } from "./command-effects.js";
@@ -7,24 +9,30 @@ import { watchClient } from "./watch-client.js";
7
9
  import { watchPhoneClient } from "./watch-phone-client.js";
8
10
  import { PhoneAsk, PhoneCode, PhoneList, PhonePanel, phoneButton, phoneNotices, refusalText, timeLeft, } from "./watch-phone-view.js";
9
11
  import { priceOf, tokenCount, usageOf } from "../worker-usage.js";
10
- import { priceText, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
11
- import { startPrompts, StartCard, StartRun } from "./watch-start-view.js";
12
+ import { priceText, queueSpendLines, usageText, attemptText, totalsSuffix, } from "./usage-render.js";
12
13
  import { Board, boardSizing, Card, HandoffLinks, Column, columnCollapsed, CardReview, WorkflowList, cardReview, cardStep, completionMark, observationText, staleObservation, } from "./watch-board-view.js";
13
14
  import { boardWorkflow, watchHash, watchLocation, watchTitle, } from "./watch-navigation.js";
14
15
  import { clockTime, completedDetail, counted, elapsed, groupActivity, pageTitle, phaseTime, runName, runTone, selectedRun, toneOf, turnTime, waitingDetail, } from "./watch-render.js";
15
16
  import { Command, Decision, Events, Group, Item, Turn, Work, } from "./watch-turn.js";
16
17
  import { Banner, BannerDetail, BoardPage, Page, Phases, PullRequest, Review, RefusedWorkflows, Run, } from "./watch-view.js";
17
- import { Brand, clove, Header, HeaderActions, HeaderStatus, Queue, queueLanes, skippedText, } from "./watch-header-view.js";
18
+ import { Brand, clove, Header, HeaderActions, HeaderStatus, Queue, queueLanes, skippedText, Version, } from "./watch-header-view.js";
18
19
  const functions = [
20
+ scheduleStatusLine,
21
+ scheduledText,
22
+ shownScheduled,
19
23
  record,
20
24
  commandText,
21
25
  Commands,
26
+ waitDisplay.CommandWaits,
27
+ waitDisplay.commandWaitText,
28
+ waitDisplay.effectBudgetText,
22
29
  queueLanes,
23
30
  skippedText,
24
31
  Queue,
25
32
  Brand,
26
33
  HeaderStatus,
27
34
  HeaderActions,
35
+ Version,
28
36
  cardReply,
29
37
  cardSubmitKey,
30
38
  cardKey,
@@ -34,6 +42,7 @@ const functions = [
34
42
  tokenCount,
35
43
  usageOf,
36
44
  priceText,
45
+ queueSpendLines,
37
46
  usageText,
38
47
  attemptText,
39
48
  totalsSuffix,
@@ -73,9 +82,6 @@ const functions = [
73
82
  Command,
74
83
  Decision,
75
84
  Events,
76
- startPrompts,
77
- StartCard,
78
- StartRun,
79
85
  BannerDetail,
80
86
  Banner,
81
87
  Phases,
@@ -146,7 +152,6 @@ body { margin: 0 auto; max-width: 1800px; padding: 0 20px 96px; }
146
152
  body:has(.board-page) { padding-bottom: 0; overflow: hidden; }
147
153
  .board-page { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
148
154
  .board-page > header, .board-page > .down { flex-shrink: 0; }
149
- .start-run { flex-shrink: 0; max-height: 45dvh; overflow-y: auto; }
150
155
  .workflow-refusals { flex-shrink: 0; max-height: 25dvh; overflow-y: auto; overflow-wrap: anywhere; }
151
156
  .workflow-refusals h2 { margin: 8px 0; }
152
157
  a { color: var(--accent-strong); }
@@ -168,12 +173,6 @@ header { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; padding
168
173
  .brand svg { width: 30px; height: 30px; color: var(--accent); }
169
174
  a:focus-visible, button:focus-visible, summary:focus-visible, input:focus-visible, textarea:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 6px var(--code-bg); }
170
175
  h2, h3 { font-family: var(--heading-font); font-weight: 700; }
171
- .start-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); gap: 16px; margin-top: 12px; }
172
- .start-card { min-width: 0; padding: 14px; border-radius: 14px; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
173
- .start-card h3 { margin: 0; }
174
- .start-card p { margin: 6px 0 12px; }
175
- .start-card .command { grid-template-columns: minmax(0, 1fr); margin: 0; }
176
- .start-card button { justify-self: end; }
177
176
  .workspace { display: flex; width: 100%; margin-top: 12px; flex: 1; min-height: 0; }
178
177
  .workflows { display: flex; flex-direction: row; flex-shrink: 0; gap: 8px; min-width: 0; margin-top: 12px; padding: 6px; overflow-x: auto; overflow-y: hidden; }
179
178
  .workflows a { display: grid; flex-shrink: 0; white-space: nowrap; gap: 2px; border-bottom: 3px solid transparent; padding: 10px; color: inherit; text-decoration: none; }
@@ -192,8 +191,8 @@ h2, h3 { font-family: var(--heading-font); font-weight: 700; }
192
191
  .column-cards { min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; }
193
192
  .column.collapsed { flex: 0 0 ${String(boardSizing.collapsedColumnWidth)}px; min-width: ${String(boardSizing.collapsedColumnWidth)}px; padding: 6px; }
194
193
  .collapsed .column-name { writing-mode: vertical-rl; padding: 0; }
195
- header button, .phone button, .column-name button, .add-card, .add-card-form button, .start-card button { font: 500 13px/1.4 var(--body-font); color: var(--ink); background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); margin: 0; }
196
- header button:hover, .phone button:hover, .column-name button:hover, .add-card:hover, .add-card-form button:hover, .start-card button:hover { background: var(--surface-2); }
194
+ header button, .phone button, .column-name button, .add-card, .add-card-form button { font: 500 13px/1.4 var(--body-font); color: var(--ink); background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); margin: 0; }
195
+ header button:hover, .phone button:hover, .column-name button:hover, .add-card:hover, .add-card-form button:hover { background: var(--surface-2); }
197
196
  .add-card, .add-card-form button { color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); margin: 4px 8px 4px 0; }
198
197
  .add-card { width: 100%; text-align: left; margin: 4px 0; }
199
198
  .add-card-form { padding: 8px 0; overflow-wrap: anywhere; }
@@ -286,6 +285,7 @@ button:hover { background: var(--code-head); }
286
285
  .events { margin-top: 18px; padding-bottom: 10px; }
287
286
  .events > summary { color: var(--code-fg); }
288
287
  .down { font-weight: 600; }
288
+ .version { position: fixed; left: 12px; bottom: 8px; font: 12px/1.4 var(--code-font); color: var(--muted); pointer-events: none; }
289
289
  @media (max-width: 700px) { body { padding-inline: 12px; } }
290
290
  `;
291
291
  export function pageDocument(actionToken = null) {
@@ -1,7 +1,16 @@
1
- import type { WatchPhase } from "./watch-render.ts";
2
- export declare const issueSteps: {
1
+ import type { WorkflowStage } from "../workflow-declaration.ts";
2
+ import type { WatchPhase, WatchPullRequest } from "./watch-render.ts";
3
+ export declare const pullRequestSteps: {
3
4
  name: string;
4
5
  operation: string;
5
6
  }[];
6
7
  export declare function decisionOf(events: readonly unknown[]): string;
7
- export declare function phasesOf(events: readonly unknown[], workflowId?: string): WatchPhase[];
8
+ export declare function pullRequestStepOf(event: unknown): {
9
+ name: string;
10
+ operation: string;
11
+ } | undefined;
12
+ export declare function stageOf(event: unknown, stages: readonly WorkflowStage[]): WorkflowStage | undefined;
13
+ export declare function phasesOf(events: readonly unknown[], workflow?: {
14
+ readonly pullRequest?: WatchPullRequest | null;
15
+ readonly stages?: readonly WorkflowStage[] | undefined;
16
+ }): WatchPhase[];
@@ -5,8 +5,7 @@ const endings = [
5
5
  ];
6
6
  const review = { open: "gate.opened", close: "gate.decided" };
7
7
  const effect = { open: "effect.requested", close: "effect.reported" };
8
- const issueWorkflow = "develop-issue";
9
- export const issueSteps = [
8
+ export const pullRequestSteps = [
10
9
  { name: "Work tree", operation: "github-prepare" },
11
10
  { name: "Agent turn", operation: "claude-turn" },
12
11
  { name: "Pull request", operation: "github-open-pr" },
@@ -79,24 +78,82 @@ function operationOf(event) {
79
78
  return [];
80
79
  }
81
80
  }
81
+ export function pullRequestStepOf(event) {
82
+ const scope = operationOf(record(event));
83
+ return pullRequestSteps.find((step) => step.operation === scope[4] ||
84
+ (step.name === "Code review" && scope[3] === "review") ||
85
+ (step.name === "Merge" && scope[3] === "merge"));
86
+ }
87
+ function stepEffects(events, context) {
88
+ const { step, round } = context;
89
+ const repeated = roundOperations.includes(step.operation);
90
+ const currentTurn = events.findLastIndex((event) => event["type"] === effect.open && operationOf(event)[4] === "claude-turn");
91
+ const requested = new Set(events
92
+ .slice(currentTurn + 1)
93
+ .filter((event) => event["type"] === effect.open)
94
+ .map((event) => record(event["payload"])["operationId"]));
95
+ return events.filter((event) => {
96
+ if (pullRequestStepOf(event) !== step)
97
+ return false;
98
+ if (!repeated)
99
+ return true;
100
+ const scope = operationOf(event);
101
+ return roundOperations.includes(String(scope[4]))
102
+ ? scope[1] === round
103
+ : requested.has(record(event["payload"])["operationId"]);
104
+ });
105
+ }
106
+ export function stageOf(event, stages) {
107
+ const fields = record(event);
108
+ if ([effect.open, effect.close].includes(String(fields["type"]))) {
109
+ const operation = operationOf(fields)[4];
110
+ return stages.find((stage) => stage.operations?.some((name) => name === operation));
111
+ }
112
+ const payload = record(fields["payload"]);
113
+ return (stages.find((stage) => stage.gateIds?.some((name) => name === payload["gateId"])) ??
114
+ stages.find((stage) => stage.gateKinds?.some((name) => name === payload["gateKind"])));
115
+ }
116
+ function declaredSpans(events, stages) {
117
+ return stages.map((stage) => {
118
+ const index = events.findLastIndex((event) => [effect.open, review.open].includes(String(event["type"])) &&
119
+ stageOf(event, stages) === stage);
120
+ const opening = events[index];
121
+ const pair = opening?.["type"] === review.open ? review : effect;
122
+ const identity = pair === review ? "gateId" : "operationId";
123
+ const key = record(opening?.["payload"])[identity];
124
+ const closing = events
125
+ .slice(index + 1)
126
+ .findLast((event) => event["type"] === pair.close &&
127
+ key !== undefined &&
128
+ record(event["payload"])[identity] === key);
129
+ const payload = record(closing?.["payload"]);
130
+ const failed = unfinished.includes(String(payload["outcome"])) ||
131
+ payload["decision"] === "denied";
132
+ return {
133
+ name: stage.label,
134
+ startedAt: timeOf(opening),
135
+ endedAt: timeOf(closing),
136
+ ending: failed ? "failed" : "done",
137
+ };
138
+ });
139
+ }
82
140
  function currentRound(events) {
83
141
  const requested = events.findLast((event) => event["type"] === effect.open && operationOf(event)[4] === "claude-turn");
84
142
  const round = operationOf(requested)[1];
85
143
  return typeof round === "number" ? round : 1;
86
144
  }
87
- function spans(events, workflowId) {
88
- if (workflowId !== issueWorkflow)
145
+ function spans(events, workflow) {
146
+ if (workflow.stages !== undefined)
147
+ return [...admission(events), ...declaredSpans(events, workflow.stages)];
148
+ if (workflow.pullRequest == null)
89
149
  return ticketSpans(events);
90
150
  const effects = events.filter((event) => [effect.open, effect.close].includes(String(event["type"])));
91
151
  const round = currentRound(effects);
92
152
  return [
93
153
  ...admission(events),
94
- ...issueSteps.map((step) => {
154
+ ...pullRequestSteps.map((step) => {
95
155
  const repeated = roundOperations.includes(step.operation);
96
- const own = effects.filter((event) => {
97
- const scope = operationOf(event);
98
- return scope[4] === step.operation && (!repeated || scope[1] === round);
99
- });
156
+ const own = stepEffects(effects, { step, round });
100
157
  const last = own.findLast((event) => event["type"] === effect.close);
101
158
  const outcome = String(record(last?.["payload"])["outcome"]);
102
159
  return {
@@ -132,9 +189,9 @@ function advanced(phases) {
132
189
  ? { ...item, state: "active" }
133
190
  : item);
134
191
  }
135
- export function phasesOf(events, workflowId = "") {
192
+ export function phasesOf(events, workflow = {}) {
136
193
  const known = events.map(record);
137
- const steps = spans(known, workflowId);
194
+ const steps = spans(known, workflow);
138
195
  const [end] = ends(known);
139
196
  if (end !== undefined)
140
197
  return [...steps.map((span) => phase(span, "failed")), end];
@@ -2,7 +2,7 @@ function observedCard(context, card) {
2
2
  if (card.completionMark?.text !== "Needs attention")
3
3
  return card;
4
4
  const run = context.model.runs.find((run) => run.runId === card.runId);
5
- if (run?.workflowId !== "develop-issue" ||
5
+ if (run === undefined ||
6
6
  run.state !== "completed" ||
7
7
  run.outcome !== "blocked" ||
8
8
  run.pullRequest === null)
@@ -6,6 +6,7 @@ export interface WatchCommandOutput {
6
6
  readonly errorCode: string | null;
7
7
  }
8
8
  export interface WatchCommandRequest {
9
+ readonly outputBytes?: number;
9
10
  readonly command: readonly string[];
10
11
  readonly directory: string;
11
12
  readonly signal: AbortSignal;
@@ -23,6 +23,11 @@ function list(value) {
23
23
  function count(value) {
24
24
  return typeof value === "number" ? value : null;
25
25
  }
26
+ function methodScope(method, operation) {
27
+ if (operation[3] === "pull-request")
28
+ return operation[4] === `github-${method}`;
29
+ return (method === "merge" && operation[3] === "merge" && operation[4] === "merge");
30
+ }
26
31
  function attributed(started, operation) {
27
32
  const stage = list(operation[5]);
28
33
  const checked = operationIdentity({
@@ -37,8 +42,7 @@ function attributed(started, operation) {
37
42
  });
38
43
  return (checked.kind === "valid" &&
39
44
  checked.value === JSON.stringify(operation) &&
40
- operation[3] === "pull-request" &&
41
- operation[4] === `github-${text(started["method"])}` &&
45
+ methodScope(text(started["method"]), operation) &&
42
46
  (started["runId"] === undefined || started["runId"] === operation[2]));
43
47
  }
44
48
  function githubOf(records) {
@@ -47,22 +51,28 @@ function githubOf(records) {
47
51
  const result = record(records.result);
48
52
  const completed = result["outcome"] === "completed";
49
53
  return {
50
- runId: text(operation[2]),
54
+ runId: started["runId"] === undefined || started["runId"] === operation[2]
55
+ ? text(operation[2])
56
+ : "",
51
57
  round: Number(operation[1]),
58
+ startedAt: Date.parse(text(started["startedAt"])) || 0,
52
59
  method: text(started["method"]),
53
60
  completed,
54
61
  attributed: attributed(started, operation) && !Object.hasOwn(result, "reason"),
55
62
  report: completed ? record(parsed(text(result["result"]))) : {},
56
63
  };
57
64
  }
58
- function pullRequestOf(results) {
65
+ function pullRequestOf(results, repository) {
59
66
  const opened = results
60
- .filter((item) => item.method === "open-pr")
67
+ .filter((item) => item.method === "open-pr" && item.completed)
61
68
  .map((item) => item.report)
62
69
  .findLast((report) => text(report["url"]).startsWith("https://"));
63
70
  if (opened === undefined)
64
71
  return null;
65
- return { number: Number(opened["number"]), url: text(opened["url"]) };
72
+ const pull = { number: Number(opened["number"]), url: text(opened["url"]) };
73
+ return repository === null || prIdentity(repository, pull) !== null
74
+ ? pull
75
+ : null;
66
76
  }
67
77
  function reviewsOf(results) {
68
78
  return results
@@ -115,8 +125,8 @@ export function pullOf(inputs, runId) {
115
125
  const results = inputs.records
116
126
  .map(githubOf)
117
127
  .filter((item) => item.runId === runId)
118
- .toSorted((first, second) => first.round - second.round);
119
- const pullRequest = pullRequestOf(results);
128
+ .toSorted((first, second) => first.round - second.round || first.startedAt - second.startedAt);
129
+ const pullRequest = pullRequestOf(results, inputs.repository);
120
130
  const mergeProof = mergeProofOf(results, {
121
131
  repository: inputs.repository,
122
132
  pullRequest,
@@ -1,4 +1,5 @@
1
1
  import { type PrRepository } from "./watch-pr-identity.ts";
2
+ import { type ShownSchedules } from "./schedule-render.ts";
2
3
  import { type WorkflowStages } from "../workflow-declaration.ts";
3
4
  import { type Fields } from "../protocol.ts";
4
5
  import { type WorkflowRefusal } from "../workflow-refusals.ts";
@@ -16,8 +17,10 @@ interface ReadRun {
16
17
  readonly events: readonly ReadEvent[];
17
18
  }
18
19
  export interface WatchRead {
20
+ readonly schedules?: ShownSchedules;
19
21
  readonly queue?: Fields;
20
22
  readonly service: string;
23
+ readonly serviceVersion?: string;
21
24
  readonly workflows: readonly string[];
22
25
  readonly workflowRefusals: readonly WorkflowRefusal[];
23
26
  readonly workflowStages?: WorkflowStages;
@@ -1,5 +1,6 @@
1
1
  import { establishedIssue } from "./watch-pr-identity.js";
2
- import { isWorkflowStages, } from "../workflow-declaration.js";
2
+ import { shownSchedules } from "./schedule-render.js";
3
+ import { workflowStagesOf, } from "../workflow-declaration.js";
3
4
  import { record } from "../protocol.js";
4
5
  import { send } from "./client.js";
5
6
  import { activeRun, recentRun } from "./watch-board.js";
@@ -86,7 +87,6 @@ async function creationOf(reader, runId) {
86
87
  function matchingCompletion(status, context) {
87
88
  const issue = establishedIssue(context.repository, status["issueIdentity"]);
88
89
  return (status.state === "completed" &&
89
- status["workflowId"] === "develop-issue" &&
90
90
  record(status["outcome"])?.["kind"] === "handoff_requested" &&
91
91
  record(status["outcome"])?.["ticketStatus"] !== "partial" &&
92
92
  record(status["outcome"])?.["issueUpdate"] !== "failed" &&
@@ -127,20 +127,17 @@ async function completionOf(reader, search) {
127
127
  reader.completions.set(runId, { ...known, creation });
128
128
  return { status: known.status, events: creation === null ? [] : [creation] };
129
129
  }
130
- function refreshedLinks(run, status) {
131
- const links = Object.fromEntries(["parentRunId", "chainId", "childRunIds"]
130
+ function refreshedStatus(run, status) {
131
+ const links = Object.fromEntries(["parentRunId", "chainId", "childRunIds", "commandWaits"]
132
132
  .filter((name) => Object.hasOwn(status, name))
133
133
  .map((name) => [name, status[name]]));
134
- return {
135
- ...run,
136
- status: { ...run.status, ...links },
137
- };
134
+ return { ...run, status: { ...run.status, ...links } };
138
135
  }
139
136
  async function detailed(reader, summary) {
140
137
  const { runId, latestSequence: sequence } = summary;
141
138
  const known = reader.details.get(runId);
142
139
  if (known !== undefined && known.sequence === sequence)
143
- return refreshedLinks(known.value, summary);
140
+ return refreshedStatus(known.value, summary);
144
141
  const shown = await asked(reader, {
145
142
  operation: "status",
146
143
  parameters: { runId },
@@ -181,21 +178,22 @@ function stoppedIssues(runs, context) {
181
178
  const stopped = runs
182
179
  .map((run) => run.status)
183
180
  .filter((status) => recentRun(status.latestAt, context.now) &&
184
- status["workflowId"] === "develop-issue" &&
185
181
  (["failed", "cancelled"].includes(status.state) ||
186
182
  (status.state === "completed" &&
187
183
  record(status["outcome"])?.["kind"] === "blocked")))
188
- .toSorted((first, second) => Date.parse(second.latestAt ?? "") - Date.parse(first.latestAt ?? ""))
189
- .slice(0, 20);
190
- return new Set(stopped.flatMap((status) => {
184
+ .toSorted((first, second) => Date.parse(second.latestAt ?? "") - Date.parse(first.latestAt ?? ""));
185
+ const retained = [
186
+ ...Map.groupBy(stopped, (status) => status["workflowId"]).values(),
187
+ ].flatMap((group) => group.slice(0, 20));
188
+ return new Set(retained.flatMap((status) => {
191
189
  const issue = establishedIssue(context.repository, status["issueIdentity"]);
192
190
  return status.state === "completed" && issue !== null
193
191
  ? [JSON.stringify(issue)]
194
192
  : [];
195
193
  }));
196
194
  }
197
- function stageMetadata(value) {
198
- return Object.fromEntries(Object.entries(record(value) ?? {}).flatMap(([workflowId, stages]) => isWorkflowStages(stages) ? [[workflowId, stages]] : []));
195
+ function versionOf(value) {
196
+ return typeof value === "string" ? { serviceVersion: value } : {};
199
197
  }
200
198
  async function service(reader, now) {
201
199
  const status = await asked(reader, {
@@ -213,9 +211,7 @@ async function service(reader, now) {
213
211
  const issues = stoppedIssues(runs, { now, repository: reader.repository });
214
212
  const older = issues.size === 0
215
213
  ? []
216
- : summaries.filter((summary) => !recentRun(summary.latestAt, now) &&
217
- summary["workflowId"] === "develop-issue" &&
218
- summary.state === "completed");
214
+ : summaries.filter((summary) => !recentRun(summary.latestAt, now) && summary.state === "completed");
219
215
  for (const summary of older) {
220
216
  const candidate = await completionOf(reader, { summary, issues });
221
217
  if (candidate !== null)
@@ -223,11 +219,15 @@ async function service(reader, now) {
223
219
  }
224
220
  return {
225
221
  service: "up",
222
+ ...("schedules" in status
223
+ ? { schedules: shownSchedules(status["schedules"]) }
224
+ : {}),
226
225
  ...(record(status["queue"]) === undefined
227
226
  ? {}
228
227
  : { queue: record(status["queue"]) ?? {} }),
229
228
  workflows: list(status["workflows"]).filter((value) => typeof value === "string"),
230
- workflowStages: stageMetadata(status["workflowStages"]),
229
+ workflowStages: workflowStagesOf(status["workflowStages"]),
230
+ ...versionOf(status["serviceVersion"]),
231
231
  workflowRefusals: workflowRefusals(status["workflowRefusals"]),
232
232
  summaries,
233
233
  runs,
@@ -247,11 +247,13 @@ async function singleRun(reader, runId) {
247
247
  const status = statusOf(reply.result["run"]);
248
248
  const known = reader.details.get(runId);
249
249
  const value = known !== undefined && known.sequence === status.latestSequence
250
- ? refreshedLinks(known.value, status)
250
+ ? refreshedStatus(known.value, status)
251
251
  : await remember(reader, status);
252
+ const metadata = await asked(reader, { operation: "status", parameters: {} });
252
253
  return {
253
254
  ...unavailable,
254
255
  service: "up",
256
+ workflowStages: workflowStagesOf(metadata["workflowStages"]),
255
257
  runs: [value],
256
258
  decisions: await decisionsOf(reader),
257
259
  };
@@ -1,3 +1,5 @@
1
+ import type { ShownSchedule, ShownSchedules } from "./schedule-render.ts";
2
+ import type { CommandWaitView } from "../authority/command-wait-view.ts";
1
3
  import type { CommandEffect } from "../command-settings.ts";
2
4
  import type { CardForm } from "./watch-run-input.ts";
3
5
  import type { CiRerunNotice } from "./github-ci-progress.ts";
@@ -68,6 +70,12 @@ export interface WatchStep {
68
70
  readonly startedAt: string | null;
69
71
  }
70
72
  export interface WatchCard {
73
+ readonly scheduled?: {
74
+ readonly slot: number;
75
+ };
76
+ readonly commandWaits?: readonly CommandWaitView[];
77
+ readonly spent?: number | null;
78
+ readonly limit?: number | null;
71
79
  readonly awaitedRunId?: string | null;
72
80
  readonly parentRunId?: string | null;
73
81
  readonly chainId?: string;
@@ -95,6 +103,7 @@ export interface WatchColumn {
95
103
  readonly cards: readonly WatchCard[];
96
104
  }
97
105
  export interface WatchWorkflow {
106
+ readonly schedule?: ShownSchedule;
98
107
  readonly workflowId: string;
99
108
  readonly activeCount: number;
100
109
  readonly waitingCount: number;
@@ -102,6 +111,10 @@ export interface WatchWorkflow {
102
111
  readonly columns: readonly WatchColumn[];
103
112
  }
104
113
  export interface WatchRun {
114
+ readonly scheduled?: {
115
+ readonly slot: number;
116
+ };
117
+ readonly commandWaits?: readonly CommandWaitView[];
105
118
  readonly awaitedRunId?: string | null;
106
119
  readonly commandEffects?: readonly CommandEffect[];
107
120
  readonly ciReruns?: readonly CiRerunNotice[];
@@ -140,6 +153,8 @@ export interface WatchRun {
140
153
  readonly mergeCommit: string | null;
141
154
  }
142
155
  export interface WatchModel {
156
+ readonly serviceVersion?: string;
157
+ readonly schedules?: ShownSchedules;
143
158
  readonly queue?: Fields;
144
159
  readonly workflowRefusals?: readonly WorkflowRefusal[];
145
160
  readonly cardForms?: readonly CardForm[];
@@ -10,5 +10,4 @@ export interface CardForm {
10
10
  readonly source: "ticket" | "prompt" | "input";
11
11
  readonly fields: readonly CardField[];
12
12
  }
13
- export declare function builtinCardForms(): readonly CardForm[];
14
13
  export declare function cardRunRequest(forms: readonly CardForm[], value: unknown): ServiceRequest | null;
@@ -1,17 +1,4 @@
1
1
  import { record } from "../protocol.js";
2
- export function builtinCardForms() {
3
- const entries = [
4
- ["develop-issue", "ticket", "Issue number"],
5
- ["develop-ticket", "ticket", "Ticket ID"],
6
- ["develop-prd", "prompt", "Idea"],
7
- ["develop-prompt", "prompt", "Task"],
8
- ];
9
- return entries.map(([workflowId, name, label]) => ({
10
- workflowId,
11
- source: name === "ticket" ? "ticket" : "prompt",
12
- fields: [{ name, label, multiline: name === "prompt", optional: false }],
13
- }));
14
- }
15
2
  function validFields(form, fields) {
16
3
  if (Object.keys(fields).some((name) => !form.fields.some((field) => field.name === name)))
17
4
  return false;
@@ -1,4 +1,5 @@
1
1
  import { watchAction, watchActions, watchHost, } from "./watch-actions.js";
2
+ import { watchApiChange, watchApiReply } from "./watch-api.js";
2
3
  import { observedBoard } from "./watch-pr-board.js";
3
4
  import { isPhoneAction, phoneAction, phoneRead } from "./watch-phone.js";
4
5
  import { watchPrObserver } from "./watch-pr-settings.js";
@@ -9,7 +10,7 @@ import { dirname, join } from "node:path";
9
10
  import { fileURLToPath } from "node:url";
10
11
  import { watchReader } from "./watch-reads.js";
11
12
  import { ciRerunNotices } from "./github-ci-progress.js";
12
- import { turnOf, watchModel } from "./watch-model.js";
13
+ import { turnActivity, turnOf, watchModel, } from "./watch-model.js";
13
14
  import { pageDocument } from "./watch-page.js";
14
15
  import { watchStream } from "./watch-stream.js";
15
16
  export const defaultWatchPort = 3663;
@@ -30,6 +31,7 @@ const fontFiles = new Map([
30
31
  new URL(`assets/watch-fonts/${name}`, import.meta.resolve("#package")),
31
32
  ]));
32
33
  const libraryFile = fileURLToPath(import.meta.resolve("preact"));
34
+ const pageChange = () => "data: change\n\n";
33
35
  function parsed(text) {
34
36
  try {
35
37
  const value = JSON.parse(text);
@@ -39,7 +41,7 @@ function parsed(text) {
39
41
  return null;
40
42
  }
41
43
  }
42
- const noStream = { size: 0, lines: [], activeAt: null };
44
+ const noStream = { size: 0, activity: [], activeAt: null };
43
45
  async function streamed(watch, file) {
44
46
  const found = await stat(file).catch(() => null);
45
47
  if (found === null)
@@ -48,9 +50,9 @@ async function streamed(watch, file) {
48
50
  const activeAt = found.mtime.toISOString();
49
51
  if (known?.size === found.size)
50
52
  return { ...known, activeAt };
51
- const lines = (await readFile(file, "utf8").catch(() => "")).split("\n");
52
- watch.streams.set(file, { size: found.size, lines });
53
- return { size: found.size, lines, activeAt };
53
+ const activity = turnActivity((await readFile(file, "utf8").catch(() => "")).split("\n"));
54
+ watch.streams.set(file, { size: found.size, activity });
55
+ return { size: found.size, activity, activeAt };
54
56
  }
55
57
  async function stored(file) {
56
58
  return parsed(await readFile(file, "utf8").catch(() => "null"));
@@ -67,7 +69,7 @@ async function turns(watch) {
67
69
  key,
68
70
  started,
69
71
  result: await stored(join(journal, key, "result.json")),
70
- lines: stream.lines,
72
+ activity: stream.activity,
71
73
  activeAt: stream.activeAt,
72
74
  }));
73
75
  }
@@ -139,6 +141,14 @@ async function answered(watch, request) {
139
141
  if (font !== null)
140
142
  return font;
141
143
  const url = new URL(String(request.url), "http://localhost");
144
+ const api = await watchApiReply({
145
+ method: request.method ?? "",
146
+ url,
147
+ model: () => snapshot(watch, null),
148
+ run: (runId) => snapshot(watch, runId),
149
+ });
150
+ if (api !== null)
151
+ return api;
142
152
  if (request.method === "GET")
143
153
  return readReply(watch, url);
144
154
  if (request.method !== "POST" || watch.actions === null)
@@ -187,13 +197,14 @@ function replied(response, reply) {
187
197
  response.writeHead(reply.status, {
188
198
  "content-type": reply.type,
189
199
  "cache-control": reply.cache ?? "no-store",
200
+ ...(reply.allow === undefined ? {} : { allow: reply.allow }),
190
201
  });
191
202
  response.end(reply.body);
192
203
  }
193
204
  function subscribed(stream, exchange) {
194
- const { request, response } = exchange;
205
+ const { request, response, message } = exchange;
195
206
  const changed = () => {
196
- response.write("data: change\n\n");
207
+ response.write(message());
197
208
  };
198
209
  response.writeHead(200, {
199
210
  "content-type": "text/event-stream",
@@ -223,11 +234,14 @@ export async function watchServer(settings) {
223
234
  if (watchHost(request) &&
224
235
  request.method === "GET" &&
225
236
  request.url === "/events") {
226
- subscribed(stream, { request, response });
237
+ subscribed(stream, { request, response, message: pageChange });
227
238
  return;
228
239
  }
229
240
  answered(watch, request).then((reply) => {
230
- replied(response, reply);
241
+ if (reply === "stream")
242
+ subscribed(stream, { request, response, message: watchApiChange });
243
+ else
244
+ replied(response, reply);
231
245
  }, () => {
232
246
  replied(response, { ...notFound, status: 500, body: "failed" });
233
247
  });
@@ -1,8 +1,6 @@
1
1
  import type { CardControls } from "./watch-card-view.ts";
2
2
  import type { PhoneControls } from "./watch-phone-view.ts";
3
- import { type StartControls } from "./watch-header-view.ts";
4
3
  export { clove, Header } from "./watch-header-view.ts";
5
- export type { StartControls } from "./watch-header-view.ts";
6
4
  import { type Shown } from "./watch-element.ts";
7
5
  import { type Copying, type WatchModel, type WatchPhase, type WatchRun } from "./watch-render.ts";
8
6
  import { type ColumnControls } from "./watch-board-view.ts";
@@ -33,7 +31,6 @@ export interface PageProps {
33
31
  readonly stale: boolean;
34
32
  readonly copying: Copying;
35
33
  readonly columns?: ColumnControls;
36
- readonly start?: StartControls;
37
34
  readonly phone?: PhoneControls | undefined;
38
35
  }
39
36
  export declare function RefusedWorkflows(props: {