cloving 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/README.md +235 -206
  2. package/dist/src/agent-harness-shell.d.ts +2 -1
  3. package/dist/src/agent-harness-shell.js +8 -5
  4. package/dist/src/authority/command-wait-checks.d.ts +8 -0
  5. package/dist/src/authority/command-wait-checks.js +88 -0
  6. package/dist/src/authority/command-wait-results.d.ts +15 -0
  7. package/dist/src/authority/command-wait-results.js +73 -0
  8. package/dist/src/authority/command-wait-view.d.ts +21 -0
  9. package/dist/src/authority/command-wait-view.js +34 -0
  10. package/dist/src/authority/command-waits.d.ts +39 -0
  11. package/dist/src/authority/command-waits.js +97 -0
  12. package/dist/src/authority/commands.js +22 -1
  13. package/dist/src/authority/dispatch-decision.d.ts +8 -0
  14. package/dist/src/authority/dispatch-decision.js +26 -1
  15. package/dist/src/authority/effect-requests.js +6 -3
  16. package/dist/src/authority/effect-results.js +4 -2
  17. package/dist/src/authority/history-state.d.ts +2 -0
  18. package/dist/src/authority/history-state.js +13 -1
  19. package/dist/src/authority/instants.d.ts +1 -0
  20. package/dist/src/authority/instants.js +21 -0
  21. package/dist/src/authority/reduction-state.d.ts +2 -0
  22. package/dist/src/authority/reduction-state.js +5 -0
  23. package/dist/src/authority/reduction.js +24 -0
  24. package/dist/src/authority/status-input.d.ts +2 -0
  25. package/dist/src/authority/status.d.ts +2 -0
  26. package/dist/src/authority/status.js +1 -0
  27. package/dist/src/authority/stop-sequence.d.ts +1 -0
  28. package/dist/src/authority/stop-sequence.js +2 -1
  29. package/dist/src/authority/transitions.d.ts +6 -4
  30. package/dist/src/authority/transitions.js +7 -0
  31. package/dist/src/broker/actor/authority-queries.d.ts +2 -1
  32. package/dist/src/broker/actor/authority-queries.js +14 -5
  33. package/dist/src/broker/actor/authority-receipts.js +1 -1
  34. package/dist/src/broker/actor/authority-settings.js +2 -2
  35. package/dist/src/broker/actor/authority-upgrades.d.ts +19 -2
  36. package/dist/src/broker/actor/authority-upgrades.js +7 -2
  37. package/dist/src/broker/actor/delivery-intents.js +2 -0
  38. package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
  39. package/dist/src/broker/actor/effect-delivery.js +15 -2
  40. package/dist/src/broker/actor/effect-plan.js +11 -2
  41. package/dist/src/broker/actor/effect-queries.d.ts +4 -0
  42. package/dist/src/broker/actor/effect-queries.js +9 -1
  43. package/dist/src/broker/actor/effect-turn.js +2 -0
  44. package/dist/src/broker/actor/stop-plan.js +9 -3
  45. package/dist/src/broker/actor/stop-turn.d.ts +2 -0
  46. package/dist/src/broker/actor/stop-turn.js +24 -11
  47. package/dist/src/broker/actor/turn-draft.d.ts +1 -0
  48. package/dist/src/broker/actor/turn-draft.js +4 -0
  49. package/dist/src/broker/actor/turn-state.js +5 -1
  50. package/dist/src/broker/authority-admission.js +60 -0
  51. package/dist/src/broker/authority-restore.d.ts +2 -0
  52. package/dist/src/broker/authority-restore.js +35 -1
  53. package/dist/src/broker/command-wait-restore.d.ts +31 -0
  54. package/dist/src/broker/command-wait-restore.js +86 -0
  55. package/dist/src/broker/decision-restore.d.ts +1 -1
  56. package/dist/src/broker/decision-restore.js +1 -0
  57. package/dist/src/broker/effect-upgrade.d.ts +2 -0
  58. package/dist/src/broker/effect-upgrade.js +8 -2
  59. package/dist/src/cli/arguments.d.ts +13 -0
  60. package/dist/src/cli/arguments.js +42 -3
  61. package/dist/src/cli/chat-stores.d.ts +2 -0
  62. package/dist/src/cli/chat-stores.js +113 -0
  63. package/dist/src/cli/client.d.ts +4 -1
  64. package/dist/src/cli/client.js +9 -3
  65. package/dist/src/cli/command-requests.d.ts +17 -0
  66. package/dist/src/cli/command-requests.js +43 -0
  67. package/dist/src/cli/command-waits.d.ts +9 -0
  68. package/dist/src/cli/command-waits.js +51 -0
  69. package/dist/src/cli/commands.js +14 -41
  70. package/dist/src/cli/config-file.d.ts +2 -2
  71. package/dist/src/cli/config-file.js +4 -2
  72. package/dist/src/cli/doctor-workflows.d.ts +5 -2
  73. package/dist/src/cli/doctor-workflows.js +12 -7
  74. package/dist/src/cli/doctor.js +6 -9
  75. package/dist/src/cli/harness-probes.d.ts +2 -0
  76. package/dist/src/cli/harness-probes.js +1 -1
  77. package/dist/src/cli/harness-processes.d.ts +6 -0
  78. package/dist/src/cli/harness-processes.js +36 -0
  79. package/dist/src/cli/init-command.d.ts +9 -0
  80. package/dist/src/cli/init-command.js +52 -0
  81. package/dist/src/cli/init-prompt-command.d.ts +10 -0
  82. package/dist/src/cli/init-prompt-command.js +145 -0
  83. package/dist/src/cli/init-prompt.d.ts +35 -0
  84. package/dist/src/cli/init-prompt.js +74 -0
  85. package/dist/src/cli/init-selection.d.ts +13 -0
  86. package/dist/src/cli/init-selection.js +75 -0
  87. package/dist/src/cli/main.d.ts +2 -0
  88. package/dist/src/cli/main.js +37 -7
  89. package/dist/src/cli/mcp-server.d.ts +1 -0
  90. package/dist/src/cli/mcp-server.js +156 -0
  91. package/dist/src/cli/mcp-tools.d.ts +15 -0
  92. package/dist/src/cli/mcp-tools.js +80 -0
  93. package/dist/src/cli/render.d.ts +1 -1
  94. package/dist/src/cli/render.js +17 -30
  95. package/dist/src/cli/report-ci-jobs.d.ts +23 -0
  96. package/dist/src/cli/report-ci-jobs.js +103 -0
  97. package/dist/src/cli/report-ci-usage.d.ts +9 -0
  98. package/dist/src/cli/report-ci-usage.js +185 -0
  99. package/dist/src/cli/report-ci.d.ts +13 -0
  100. package/dist/src/cli/report-ci.js +74 -0
  101. package/dist/src/cli/report-closures.d.ts +6 -0
  102. package/dist/src/cli/report-closures.js +97 -0
  103. package/dist/src/cli/report-flow.d.ts +7 -0
  104. package/dist/src/cli/report-flow.js +122 -0
  105. package/dist/src/cli/report-github-reader.d.ts +29 -0
  106. package/dist/src/cli/report-github-reader.js +157 -0
  107. package/dist/src/cli/report-github.d.ts +15 -8
  108. package/dist/src/cli/report-github.js +131 -150
  109. package/dist/src/cli/report-operator.d.ts +3 -0
  110. package/dist/src/cli/report-operator.js +40 -0
  111. package/dist/src/cli/report-ready.d.ts +3 -0
  112. package/dist/src/cli/report-ready.js +96 -0
  113. package/dist/src/cli/report-text.d.ts +9 -0
  114. package/dist/src/cli/report-text.js +33 -0
  115. package/dist/src/cli/report.d.ts +1 -0
  116. package/dist/src/cli/report.js +104 -27
  117. package/dist/src/cli/runtime-arguments.d.ts +2 -1
  118. package/dist/src/cli/runtime-arguments.js +7 -2
  119. package/dist/src/cli/schedule-arguments.d.ts +14 -0
  120. package/dist/src/cli/schedule-arguments.js +26 -0
  121. package/dist/src/cli/schedule-render.d.ts +22 -0
  122. package/dist/src/cli/schedule-render.js +73 -0
  123. package/dist/src/cli/terminal-text.d.ts +3 -0
  124. package/dist/src/cli/terminal-text.js +28 -0
  125. package/dist/src/cli/usage-render.d.ts +1 -0
  126. package/dist/src/cli/usage-render.js +28 -1
  127. package/dist/src/cli/usage.d.ts +1 -1
  128. package/dist/src/cli/usage.js +50 -7
  129. package/dist/src/cli/watch-actions.js +2 -2
  130. package/dist/src/cli/watch-board-view.js +19 -2
  131. package/dist/src/cli/watch-board.d.ts +4 -2
  132. package/dist/src/cli/watch-board.js +53 -43
  133. package/dist/src/cli/watch-card-forms.d.ts +1 -1
  134. package/dist/src/cli/watch-card-forms.js +11 -10
  135. package/dist/src/cli/watch-client.d.ts +1 -1
  136. package/dist/src/cli/watch-client.js +2 -11
  137. package/dist/src/cli/watch-header-view.d.ts +0 -5
  138. package/dist/src/cli/watch-header-view.js +8 -20
  139. package/dist/src/cli/watch-model.d.ts +4 -1
  140. package/dist/src/cli/watch-model.js +17 -11
  141. package/dist/src/cli/watch-page.js +12 -14
  142. package/dist/src/cli/watch-phases.d.ts +12 -3
  143. package/dist/src/cli/watch-phases.js +68 -11
  144. package/dist/src/cli/watch-pr-board.js +1 -1
  145. package/dist/src/cli/watch-pr-command.d.ts +1 -0
  146. package/dist/src/cli/watch-pull-request.js +18 -8
  147. package/dist/src/cli/watch-reads.d.ts +2 -0
  148. package/dist/src/cli/watch-reads.js +17 -16
  149. package/dist/src/cli/watch-render.d.ts +14 -0
  150. package/dist/src/cli/watch-run-input.d.ts +0 -1
  151. package/dist/src/cli/watch-run-input.js +0 -13
  152. package/dist/src/cli/watch-server.js +6 -6
  153. package/dist/src/cli/watch-view.d.ts +0 -3
  154. package/dist/src/cli/watch-view.js +13 -13
  155. package/dist/src/cli.js +59 -5
  156. package/dist/src/command-wait.d.ts +4 -0
  157. package/dist/src/command-wait.js +45 -0
  158. package/dist/src/configuration-change.d.ts +7 -0
  159. package/dist/src/configuration-change.js +14 -0
  160. package/dist/src/configuration-schema.d.ts +9 -0
  161. package/dist/src/configuration-schema.js +6 -2
  162. package/dist/src/daemon/attachment-file.d.ts +6 -0
  163. package/dist/src/daemon/attachment-file.js +86 -0
  164. package/dist/src/daemon/attachments.d.ts +14 -0
  165. package/dist/src/daemon/attachments.js +17 -0
  166. package/dist/src/daemon/claude-recovery.d.ts +50 -0
  167. package/dist/src/daemon/claude-recovery.js +204 -0
  168. package/dist/src/daemon/claude-stream.d.ts +27 -0
  169. package/dist/src/daemon/claude-stream.js +63 -0
  170. package/dist/src/daemon/claude-turn.d.ts +11 -25
  171. package/dist/src/daemon/claude-turn.js +64 -81
  172. package/dist/src/daemon/claude-worker.d.ts +2 -1
  173. package/dist/src/daemon/claude-worker.js +124 -122
  174. package/dist/src/daemon/daemon-adapters.d.ts +2 -0
  175. package/dist/src/daemon/daemon-adapters.js +26 -2
  176. package/dist/src/daemon/daemon-loops.d.ts +3 -1
  177. package/dist/src/daemon/daemon-loops.js +3 -1
  178. package/dist/src/daemon/daemon.js +14 -6
  179. package/dist/src/daemon/github-attach.d.ts +2 -0
  180. package/dist/src/daemon/github-attach.js +149 -0
  181. package/dist/src/daemon/github-ci-filters.d.ts +6 -0
  182. package/dist/src/daemon/github-ci-filters.js +138 -0
  183. package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
  184. package/dist/src/daemon/github-ci-workflows.js +148 -0
  185. package/dist/src/daemon/github-ci.js +22 -4
  186. package/dist/src/daemon/github-issue-methods.d.ts +2 -0
  187. package/dist/src/daemon/github-issue-methods.js +37 -2
  188. package/dist/src/daemon/github-merge-call.d.ts +2 -1
  189. package/dist/src/daemon/github-merge-call.js +10 -3
  190. package/dist/src/daemon/github-merge.js +52 -24
  191. package/dist/src/daemon/github-methods.js +12 -2
  192. package/dist/src/daemon/github-operation.d.ts +4 -0
  193. package/dist/src/daemon/github-operation.js +6 -0
  194. package/dist/src/daemon/github-worker.d.ts +4 -0
  195. package/dist/src/daemon/github-worker.js +6 -0
  196. package/dist/src/daemon/issue-queue.d.ts +1 -1
  197. package/dist/src/daemon/issue-queue.js +16 -11
  198. package/dist/src/daemon/notify-events.d.ts +6 -0
  199. package/dist/src/daemon/notify-events.js +84 -0
  200. package/dist/src/daemon/notify-journal.js +1 -1
  201. package/dist/src/daemon/notify-message.d.ts +4 -1
  202. package/dist/src/daemon/notify-message.js +36 -0
  203. package/dist/src/daemon/notify.d.ts +1 -1
  204. package/dist/src/daemon/notify.js +5 -77
  205. package/dist/src/daemon/operation-journal.d.ts +1 -0
  206. package/dist/src/daemon/queue-status.d.ts +9 -3
  207. package/dist/src/daemon/queue-status.js +17 -4
  208. package/dist/src/daemon/resume-index-lock.d.ts +13 -0
  209. package/dist/src/daemon/resume-index-lock.js +160 -0
  210. package/dist/src/daemon/resume-worktree.d.ts +7 -0
  211. package/dist/src/daemon/resume-worktree.js +29 -0
  212. package/dist/src/daemon/retrying-turn.d.ts +2 -12
  213. package/dist/src/daemon/retrying-turn.js +98 -172
  214. package/dist/src/daemon/schedule-control.d.ts +26 -0
  215. package/dist/src/daemon/schedule-control.js +110 -0
  216. package/dist/src/daemon/schedule-journal.d.ts +2 -15
  217. package/dist/src/daemon/schedule-journal.js +67 -4
  218. package/dist/src/daemon/ticket-registration.d.ts +2 -7
  219. package/dist/src/daemon/ticket-registration.js +15 -81
  220. package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
  221. package/dist/src/daemon/turn-attempt-journal.js +136 -0
  222. package/dist/src/daemon/turn-attempts.d.ts +47 -0
  223. package/dist/src/daemon/turn-attempts.js +166 -0
  224. package/dist/src/daemon/turn-report.d.ts +8 -1
  225. package/dist/src/daemon/turn-report.js +39 -0
  226. package/dist/src/daemon/work-tree.d.ts +9 -0
  227. package/dist/src/daemon/work-tree.js +20 -0
  228. package/dist/src/daemon/worker-profile.d.ts +8 -0
  229. package/dist/src/daemon/worker-profile.js +40 -0
  230. package/dist/src/daemon/workflow-schedules.d.ts +3 -0
  231. package/dist/src/daemon/workflow-schedules.js +98 -45
  232. package/dist/src/daemon/worktree-processes.d.ts +9 -0
  233. package/dist/src/daemon/worktree-processes.js +151 -0
  234. package/dist/src/doctor-report.d.ts +3 -5
  235. package/dist/src/doctor-report.js +6 -13
  236. package/dist/src/harness-start.d.ts +15 -0
  237. package/dist/src/harness-start.js +37 -0
  238. package/dist/src/host/command-wait.d.ts +38 -0
  239. package/dist/src/host/command-wait.js +115 -0
  240. package/dist/src/host/start-delivery.d.ts +5 -7
  241. package/dist/src/host/start-delivery.js +3 -15
  242. package/dist/src/host/step-bridge-host.d.ts +2 -0
  243. package/dist/src/host/step-bridge-host.js +21 -0
  244. package/dist/src/operation-identity.d.ts +1 -0
  245. package/dist/src/operation-identity.js +4 -0
  246. package/dist/src/private-config.schema.json +40 -0
  247. package/dist/src/project-config.schema.json +40 -0
  248. package/dist/src/project-settings.d.ts +2 -2
  249. package/dist/src/project-settings.js +3 -1
  250. package/dist/src/queue-spend.d.ts +4 -0
  251. package/dist/src/queue-spend.js +21 -0
  252. package/dist/src/relay/relay-service.d.ts +3 -0
  253. package/dist/src/relay/relay-service.js +5 -3
  254. package/dist/src/report-ci.d.ts +164 -0
  255. package/dist/src/report-ci.js +32 -0
  256. package/dist/src/report-effects.d.ts +15 -0
  257. package/dist/src/report-effects.js +212 -0
  258. package/dist/src/report-flow-types.d.ts +38 -0
  259. package/dist/src/report-flow-types.js +7 -0
  260. package/dist/src/report-flow.d.ts +43 -0
  261. package/dist/src/report-flow.js +193 -0
  262. package/dist/src/report-operator.d.ts +67 -0
  263. package/dist/src/report-operator.js +25 -0
  264. package/dist/src/report-quality.d.ts +221 -0
  265. package/dist/src/report-quality.js +94 -0
  266. package/dist/src/report-ready.d.ts +23 -0
  267. package/dist/src/report-ready.js +117 -0
  268. package/dist/src/report-statistics.d.ts +2 -1
  269. package/dist/src/report-statistics.js +40 -4
  270. package/dist/src/report.d.ts +588 -47
  271. package/dist/src/report.js +156 -41
  272. package/dist/src/schedule-progress.d.ts +33 -0
  273. package/dist/src/schedule-progress.js +45 -0
  274. package/dist/src/service/active-tickets.js +6 -6
  275. package/dist/src/service/command-waits.d.ts +34 -0
  276. package/dist/src/service/command-waits.js +86 -0
  277. package/dist/src/service/expiry.js +2 -0
  278. package/dist/src/service/gateway.js +3 -1
  279. package/dist/src/service/queue-spend.d.ts +6 -0
  280. package/dist/src/service/queue-spend.js +68 -0
  281. package/dist/src/service/replies.d.ts +8 -1
  282. package/dist/src/service/replies.js +11 -0
  283. package/dist/src/service/run-handlers.js +22 -2
  284. package/dist/src/service/run-metadata.d.ts +15 -1
  285. package/dist/src/service/run-metadata.js +93 -8
  286. package/dist/src/service/service.d.ts +4 -0
  287. package/dist/src/service/service.js +8 -8
  288. package/dist/src/service/submission-handler.js +18 -4
  289. package/dist/src/service/worker-port.js +9 -1
  290. package/dist/src/service/worker-totals.d.ts +2 -0
  291. package/dist/src/service/worker-totals.js +1 -1
  292. package/dist/src/step-bridge.d.ts +20 -0
  293. package/dist/src/steps/command-wait.d.ts +12 -0
  294. package/dist/src/steps/command-wait.js +26 -0
  295. package/dist/src/steps/open-decision-wait.d.ts +2 -0
  296. package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
  297. package/dist/src/steps/review-by-person.js +4 -1
  298. package/dist/src/steps/wait-for-command.d.ts +3 -0
  299. package/dist/src/steps/wait-for-command.js +17 -0
  300. package/dist/src/steps/wait-for-decision.js +1 -1
  301. package/dist/src/storage/command-wait-rows.d.ts +30 -0
  302. package/dist/src/storage/command-wait-rows.js +96 -0
  303. package/dist/src/storage/decision-snapshots.d.ts +8 -1
  304. package/dist/src/storage/decision-snapshots.js +15 -1
  305. package/dist/src/storage/domain-changes.d.ts +2 -0
  306. package/dist/src/storage/domain-changes.js +3 -0
  307. package/dist/src/storage/domain-schema.d.ts +13 -1
  308. package/dist/src/storage/domain-schema.js +31 -4
  309. package/dist/src/storage/effect-schema.d.ts +1 -0
  310. package/dist/src/storage/effect-schema.js +5 -0
  311. package/dist/src/testing-requests.d.ts +15 -0
  312. package/dist/src/testing-requests.js +93 -0
  313. package/dist/src/testing.d.ts +4 -10
  314. package/dist/src/testing.js +33 -86
  315. package/dist/src/worker-usage.d.ts +1 -0
  316. package/dist/src/worker-usage.js +3 -0
  317. package/dist/src/workflow-candidate.d.ts +1 -0
  318. package/dist/src/workflow-candidate.js +12 -1
  319. package/dist/src/workflow-contracts.d.ts +1 -0
  320. package/dist/src/workflow-contracts.js +9 -2
  321. package/dist/src/workflow-discovery.d.ts +2 -13
  322. package/dist/src/workflow-discovery.js +1 -13
  323. package/dist/src/workflow-refusals.js +0 -1
  324. package/dist/src/workflows.d.ts +1 -1
  325. package/dist/src/workflows.js +1 -1
  326. package/dist/tools/red-green-command.d.ts +1 -0
  327. package/dist/tools/red-green-command.js +174 -0
  328. package/dist/tools/red-green-process.d.ts +10 -0
  329. package/dist/tools/red-green-process.js +59 -0
  330. package/dist/tools/self-host-processes.d.ts +2 -0
  331. package/dist/tools/self-host-processes.js +32 -13
  332. package/dist/tools/self-host-project.js +13 -78
  333. package/dist/tools/self-host-runtime.js +1 -1
  334. package/dist/tools/self-host.js +42 -10
  335. package/dist/tools/template-command.d.ts +1 -0
  336. package/dist/tools/template-command.js +160 -0
  337. package/dist/tools/template-copy.d.ts +11 -0
  338. package/dist/tools/template-copy.js +130 -0
  339. package/dist/tools/template-files.d.ts +17 -0
  340. package/dist/tools/template-files.js +74 -0
  341. package/dist/tools/workflow-bundles.js +1 -0
  342. package/dist/tools/workflow-candidate-counts.js +2 -2
  343. package/dist/tools/workflow-candidate-shape.d.ts +3 -0
  344. package/dist/tools/workflow-candidate-shape.js +90 -0
  345. package/dist/tools/workflow-candidate-source.js +15 -1
  346. package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
  347. package/dist/tools/workflow-candidate-syntax.js +24 -94
  348. package/dist/tools/workflow-command.js +1 -2
  349. package/dist/tools/workflow-folders.d.ts +2 -3
  350. package/dist/tools/workflow-folders.js +1 -1
  351. package/package.json +16 -8
  352. package/templates/develop/README.md +12 -0
  353. package/templates/develop/develop/flow-tests.ts +37 -0
  354. package/templates/develop/develop/pull.ts +5 -1
  355. package/templates/develop/develop/refusal-tests.ts +77 -0
  356. package/templates/develop/develop/turn.ts +2 -1
  357. package/templates/idea-to-issue/README.md +27 -0
  358. package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
  359. package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
  360. package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
  361. package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
  362. package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
  363. package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
  364. package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
  365. package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
  366. package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
  367. package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
  368. package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
  369. package/templates/idea-to-issue/idea-to-issue.ts +49 -0
  370. package/templates/idea-to-issue/template.json +81 -0
  371. package/templates/review-day/README.md +97 -0
  372. package/templates/review-day/review-day/critique.ts +58 -0
  373. package/templates/review-day/review-day/decision.ts +29 -0
  374. package/templates/review-day/review-day/facts.ts +69 -0
  375. package/templates/review-day/review-day/label.ts +29 -0
  376. package/templates/review-day/review-day/next.ts +28 -0
  377. package/templates/review-day/review-day/post.ts +27 -0
  378. package/templates/review-day/review-day/report.ts +98 -0
  379. package/templates/review-day/review-day/rules.ts +12 -0
  380. package/templates/review-day/review-day/scenarios.ts +76 -0
  381. package/templates/review-day/review-day/turn.ts +73 -0
  382. package/templates/review-day/review-day.declaration.json +16 -0
  383. package/templates/review-day/review-day.test.ts +362 -0
  384. package/templates/review-day/review-day.ts +37 -0
  385. package/templates/review-day/template.json +56 -0
  386. package/dist/src/cli/watch-start-view.d.ts +0 -18
  387. package/dist/src/cli/watch-start-view.js +0 -77
  388. package/dist/src/steps/decision-gate.d.ts +0 -3
  389. package/dist/workflows/develop-prd.d.ts +0 -7
  390. package/dist/workflows/develop-prd.js +0 -165
  391. package/dist/workflows/develop-ticket.d.ts +0 -9
  392. package/dist/workflows/develop-ticket.js +0 -207
  393. package/dist/workflows/issue-labels.d.ts +0 -16
  394. package/dist/workflows/issue-labels.js +0 -70
  395. package/dist/workflows/ticket-prompts.d.ts +0 -35
  396. package/dist/workflows/ticket-prompts.js +0 -147
@@ -0,0 +1,151 @@
1
+ import { execFile } from "node:child_process";
2
+ import { readdir, readlink, realpath } from "node:fs/promises";
3
+ import { resolve, sep } from "node:path";
4
+ import { setTimeout as delay } from "node:timers/promises";
5
+ import { promisify } from "node:util";
6
+ import { writeRecord } from "./operation-journal.js";
7
+ const execute = promisify(execFile);
8
+ async function output(command, arguments_) {
9
+ return (await execute(command, arguments_, {
10
+ encoding: "utf8",
11
+ timeout: 5000,
12
+ maxBuffer: 8 * 1024 * 1024,
13
+ })).stdout;
14
+ }
15
+ async function directories() {
16
+ if (process.platform === "linux") {
17
+ const entries = await readdir("/proc");
18
+ const links = await Promise.all(entries
19
+ .filter((entry) => /^\d+$/.test(entry))
20
+ .map(async (entry) => {
21
+ const directory = await readlink(`/proc/${entry}/cwd`).catch(() => undefined);
22
+ return [Number(entry), directory];
23
+ }));
24
+ return new Map(links.filter((entry) => entry[1] !== undefined));
25
+ }
26
+ const text = await output("lsof", ["-d", "cwd", "-Fpn", "-n", "-P"]);
27
+ const found = new Map();
28
+ let processId = 0;
29
+ for (const line of text.split("\n")) {
30
+ if (line.startsWith("p"))
31
+ processId = Number(line.slice(1));
32
+ if (line.startsWith("n"))
33
+ found.set(processId, line.slice(1));
34
+ }
35
+ return found;
36
+ }
37
+ async function processes() {
38
+ try {
39
+ const text = await output("ps", ["-axo", "pid=,pgid=,uid="]);
40
+ const entries = text
41
+ .trim()
42
+ .split("\n")
43
+ .map((line) => {
44
+ const [processId = 0, group = 0, user = -1] = line
45
+ .trim()
46
+ .split(/\s+/)
47
+ .map(Number);
48
+ return { processId, group, user };
49
+ });
50
+ const working = await directories();
51
+ return entries.map((entry) => {
52
+ const directory = working.get(entry.processId);
53
+ return { ...entry, ...(directory === undefined ? {} : { directory }) };
54
+ });
55
+ }
56
+ catch {
57
+ return undefined;
58
+ }
59
+ }
60
+ function inTree(entry, directory) {
61
+ if (entry.processId <= 1 ||
62
+ entry.processId === process.pid ||
63
+ entry.directory === undefined)
64
+ return false;
65
+ const root = resolve(directory);
66
+ return entry.directory === root || entry.directory.startsWith(root + sep);
67
+ }
68
+ export async function recordedProcessDirectory(processId) {
69
+ return (await processes())?.find((entry) => entry.processId === processId)
70
+ ?.directory;
71
+ }
72
+ function terminate(entries, request) {
73
+ const { directory, signal } = request;
74
+ const maySignal = (entry) => entry.user === process.getuid?.() && inTree(entry, directory);
75
+ const found = entries.filter(maySignal);
76
+ const groups = new Set();
77
+ for (const entry of found) {
78
+ const safeGroup = entry.group > 1 &&
79
+ entries.filter((other) => other.group === entry.group).every(maySignal);
80
+ const target = safeGroup ? -entry.group : entry.processId;
81
+ if (groups.has(target))
82
+ continue;
83
+ groups.add(target);
84
+ try {
85
+ process.kill(target, signal);
86
+ }
87
+ catch {
88
+ continue;
89
+ }
90
+ }
91
+ return found.map((entry) => entry.processId);
92
+ }
93
+ async function treeSnapshot(directory) {
94
+ const entries = await processes();
95
+ return entries?.some((entry) => inTree(entry, directory)) === false
96
+ ? processes()
97
+ : entries;
98
+ }
99
+ async function waitForTree(request, deadline) {
100
+ while (!request.signal.aborted) {
101
+ const entries = await treeSnapshot(request.directory);
102
+ if (entries === undefined ||
103
+ !entries.some((entry) => inTree(entry, request.directory)) ||
104
+ performance.now() >= deadline)
105
+ return entries;
106
+ await delay(Math.min(250, Math.max(0, deadline - performance.now())));
107
+ }
108
+ return undefined;
109
+ }
110
+ export async function stopTreeProcesses(request) {
111
+ const directory = await realpath(request.directory).catch(() => undefined);
112
+ return directory === undefined
113
+ ? false
114
+ : stopCanonicalTree({ ...request, directory });
115
+ }
116
+ async function stopCanonicalTree(request) {
117
+ const entries = await treeSnapshot(request.directory);
118
+ const aborted = () => request.signal.aborted;
119
+ if (entries === undefined || aborted())
120
+ return false;
121
+ const processIds = terminate(entries, {
122
+ directory: request.directory,
123
+ signal: "SIGTERM",
124
+ });
125
+ let remaining = processIds.length === 0
126
+ ? entries
127
+ : await waitForTree(request, performance.now() + (request.stopMilliseconds ?? 15_000));
128
+ if (remaining === undefined || aborted())
129
+ return recordCleanup(request, { processIds, remaining });
130
+ const killed = terminate(remaining, {
131
+ directory: request.directory,
132
+ signal: "SIGKILL",
133
+ });
134
+ processIds.push(...killed);
135
+ if (killed.length > 0)
136
+ remaining = await waitForTree(request, performance.now() + 1000);
137
+ return recordCleanup(request, { processIds, remaining });
138
+ }
139
+ async function recordCleanup(request, cleanup) {
140
+ const remainingProcessIds = cleanup.remaining
141
+ ?.filter((entry) => inTree(entry, request.directory))
142
+ .map((entry) => entry.processId);
143
+ await writeRecord(request.folder, {
144
+ name: "resume-processes.json",
145
+ value: {
146
+ processIds: [...new Set(cleanup.processIds)],
147
+ remainingProcessIds,
148
+ },
149
+ });
150
+ return !request.signal.aborted && remainingProcessIds?.length === 0;
151
+ }
@@ -1,5 +1,5 @@
1
1
  import { type SubmissionContract } from "./submission.ts";
2
- export declare const doctorCodes: readonly ["git-repository", "node-version", "harnesses", "default-harness", "gh-login", "github-origin", "greptile-review", "settings-files", "runtime-directory", "service", "ticket-command", "next-command", "check-command", "queue-interval", "private-texts"];
2
+ export declare const doctorCodes: readonly ["git-repository", "node-version", "harnesses", "default-harness", "gh-login", "github-origin", "greptile-review", "settings-files", "no-workflow", "runtime-directory", "service", "ticket-command", "next-command", "check-command", "queue-interval", "private-texts"];
3
3
  export type DoctorCode = (typeof doctorCodes)[number];
4
4
  export interface DoctorObservation {
5
5
  readonly result: "ok" | "fail" | "skip";
@@ -14,11 +14,9 @@ export declare const doctorFixes: Readonly<Record<DoctorCode, string>>;
14
14
  export declare function doctorExitCode(checks: readonly DoctorCheck[]): number;
15
15
  export interface DoctorWorkflow {
16
16
  readonly queue?: boolean;
17
- readonly scope: "bundled" | "project" | "user";
17
+ readonly scope: "project" | "user";
18
18
  readonly workflowId: string;
19
19
  readonly capabilities: readonly string[];
20
20
  readonly input?: SubmissionContract;
21
21
  }
22
- export declare function requiredDoctorCodes(workflows: readonly DoctorWorkflow[], options: {
23
- readonly queueSeconds: string | undefined;
24
- }): readonly DoctorCode[];
22
+ export declare function requiredDoctorCodes(workflows: readonly DoctorWorkflow[]): readonly DoctorCode[];
@@ -8,6 +8,7 @@ export const doctorCodes = [
8
8
  "github-origin",
9
9
  "greptile-review",
10
10
  "settings-files",
11
+ "no-workflow",
11
12
  "runtime-directory",
12
13
  "service",
13
14
  "ticket-command",
@@ -25,6 +26,7 @@ export const doctorFixes = {
25
26
  "github-origin": "Set a GitHub origin: git remote add origin git@github.com:OWNER/REPO.git || git remote set-url origin git@github.com:OWNER/REPO.git",
26
27
  "greptile-review": "Install the Greptile app at https://github.com/apps/greptile, then open a first pull request: gh pr create",
27
28
  "settings-files": "Fix the project JSON: ${EDITOR:-vi} .cloving/config.json; for private JSON, edit <config>/cloving/projects/<repository-id>.json",
29
+ "no-workflow": "cloving init",
28
30
  "runtime-directory": 'Select a private writable runtime: CLOVING_RUNTIME_DIR="$HOME/.local/state/cloving/doctor/run" cloving doctor',
29
31
  service: "Start the service: cloving start",
30
32
  "ticket-command": "Set tickets.command to an executable list: ${EDITOR:-vi} .cloving/config.json",
@@ -38,33 +40,24 @@ export function doctorExitCode(checks) {
38
40
  ? 1
39
41
  : 0;
40
42
  }
41
- export function requiredDoctorCodes(workflows, options) {
43
+ export function requiredDoctorCodes(workflows) {
42
44
  const codes = new Set([
43
45
  "git-repository",
44
46
  "node-version",
45
47
  "default-harness",
46
48
  "settings-files",
49
+ "no-workflow",
47
50
  "runtime-directory",
48
51
  ]);
49
52
  if (workflows.some((workflow) => workflow.capabilities.includes("github"))) {
50
53
  codes.add("gh-login");
51
54
  codes.add("github-origin");
52
55
  }
53
- const bundled = workflows
54
- .filter((workflow) => workflow.scope === "bundled")
55
- .map((workflow) => workflow.workflowId);
56
- const issue = bundled.includes("develop-issue");
57
- if (issue)
58
- codes.add("check-command");
59
- if (workflows.some((workflow) => workflow.queue === true) ||
60
- (issue && options.queueSeconds !== undefined)) {
56
+ if (workflows.some((workflow) => workflow.queue === true)) {
61
57
  codes.add("next-command");
62
58
  codes.add("queue-interval");
63
59
  }
64
- if (workflows.some((workflow) => hasTicketField(workflow.input)) ||
65
- bundled.some((name) => ["develop-ticket", "develop-issue"].includes(name)))
60
+ if (workflows.some((workflow) => hasTicketField(workflow.input)))
66
61
  codes.add("ticket-command");
67
- if (bundled.includes("develop-prd"))
68
- codes.add("private-texts");
69
62
  return [...codes];
70
63
  }
@@ -0,0 +1,15 @@
1
+ import { type ShellMode } from "./agent-harness-shell.ts";
2
+ import type { HarnessSelection } from "./configuration-change.ts";
3
+ export interface HarnessStartRequest {
4
+ readonly executable: string;
5
+ readonly arguments: readonly string[];
6
+ readonly directory: string;
7
+ readonly environment: Readonly<Record<string, string | undefined>>;
8
+ }
9
+ export declare function harnessStartRequest(entry: HarnessSelection & {
10
+ readonly shellMode?: ShellMode;
11
+ }, context: {
12
+ readonly repository: string;
13
+ readonly environment: Readonly<NodeJS.ProcessEnv>;
14
+ readonly message: string;
15
+ }): HarnessStartRequest;
@@ -0,0 +1,37 @@
1
+ import { shellArguments, shellRunScript, } from "./agent-harness-shell.js";
2
+ const shellStartScript = `
3
+ set +m
4
+ kind=
5
+ if [ -n "\${ZSH_VERSION-}" ]; then
6
+ kind=$(builtin whence -w -- "$1" 2>/dev/null) || kind=
7
+ kind="\${kind##*: }"
8
+ elif [ -n "\${BASH_VERSION-}" ]; then
9
+ kind=$(builtin type -t -- "$1" 2>/dev/null) || kind=
10
+ fi
11
+ case "$kind" in
12
+ function|alias) ;;
13
+ *) printf '%s\\n' 'Open your agent in this repository and tell it: run \`cloving init-prompt\`.' >&2; exit 1 ;;
14
+ esac
15
+ ${shellRunScript}
16
+ `;
17
+ export function harnessStartRequest(entry, context) {
18
+ const argumentsList = entry.name === "opencode"
19
+ ? ["--prompt", context.message]
20
+ : [context.message];
21
+ const executable = entry.kind === "shell" ? (context.environment["SHELL"] ?? "") : entry.path;
22
+ const args = entry.kind === "shell"
23
+ ? [
24
+ ...shellArguments(entry.shellMode ?? "login"),
25
+ shellStartScript,
26
+ "cloving-init",
27
+ entry.path,
28
+ ...argumentsList,
29
+ ]
30
+ : argumentsList;
31
+ return {
32
+ executable,
33
+ arguments: args,
34
+ directory: context.repository,
35
+ environment: context.environment,
36
+ };
37
+ }
@@ -0,0 +1,38 @@
1
+ import type { CommandWaitState } from "../authority/command-waits.ts";
2
+ import type { CommandWaitRequest, CommandWaitProgress } from "../step-bridge.ts";
3
+ interface WaitName {
4
+ readonly runId: string;
5
+ readonly name: string;
6
+ }
7
+ interface WaitCall extends WaitName {
8
+ readonly commandId: string;
9
+ }
10
+ interface WaitReceipt {
11
+ readonly kind: string;
12
+ readonly reason?: string;
13
+ }
14
+ export interface CommandWaitPorts {
15
+ readonly open: (request: WaitCall & {
16
+ readonly input: string;
17
+ }) => Promise<WaitReceipt>;
18
+ readonly check: (request: WaitCall) => Promise<WaitReceipt>;
19
+ readonly read: (request: WaitName) => Promise<CommandWaitState | undefined>;
20
+ }
21
+ interface WaitHost {
22
+ readonly commandWait?: CommandWaitPorts;
23
+ readonly runStatus: (runId: string) => Promise<string | undefined>;
24
+ readonly subject: () => Promise<{
25
+ readonly runId: string;
26
+ readonly commandId: string;
27
+ } | undefined>;
28
+ readonly stopped: AbortSignal;
29
+ readonly pollMilliseconds: number;
30
+ readonly retryMilliseconds: number;
31
+ }
32
+ export declare function commandWaitBridge(host: WaitHost): {
33
+ openCommandWait: (request: CommandWaitRequest) => Promise<CommandWaitProgress>;
34
+ checkCommandWait: (request: {
35
+ readonly name: string;
36
+ }) => Promise<CommandWaitProgress>;
37
+ };
38
+ export {};
@@ -0,0 +1,115 @@
1
+ import { setTimeout as delay } from "node:timers/promises";
2
+ import { commandWaitValue, isCommandWaitRequest } from "../command-wait.js";
3
+ function progress(wait) {
4
+ if (wait === undefined)
5
+ return { kind: "refused", reason: "unknown-command-wait" };
6
+ if (wait.state === "waiting")
7
+ return waiting(wait);
8
+ if (wait.state === "timed-out")
9
+ return { kind: "timed-out", reason: "command-wait-timeout" };
10
+ if (wait.state !== "completed")
11
+ return { kind: "failed", reason: wait.reason ?? "command-wait-failed" };
12
+ const value = JSON.parse(wait.result ?? "null");
13
+ return commandWaitValue(value)
14
+ ? { kind: "ready", value }
15
+ : { kind: "failed", reason: "command-wait-invalid-output" };
16
+ }
17
+ function refused(receipt) {
18
+ if (["accepted", "duplicate"].includes(receipt.kind))
19
+ return undefined;
20
+ return {
21
+ kind: receipt.kind === "failed" ? "failed" : "refused",
22
+ reason: receipt.reason ?? receipt.kind,
23
+ };
24
+ }
25
+ async function requested(context, send) {
26
+ const { host, call, retryReasons = ["service-busy"] } = context;
27
+ for (;;) {
28
+ if (host.stopped.aborted)
29
+ await new Promise(() => undefined);
30
+ const receipt = await send();
31
+ if (receipt.kind !== "rejected" ||
32
+ !retryReasons.includes(receipt.reason ?? ""))
33
+ return receipt;
34
+ if (receipt.reason === "command-wait-run-not-running" &&
35
+ !["queued", "running", "waiting_gate", "paused"].includes((await host.runStatus(call.runId)) ?? ""))
36
+ return receipt;
37
+ await delay(host.retryMilliseconds, undefined, {
38
+ signal: host.stopped,
39
+ }).catch(() => undefined);
40
+ }
41
+ }
42
+ async function settled(context, request) {
43
+ const { host, port } = context;
44
+ for (;;) {
45
+ if (host.stopped.aborted)
46
+ await new Promise(() => undefined);
47
+ const wait = await port.read(request);
48
+ if (wait?.state !== "waiting" || wait.checkOperation === null)
49
+ return progress(wait);
50
+ await delay(host.pollMilliseconds, undefined, {
51
+ signal: host.stopped,
52
+ }).catch(() => undefined);
53
+ }
54
+ }
55
+ export function commandWaitBridge(host) {
56
+ return {
57
+ openCommandWait: async (request) => {
58
+ if (!isCommandWaitRequest(request))
59
+ return { kind: "refused", reason: "invalid-command-wait-request" };
60
+ const subject = await host.subject();
61
+ const port = host.commandWait;
62
+ if (subject === undefined || port === undefined)
63
+ return { kind: "unavailable", reason: "cloving-host-unavailable" };
64
+ const call = {
65
+ ...subject,
66
+ name: request.name,
67
+ input: JSON.stringify(request.input),
68
+ };
69
+ const receipt = await requested({
70
+ host,
71
+ call,
72
+ retryReasons: ["service-busy", "command-wait-run-not-running"],
73
+ }, () => port.open(call));
74
+ return (refused(receipt) ??
75
+ progress(await port.read({ ...subject, name: request.name })));
76
+ },
77
+ checkCommandWait: async (request) => {
78
+ const subject = await host.subject();
79
+ const port = host.commandWait;
80
+ if (subject === undefined || port === undefined)
81
+ return { kind: "unavailable", reason: "cloving-host-unavailable" };
82
+ const call = { ...subject, name: request.name };
83
+ const wait = await port.read(call);
84
+ if (wait?.state !== "waiting")
85
+ return progress(wait);
86
+ if (wait.checkOperation !== null)
87
+ return await settled({ host, port }, call);
88
+ if (wait.nextCheckAt !== null &&
89
+ Date.now() < Math.min(wait.nextCheckAt, wait.deadline))
90
+ return progress(wait);
91
+ const receipt = await requested({ host, call }, () => port.check(call));
92
+ return checkReply(receipt, wait) ?? (await settled({ host, port }, call));
93
+ },
94
+ };
95
+ }
96
+ function checkReply(receipt, wait) {
97
+ if (receipt.reason === "command-wait-timeout")
98
+ return { kind: "timed-out", reason: receipt.reason };
99
+ if (receipt.reason === "command-wait-run-not-running")
100
+ return waiting(wait, Date.now() + 1000);
101
+ if ([
102
+ "command-wait-check-in-flight",
103
+ "command-wait-check-not-due",
104
+ "command-wait-ended",
105
+ ].includes(receipt.reason ?? ""))
106
+ return undefined;
107
+ return refused(receipt);
108
+ }
109
+ function waiting(wait, nextCheckAt = wait.nextCheckAt ?? wait.deadline) {
110
+ return {
111
+ kind: "pending",
112
+ deadline: wait.deadline,
113
+ nextCheckAt,
114
+ };
115
+ }
@@ -1,11 +1,9 @@
1
1
  import { type TaggedRun } from "./world-runs.ts";
2
- export type WorkflowFunction = (input: unknown, continuation?: Continuation) => Promise<unknown>;
3
- export interface Continuation {
4
- readonly gateId: string;
5
- readonly decision: string;
6
- readonly answer: string | null;
7
- }
8
- export interface RunIntent extends Partial<Continuation> {
2
+ export type WorkflowFunction = (input: unknown) => Promise<unknown>;
3
+ export interface RunIntent {
4
+ readonly gateId?: string;
5
+ readonly decision?: string;
6
+ readonly answer?: string | null;
9
7
  readonly kind: string;
10
8
  readonly runId: string;
11
9
  readonly operationId: string;
@@ -17,27 +17,15 @@ async function reconciled(parts, intent) {
17
17
  evidence: found.map((run) => `world-run:${run.receipt}`).join(" "),
18
18
  };
19
19
  }
20
- async function continuation(parts, intent) {
21
- const { kind, gateId, decision, answer } = intent;
22
- if (kind === "start-run")
23
- return undefined;
24
- if (kind !== "continue-run" || gateId === undefined || decision === undefined)
25
- throw new Error(`unsupported-intent: ${kind}`);
26
- if (answer === undefined || answer === null)
27
- return { gateId, decision, answer: null };
28
- const text = await parts.document(answer);
29
- if (text === undefined)
30
- throw new Error(`answer-not-available: ${gateId}`);
31
- return { gateId, decision, answer: text };
32
- }
33
20
  async function delivered(parts, intent) {
34
- const continued = await continuation(parts, intent);
21
+ if (intent.kind !== "start-run")
22
+ throw new Error(`unsupported-intent: ${intent.kind}`);
35
23
  const workflow = await parts.workflow(intent);
36
24
  const input = await parts.input(intent.runId);
37
25
  if (workflow === undefined || input === undefined)
38
26
  throw new Error(`start-not-available: ${intent.runId}`);
39
27
  const argument = JSON.parse(input);
40
- const started = await start(workflow, [argument, continued], {
28
+ const started = await start(workflow, [argument], {
41
29
  attributes: {
42
30
  [runTag]: intent.runId,
43
31
  [operationTag]: intent.operationId,
@@ -1,3 +1,4 @@
1
+ import { type CommandWaitPorts } from "./command-wait.ts";
1
2
  import { type GateOpening, type GateReceipt, type WaitRegistration } from "./gate-bridge.ts";
2
3
  export type { GateOpening, GateReceipt, WaitRegistration, } from "./gate-bridge.ts";
3
4
  import { type RunWaitPorts } from "./run-wait.ts";
@@ -41,6 +42,7 @@ export interface BridgeTiming {
41
42
  }
42
43
  export declare const bridgeTiming: BridgeTiming;
43
44
  export interface BridgePorts {
45
+ readonly commandWait?: CommandWaitPorts;
44
46
  readonly decisionReceived?: (runId: string, gateId: string) => Promise<boolean>;
45
47
  readonly runWait?: RunWaitPorts;
46
48
  readonly call: () => StepCall;
@@ -1,3 +1,4 @@
1
+ import { commandWaitBridge } from "./command-wait.js";
1
2
  import { createHash } from "node:crypto";
2
3
  import { setTimeout as delay } from "node:timers/promises";
3
4
  import { getStepMetadata, getWorkflowMetadata } from "workflow";
@@ -155,9 +156,29 @@ async function gate(hold, request) {
155
156
  return { kind: "unavailable", reason: "unknown-world-run" };
156
157
  return await openBridgeGate(hold.ports, subject);
157
158
  }
159
+ function hostCommandWait(hold) {
160
+ return commandWaitBridge({
161
+ ...(hold.ports.commandWait === undefined
162
+ ? {}
163
+ : { commandWait: hold.ports.commandWait }),
164
+ stopped: hold.ports.stopped,
165
+ pollMilliseconds: hold.timing.pollMilliseconds,
166
+ retryMilliseconds: hold.timing.retryMilliseconds,
167
+ runStatus: async (runId) => (await hold.ports.state()).runs[runId]?.status,
168
+ subject: async () => {
169
+ const call = hold.ports.call();
170
+ const world = await located(hold, call.worldRunId);
171
+ if (world === undefined)
172
+ return undefined;
173
+ await inWork(hold, world.runId);
174
+ return { runId: world.runId, commandId: transportOf(call) };
175
+ },
176
+ });
177
+ }
158
178
  export function stepBridge(ports) {
159
179
  const hold = { ports, timing: ports.timing ?? bridgeTiming };
160
180
  return {
181
+ ...hostCommandWait(hold),
161
182
  effect: (request) => effect(hold, request),
162
183
  gate: (request) => gate(hold, request),
163
184
  waitForDecision: async (request) => {
@@ -5,3 +5,4 @@ export interface OperationScope {
5
5
  readonly operation: string;
6
6
  }
7
7
  export declare function operationScope(operationId: string): OperationScope | null;
8
+ export declare function operationPhase(operationId: string): string | null;
@@ -48,6 +48,10 @@ export function operationScope(operationId) {
48
48
  return null;
49
49
  return { run, operation };
50
50
  }
51
+ export function operationPhase(operationId) {
52
+ const [marker, , , phase] = parsedList(operationId);
53
+ return marker === "cloving-operation" && isComponent(phase) ? phase : null;
54
+ }
51
55
  function parsedList(text) {
52
56
  try {
53
57
  const value = JSON.parse(text);
@@ -19,6 +19,42 @@
19
19
  "type": "string",
20
20
  "pattern": "\\S"
21
21
  }
22
+ },
23
+ "redGreen": {
24
+ "type": "object",
25
+ "properties": {
26
+ "test": {
27
+ "type": "array",
28
+ "minItems": 1,
29
+ "items": {
30
+ "type": "string",
31
+ "pattern": "^[^\\u0000]+$"
32
+ }
33
+ },
34
+ "testFiles": {
35
+ "type": "array",
36
+ "items": {
37
+ "type": "string",
38
+ "pattern": "^[^\\u0000]+$"
39
+ }
40
+ },
41
+ "prepare": {
42
+ "type": "array",
43
+ "minItems": 1,
44
+ "items": {
45
+ "type": "string",
46
+ "pattern": "^[^\\u0000]+$"
47
+ }
48
+ },
49
+ "assertionPattern": {
50
+ "type": "string"
51
+ },
52
+ "skipPattern": {
53
+ "type": "string"
54
+ }
55
+ },
56
+ "required": ["test", "testFiles"],
57
+ "additionalProperties": false
22
58
  }
23
59
  },
24
60
  "additionalProperties": false
@@ -49,6 +85,10 @@
49
85
  "minimum": 10,
50
86
  "maximum": 3600
51
87
  },
88
+ "dailySpendLimitUsd": {
89
+ "type": "number",
90
+ "exclusiveMinimum": 0
91
+ },
52
92
  "lanes": {
53
93
  "type": "integer",
54
94
  "minimum": 1,
@@ -19,6 +19,42 @@
19
19
  "type": "string",
20
20
  "pattern": "\\S"
21
21
  }
22
+ },
23
+ "redGreen": {
24
+ "type": "object",
25
+ "properties": {
26
+ "test": {
27
+ "type": "array",
28
+ "minItems": 1,
29
+ "items": {
30
+ "type": "string",
31
+ "pattern": "^[^\\u0000]+$"
32
+ }
33
+ },
34
+ "testFiles": {
35
+ "type": "array",
36
+ "items": {
37
+ "type": "string",
38
+ "pattern": "^[^\\u0000]+$"
39
+ }
40
+ },
41
+ "prepare": {
42
+ "type": "array",
43
+ "minItems": 1,
44
+ "items": {
45
+ "type": "string",
46
+ "pattern": "^[^\\u0000]+$"
47
+ }
48
+ },
49
+ "assertionPattern": {
50
+ "type": "string"
51
+ },
52
+ "skipPattern": {
53
+ "type": "string"
54
+ }
55
+ },
56
+ "required": ["test", "testFiles"],
57
+ "additionalProperties": false
22
58
  }
23
59
  },
24
60
  "additionalProperties": false
@@ -49,6 +85,10 @@
49
85
  "minimum": 10,
50
86
  "maximum": 3600
51
87
  },
88
+ "dailySpendLimitUsd": {
89
+ "type": "number",
90
+ "exclusiveMinimum": 0
91
+ },
52
92
  "lanes": {
53
93
  "type": "integer",
54
94
  "minimum": 1,
@@ -1,8 +1,8 @@
1
- import { type Configuration } from "./configuration-schema.ts";
1
+ import { type Configuration, type RedGreenSettings } from "./configuration-schema.ts";
2
2
  import type { TurnProfiles } from "./turn-profile.ts";
3
3
  import type { TokenPrices } from "./token-prices.ts";
4
4
  export type SettingSource = "environment" | "private" | "project";
5
- export type SettingValue = string | number | readonly string[] | TurnProfiles | TokenPrices;
5
+ export type SettingValue = string | number | readonly string[] | TurnProfiles | TokenPrices | RedGreenSettings;
6
6
  export declare const settingVariables: Readonly<Record<string, string>>;
7
7
  export declare function absoluteWorkflowFolder(folder: string | undefined): string | undefined;
8
8
  export declare function configurationRoot(environment: Readonly<NodeJS.ProcessEnv>, home: string): string;