cloving 1.1.0 → 1.3.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 (568) hide show
  1. package/README.md +584 -144
  2. package/assets/watch-fonts/fira-code-OFL.md +93 -0
  3. package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
  4. package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
  5. package/assets/watch-fonts/heebo-OFL.md +93 -0
  6. package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
  7. package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
  8. package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
  9. package/assets/watch-fonts/manifest.json +112 -0
  10. package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
  11. package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  12. package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  13. package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
  14. package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  15. package/dist/src/agent-harness-shell.d.ts +12 -0
  16. package/dist/src/agent-harness-shell.js +90 -0
  17. package/dist/src/agent-harness-versions.d.ts +8 -0
  18. package/dist/src/agent-harness-versions.js +49 -0
  19. package/dist/src/agent-harnesses.d.ts +4 -0
  20. package/dist/src/agent-harnesses.js +13 -0
  21. package/dist/src/authority/commands.d.ts +2 -0
  22. package/dist/src/authority/commands.js +49 -8
  23. package/dist/src/authority/dispatch-decision.d.ts +1 -0
  24. package/dist/src/authority/dispatch-decision.js +7 -4
  25. package/dist/src/authority/events.js +2 -2
  26. package/dist/src/authority/gate-reduction.d.ts +1 -0
  27. package/dist/src/authority/gate-reduction.js +18 -3
  28. package/dist/src/authority/gates.d.ts +2 -1
  29. package/dist/src/authority/gates.js +5 -1
  30. package/dist/src/authority/handoff-chain.d.ts +24 -0
  31. package/dist/src/authority/handoff-chain.js +46 -0
  32. package/dist/src/authority/operations.js +1 -1
  33. package/dist/src/authority/reconciliation.d.ts +1 -0
  34. package/dist/src/authority/reconciliation.js +18 -11
  35. package/dist/src/authority/reduction.d.ts +1 -1
  36. package/dist/src/authority/reduction.js +6 -1
  37. package/dist/src/authority/status-input.d.ts +1 -1
  38. package/dist/src/authority/status.d.ts +1 -0
  39. package/dist/src/authority/status.js +27 -3
  40. package/dist/src/authority/transitions.d.ts +5 -5
  41. package/dist/src/authority/transitions.js +9 -0
  42. package/dist/src/broker/actor/authority-delivery.js +1 -0
  43. package/dist/src/broker/actor/authority-queries.d.ts +11 -1
  44. package/dist/src/broker/actor/authority-queries.js +67 -3
  45. package/dist/src/broker/actor/authority-receipts.js +11 -1
  46. package/dist/src/broker/actor/authority-session.js +2 -2
  47. package/dist/src/broker/actor/authority-settings.js +4 -0
  48. package/dist/src/broker/actor/delivery-intents.d.ts +3 -1
  49. package/dist/src/broker/actor/delivery-intents.js +4 -4
  50. package/dist/src/broker/actor/effect-delivery.js +13 -1
  51. package/dist/src/broker/actor/effect-queries.d.ts +1 -0
  52. package/dist/src/broker/actor/effect-queries.js +7 -0
  53. package/dist/src/broker/actor/pin-check.js +1 -1
  54. package/dist/src/broker/actor/stop-plan.js +1 -1
  55. package/dist/src/broker/actor/turn-state.js +1 -1
  56. package/dist/src/broker/authority-admission.js +26 -5
  57. package/dist/src/broker/authority-restore.js +1 -0
  58. package/dist/src/broker/decision-restore.js +4 -4
  59. package/dist/src/broker/socket-address.d.ts +3 -1
  60. package/dist/src/broker/socket-address.js +2 -2
  61. package/dist/src/cli/arguments.d.ts +11 -13
  62. package/dist/src/cli/arguments.js +37 -107
  63. package/dist/src/cli/command-effects.d.ts +7 -0
  64. package/dist/src/cli/command-effects.js +39 -0
  65. package/dist/src/cli/commands.js +11 -4
  66. package/dist/src/cli/config-arguments.d.ts +11 -0
  67. package/dist/src/cli/config-arguments.js +59 -0
  68. package/dist/src/cli/config-command.d.ts +2 -0
  69. package/dist/src/cli/config-command.js +105 -0
  70. package/dist/src/cli/config-file.d.ts +3 -0
  71. package/dist/src/cli/config-file.js +50 -0
  72. package/dist/src/cli/config-lock.d.ts +7 -0
  73. package/dist/src/cli/config-lock.js +61 -0
  74. package/dist/src/cli/config-notice.d.ts +5 -0
  75. package/dist/src/cli/config-notice.js +46 -0
  76. package/dist/src/cli/doctor-github.d.ts +9 -0
  77. package/dist/src/cli/doctor-github.js +138 -0
  78. package/dist/src/cli/doctor-harness.d.ts +13 -0
  79. package/dist/src/cli/doctor-harness.js +242 -0
  80. package/dist/src/cli/doctor-local.d.ts +18 -0
  81. package/dist/src/cli/doctor-local.js +77 -0
  82. package/dist/src/cli/doctor-runtime.d.ts +15 -0
  83. package/dist/src/cli/doctor-runtime.js +176 -0
  84. package/dist/src/cli/doctor-service.d.ts +1 -0
  85. package/dist/src/cli/doctor-service.js +11 -0
  86. package/dist/src/cli/doctor-workflows.d.ts +3 -0
  87. package/dist/src/cli/doctor-workflows.js +45 -0
  88. package/dist/src/cli/doctor.d.ts +15 -0
  89. package/dist/src/cli/doctor.js +190 -0
  90. package/dist/src/cli/github-ci-progress.d.ts +8 -0
  91. package/dist/src/cli/github-ci-progress.js +83 -0
  92. package/dist/src/cli/github-retry.d.ts +6 -0
  93. package/dist/src/cli/github-retry.js +47 -0
  94. package/dist/src/cli/harness-probes.d.ts +22 -0
  95. package/dist/src/cli/harness-probes.js +183 -0
  96. package/dist/src/cli/main.d.ts +7 -1
  97. package/dist/src/cli/main.js +39 -61
  98. package/dist/src/cli/phone-arguments.d.ts +14 -0
  99. package/dist/src/cli/phone-arguments.js +37 -0
  100. package/dist/src/cli/phone-client.d.ts +2 -0
  101. package/dist/src/cli/phone-client.js +32 -0
  102. package/dist/src/cli/phone-command.d.ts +13 -0
  103. package/dist/src/cli/phone-command.js +101 -0
  104. package/dist/src/cli/probe-command.d.ts +36 -0
  105. package/dist/src/cli/probe-command.js +59 -0
  106. package/dist/src/cli/project-settings.d.ts +4 -0
  107. package/dist/src/cli/project-settings.js +33 -0
  108. package/dist/src/cli/render.d.ts +3 -1
  109. package/dist/src/cli/render.js +102 -39
  110. package/dist/src/cli/report-github.d.ts +18 -0
  111. package/dist/src/cli/report-github.js +200 -0
  112. package/dist/src/cli/report.d.ts +17 -0
  113. package/dist/src/cli/report.js +192 -0
  114. package/dist/src/cli/repository-arguments.d.ts +5 -0
  115. package/dist/src/cli/repository-arguments.js +34 -0
  116. package/dist/src/cli/runtime-arguments.d.ts +4 -0
  117. package/dist/src/cli/runtime-arguments.js +15 -0
  118. package/dist/src/cli/runtime-directory.d.ts +6 -2
  119. package/dist/src/cli/runtime-directory.js +72 -14
  120. package/dist/src/cli/toolchain.d.ts +2 -0
  121. package/dist/src/cli/toolchain.js +22 -2
  122. package/dist/src/cli/usage-render.d.ts +5 -0
  123. package/dist/src/cli/usage-render.js +40 -1
  124. package/dist/src/cli/usage.d.ts +3 -3
  125. package/dist/src/cli/usage.js +74 -45
  126. package/dist/src/cli/watch-actions.d.ts +2 -0
  127. package/dist/src/cli/watch-actions.js +4 -4
  128. package/dist/src/cli/watch-board-view.d.ts +12 -1
  129. package/dist/src/cli/watch-board-view.js +64 -12
  130. package/dist/src/cli/watch-board.d.ts +7 -1
  131. package/dist/src/cli/watch-board.js +61 -16
  132. package/dist/src/cli/watch-card-forms.js +2 -2
  133. package/dist/src/cli/watch-client.d.ts +1 -1
  134. package/dist/src/cli/watch-client.js +12 -3
  135. package/dist/src/cli/watch-header-view.d.ts +27 -0
  136. package/dist/src/cli/watch-header-view.js +116 -0
  137. package/dist/src/cli/watch-model.d.ts +10 -4
  138. package/dist/src/cli/watch-model.js +49 -59
  139. package/dist/src/cli/watch-page.js +67 -14
  140. package/dist/src/cli/watch-phases.js +3 -3
  141. package/dist/src/cli/watch-phone-client.d.ts +1 -0
  142. package/dist/src/cli/watch-phone-client.js +84 -0
  143. package/dist/src/cli/watch-phone-view.d.ts +56 -0
  144. package/dist/src/cli/watch-phone-view.js +113 -0
  145. package/dist/src/cli/watch-phone.d.ts +5 -0
  146. package/dist/src/cli/watch-phone.js +53 -0
  147. package/dist/src/cli/watch-pr-command.d.ts +5 -2
  148. package/dist/src/cli/watch-pr-command.js +41 -4
  149. package/dist/src/cli/watch-pr-identity.d.ts +14 -2
  150. package/dist/src/cli/watch-pr-identity.js +25 -0
  151. package/dist/src/cli/watch-pr-observer.d.ts +1 -0
  152. package/dist/src/cli/watch-pr-observer.js +48 -6
  153. package/dist/src/cli/watch-pull-request.d.ts +12 -0
  154. package/dist/src/cli/watch-pull-request.js +134 -0
  155. package/dist/src/cli/watch-reads.d.ts +7 -1
  156. package/dist/src/cli/watch-reads.js +42 -20
  157. package/dist/src/cli/watch-render.d.ts +23 -2
  158. package/dist/src/cli/watch-render.js +2 -1
  159. package/dist/src/cli/watch-server.js +56 -7
  160. package/dist/src/cli/watch-turn.d.ts +4 -1
  161. package/dist/src/cli/watch-turn.js +38 -2
  162. package/dist/src/cli/watch-usage.js +5 -1
  163. package/dist/src/cli/watch-view.d.ts +10 -17
  164. package/dist/src/cli/watch-view.js +33 -77
  165. package/dist/src/cli.js +106 -23
  166. package/dist/src/command-settings.d.ts +16 -0
  167. package/dist/src/command-settings.js +42 -0
  168. package/dist/src/configuration-change.d.ts +11 -0
  169. package/dist/src/configuration-change.js +62 -0
  170. package/dist/src/configuration-display.d.ts +21 -0
  171. package/dist/src/configuration-display.js +69 -0
  172. package/dist/src/configuration-schema.d.ts +49 -0
  173. package/dist/src/configuration-schema.js +159 -0
  174. package/dist/src/daemon/claude-turn.d.ts +20 -5
  175. package/dist/src/daemon/claude-turn.js +116 -53
  176. package/dist/src/daemon/claude-worker.d.ts +3 -5
  177. package/dist/src/daemon/claude-worker.js +64 -80
  178. package/dist/src/daemon/command-journal.d.ts +5 -0
  179. package/dist/src/daemon/command-journal.js +50 -0
  180. package/dist/src/daemon/command-process.d.ts +28 -0
  181. package/dist/src/daemon/command-process.js +164 -0
  182. package/dist/src/daemon/command-worker.d.ts +19 -0
  183. package/dist/src/daemon/command-worker.js +182 -0
  184. package/dist/src/daemon/cursor-stream.d.ts +4 -0
  185. package/dist/src/daemon/cursor-stream.js +154 -0
  186. package/dist/src/daemon/daemon-adapters.d.ts +58 -0
  187. package/dist/src/daemon/daemon-adapters.js +102 -0
  188. package/dist/src/daemon/daemon-loops.d.ts +14 -0
  189. package/dist/src/daemon/daemon-loops.js +39 -0
  190. package/dist/src/daemon/daemon.d.ts +3 -30
  191. package/dist/src/daemon/daemon.js +132 -110
  192. package/dist/src/daemon/declared-input.d.ts +3 -0
  193. package/dist/src/daemon/declared-input.js +9 -0
  194. package/dist/src/daemon/delivery-router.js +7 -1
  195. package/dist/src/daemon/gemini-stream.d.ts +4 -0
  196. package/dist/src/daemon/gemini-stream.js +129 -0
  197. package/dist/src/daemon/github-calls.d.ts +4 -0
  198. package/dist/src/daemon/github-calls.js +16 -7
  199. package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
  200. package/dist/src/daemon/github-ci-rerun.js +92 -0
  201. package/dist/src/daemon/github-ci.d.ts +6 -0
  202. package/dist/src/daemon/github-ci.js +251 -0
  203. package/dist/src/daemon/github-merge-call.d.ts +16 -0
  204. package/dist/src/daemon/github-merge-call.js +73 -0
  205. package/dist/src/daemon/github-merge.d.ts +3 -5
  206. package/dist/src/daemon/github-merge.js +59 -98
  207. package/dist/src/daemon/github-methods.d.ts +28 -0
  208. package/dist/src/daemon/github-methods.js +90 -16
  209. package/dist/src/daemon/github-operation.d.ts +3 -0
  210. package/dist/src/daemon/github-retry.d.ts +6 -0
  211. package/dist/src/daemon/github-retry.js +13 -0
  212. package/dist/src/daemon/github-ticket-status.js +27 -1
  213. package/dist/src/daemon/github-worker.js +2 -1
  214. package/dist/src/daemon/handoff-worker.d.ts +10 -0
  215. package/dist/src/daemon/handoff-worker.js +232 -0
  216. package/dist/src/daemon/issue-queue.d.ts +2 -0
  217. package/dist/src/daemon/issue-queue.js +92 -63
  218. package/dist/src/daemon/notify-journal.d.ts +18 -0
  219. package/dist/src/daemon/notify-journal.js +108 -0
  220. package/dist/src/daemon/notify-message.js +2 -1
  221. package/dist/src/daemon/notify.js +177 -37
  222. package/dist/src/daemon/opencode-stream.d.ts +5 -0
  223. package/dist/src/daemon/opencode-stream.js +87 -0
  224. package/dist/src/daemon/queue-status.d.ts +4 -0
  225. package/dist/src/daemon/queue-status.js +38 -0
  226. package/dist/src/daemon/retry-worktree.d.ts +18 -0
  227. package/dist/src/daemon/retry-worktree.js +139 -0
  228. package/dist/src/daemon/retrying-turn.d.ts +5 -0
  229. package/dist/src/daemon/retrying-turn.js +145 -21
  230. package/dist/src/daemon/schedule-journal.d.ts +19 -0
  231. package/dist/src/daemon/schedule-journal.js +57 -0
  232. package/dist/src/daemon/text-output.d.ts +18 -0
  233. package/dist/src/daemon/text-output.js +44 -0
  234. package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
  235. package/dist/src/daemon/ticket-dependency-waits.js +60 -0
  236. package/dist/src/daemon/ticket-registration.d.ts +10 -8
  237. package/dist/src/daemon/ticket-registration.js +146 -47
  238. package/dist/src/daemon/ticket-source.d.ts +4 -1
  239. package/dist/src/daemon/ticket-source.js +8 -2
  240. package/dist/src/daemon/turn-command.d.ts +10 -0
  241. package/dist/src/daemon/turn-command.js +33 -0
  242. package/dist/src/daemon/turn-report.d.ts +18 -0
  243. package/dist/src/daemon/turn-report.js +79 -0
  244. package/dist/src/daemon/work-tree.d.ts +2 -1
  245. package/dist/src/daemon/work-tree.js +15 -12
  246. package/dist/src/daemon/workflow-generations.d.ts +32 -0
  247. package/dist/src/daemon/workflow-generations.js +57 -0
  248. package/dist/src/daemon/workflow-replay.d.ts +16 -0
  249. package/dist/src/daemon/workflow-replay.js +58 -0
  250. package/dist/src/daemon/workflow-schedules.d.ts +27 -0
  251. package/dist/src/daemon/workflow-schedules.js +185 -0
  252. package/dist/src/decision-visibility.d.ts +2 -0
  253. package/dist/src/decision-visibility.js +10 -0
  254. package/dist/src/decision-wait.d.ts +1 -0
  255. package/dist/src/decision-wait.js +3 -0
  256. package/dist/src/delivery-backoff.d.ts +1 -0
  257. package/dist/src/delivery-backoff.js +3 -0
  258. package/dist/src/doctor-report.d.ts +24 -0
  259. package/dist/src/doctor-report.js +70 -0
  260. package/dist/src/execution-pin.d.ts +9 -0
  261. package/dist/src/execution-pin.js +86 -2
  262. package/dist/src/grok-result.d.ts +12 -0
  263. package/dist/src/grok-result.js +61 -0
  264. package/dist/src/harness-defaults.d.ts +35 -0
  265. package/dist/src/harness-defaults.js +121 -0
  266. package/dist/src/host/decision-resume.d.ts +35 -0
  267. package/dist/src/host/decision-resume.js +86 -0
  268. package/dist/src/host/gate-bridge.d.ts +48 -0
  269. package/dist/src/host/gate-bridge.js +124 -0
  270. package/dist/src/host/run-wait.d.ts +26 -0
  271. package/dist/src/host/run-wait.js +37 -0
  272. package/dist/src/host/start-delivery.d.ts +3 -2
  273. package/dist/src/host/start-delivery.js +11 -4
  274. package/dist/src/host/step-bridge-host.d.ts +6 -19
  275. package/dist/src/host/step-bridge-host.js +57 -55
  276. package/dist/src/host/world-reconciliation.d.ts +1 -0
  277. package/dist/src/host/world-reconciliation.js +3 -0
  278. package/dist/src/host/world-runs.js +5 -0
  279. package/dist/src/issue-identity.d.ts +6 -0
  280. package/dist/src/issue-identity.js +23 -0
  281. package/dist/src/merge-request.d.ts +19 -0
  282. package/dist/src/merge-request.js +32 -0
  283. package/dist/src/phone/canonical-json.d.ts +1 -0
  284. package/dist/src/phone/canonical-json.js +16 -0
  285. package/dist/src/phone/phone-link.d.ts +7 -0
  286. package/dist/src/phone/phone-link.js +21 -0
  287. package/dist/src/phone/qr-data.d.ts +8 -0
  288. package/dist/src/phone/qr-data.js +133 -0
  289. package/dist/src/phone/qr-matrix.d.ts +6 -0
  290. package/dist/src/phone/qr-matrix.js +175 -0
  291. package/dist/src/phone/qr-penalty.d.ts +3 -0
  292. package/dist/src/phone/qr-penalty.js +67 -0
  293. package/dist/src/phone/qr-picture.d.ts +5 -0
  294. package/dist/src/phone/qr-picture.js +24 -0
  295. package/dist/src/private-config.schema.json +263 -0
  296. package/dist/src/project-config.schema.json +65 -0
  297. package/dist/src/project-settings.d.ts +19 -0
  298. package/dist/src/project-settings.js +131 -0
  299. package/dist/src/relay/answer-check.d.ts +24 -0
  300. package/dist/src/relay/answer-check.js +145 -0
  301. package/dist/src/relay/answer-inbox.d.ts +15 -0
  302. package/dist/src/relay/answer-inbox.js +173 -0
  303. package/dist/src/relay/daemon-keys.d.ts +16 -0
  304. package/dist/src/relay/daemon-keys.js +75 -0
  305. package/dist/src/relay/decision-check.d.ts +3 -0
  306. package/dist/src/relay/decision-check.js +77 -0
  307. package/dist/src/relay/decision-close.d.ts +6 -0
  308. package/dist/src/relay/decision-close.js +72 -0
  309. package/dist/src/relay/decision-envelopes.d.ts +29 -0
  310. package/dist/src/relay/decision-envelopes.js +93 -0
  311. package/dist/src/relay/decision-watch.d.ts +14 -0
  312. package/dist/src/relay/decision-watch.js +68 -0
  313. package/dist/src/relay/envelope-post.d.ts +8 -0
  314. package/dist/src/relay/envelope-post.js +71 -0
  315. package/dist/src/relay/envelope.d.ts +28 -0
  316. package/dist/src/relay/envelope.js +53 -0
  317. package/dist/src/relay/hpke.d.ts +25 -0
  318. package/dist/src/relay/hpke.js +108 -0
  319. package/dist/src/relay/pairing-checks.d.ts +42 -0
  320. package/dist/src/relay/pairing-checks.js +172 -0
  321. package/dist/src/relay/pairing-follow.d.ts +8 -0
  322. package/dist/src/relay/pairing-follow.js +95 -0
  323. package/dist/src/relay/pairing-session.d.ts +29 -0
  324. package/dist/src/relay/pairing-session.js +87 -0
  325. package/dist/src/relay/phone-delivery.d.ts +51 -0
  326. package/dist/src/relay/phone-delivery.js +139 -0
  327. package/dist/src/relay/phone-devices.d.ts +36 -0
  328. package/dist/src/relay/phone-devices.js +46 -0
  329. package/dist/src/relay/phone-inbox.d.ts +18 -0
  330. package/dist/src/relay/phone-inbox.js +17 -0
  331. package/dist/src/relay/phone-operations.d.ts +18 -0
  332. package/dist/src/relay/phone-operations.js +121 -0
  333. package/dist/src/relay/phone-outbox.d.ts +21 -0
  334. package/dist/src/relay/phone-outbox.js +25 -0
  335. package/dist/src/relay/phone-socket.d.ts +6 -0
  336. package/dist/src/relay/phone-socket.js +63 -0
  337. package/dist/src/relay/relay-control.d.ts +7 -0
  338. package/dist/src/relay/relay-control.js +24 -0
  339. package/dist/src/relay/relay-files.d.ts +2 -0
  340. package/dist/src/relay/relay-files.js +23 -0
  341. package/dist/src/relay/relay-heartbeat.d.ts +17 -0
  342. package/dist/src/relay/relay-heartbeat.js +81 -0
  343. package/dist/src/relay/relay-http.d.ts +14 -0
  344. package/dist/src/relay/relay-http.js +63 -0
  345. package/dist/src/relay/relay-registration.d.ts +15 -0
  346. package/dist/src/relay/relay-registration.js +63 -0
  347. package/dist/src/relay/relay-service.d.ts +25 -0
  348. package/dist/src/relay/relay-service.js +216 -0
  349. package/dist/src/relay/relay-store.d.ts +48 -0
  350. package/dist/src/relay/relay-store.js +131 -0
  351. package/dist/src/relay/sealed-post.d.ts +25 -0
  352. package/dist/src/relay/sealed-post.js +52 -0
  353. package/dist/src/relay.d.ts +1 -0
  354. package/dist/src/relay.js +8 -0
  355. package/dist/src/report-statistics.d.ts +50 -0
  356. package/dist/src/report-statistics.js +70 -0
  357. package/dist/src/report.d.ts +171 -0
  358. package/dist/src/report.js +119 -0
  359. package/dist/src/repository-identity.d.ts +4 -0
  360. package/dist/src/repository-identity.js +4 -0
  361. package/dist/src/review-subject.d.ts +41 -0
  362. package/dist/src/review-subject.js +91 -0
  363. package/dist/src/run-wait.d.ts +23 -0
  364. package/dist/src/run-wait.js +20 -0
  365. package/dist/src/service/active-tickets.d.ts +4 -0
  366. package/dist/src/service/active-tickets.js +49 -0
  367. package/dist/src/service/command-effects.d.ts +4 -0
  368. package/dist/src/service/command-effects.js +16 -0
  369. package/dist/src/service/decision-handler.d.ts +4 -0
  370. package/dist/src/service/decision-handler.js +39 -4
  371. package/dist/src/service/gateway.js +18 -3
  372. package/dist/src/service/queue-runs.d.ts +3 -0
  373. package/dist/src/service/queue-runs.js +39 -0
  374. package/dist/src/service/registry.d.ts +22 -3
  375. package/dist/src/service/registry.js +51 -8
  376. package/dist/src/service/replies.d.ts +10 -0
  377. package/dist/src/service/replies.js +12 -0
  378. package/dist/src/service/run-handlers.js +45 -54
  379. package/dist/src/service/run-metadata.d.ts +8 -0
  380. package/dist/src/service/run-metadata.js +53 -0
  381. package/dist/src/service/run-waits.d.ts +3 -0
  382. package/dist/src/service/run-waits.js +41 -0
  383. package/dist/src/service/service.d.ts +21 -2
  384. package/dist/src/service/service.js +23 -5
  385. package/dist/src/service/submission-handler.js +70 -19
  386. package/dist/src/service/worker-port.d.ts +1 -0
  387. package/dist/src/service/worker-totals.js +10 -1
  388. package/dist/src/step-bridge.d.ts +32 -0
  389. package/dist/src/steps/decision-gate.d.ts +2 -1
  390. package/dist/src/steps/decision-gate.js +7 -0
  391. package/dist/src/steps/handoff.d.ts +2 -0
  392. package/dist/src/steps/handoff.js +13 -0
  393. package/dist/src/steps/merge-by-person.d.ts +2 -0
  394. package/dist/src/steps/merge-by-person.js +18 -0
  395. package/dist/src/steps/merge-when-green.d.ts +2 -0
  396. package/dist/src/steps/merge-when-green.js +62 -0
  397. package/dist/src/steps/review-by-agent.d.ts +5 -0
  398. package/dist/src/steps/review-by-agent.js +124 -0
  399. package/dist/src/steps/review-by-person.d.ts +4 -0
  400. package/dist/src/steps/review-by-person.js +16 -0
  401. package/dist/src/steps/review-subject.d.ts +2 -0
  402. package/dist/src/steps/review-subject.js +11 -0
  403. package/dist/src/steps/run-command.d.ts +2 -0
  404. package/dist/src/steps/run-command.js +15 -0
  405. package/dist/src/steps/sleep.d.ts +3 -0
  406. package/dist/src/steps/sleep.js +19 -0
  407. package/dist/src/steps/wait-for-decision.d.ts +2 -0
  408. package/dist/src/steps/wait-for-decision.js +71 -0
  409. package/dist/src/steps/wait-for-run.d.ts +5 -0
  410. package/dist/src/steps/wait-for-run.js +9 -0
  411. package/dist/src/storage/decision-snapshots.d.ts +1 -0
  412. package/dist/src/storage/decision-snapshots.js +7 -1
  413. package/dist/src/submission.d.ts +4 -0
  414. package/dist/src/submission.js +6 -2
  415. package/dist/src/testing.d.ts +29 -0
  416. package/dist/src/testing.js +264 -0
  417. package/dist/src/ticket-dependencies.d.ts +1 -0
  418. package/dist/src/ticket-dependencies.js +15 -0
  419. package/dist/src/ticket-status-stream.d.ts +9 -0
  420. package/dist/src/ticket-status-stream.js +94 -0
  421. package/dist/src/ticket-status.js +7 -4
  422. package/dist/src/token-prices.d.ts +14 -4
  423. package/dist/src/token-prices.js +56 -11
  424. package/dist/src/turn-profile.d.ts +1 -0
  425. package/dist/src/turn-profile.js +8 -1
  426. package/dist/src/worker-usage.d.ts +25 -0
  427. package/dist/src/worker-usage.js +58 -1
  428. package/dist/src/workflow-admission.d.ts +6 -0
  429. package/dist/src/workflow-candidate.d.ts +7 -2
  430. package/dist/src/workflow-candidate.js +48 -5
  431. package/dist/src/workflow-contracts.d.ts +2 -0
  432. package/dist/src/workflow-contracts.js +8 -3
  433. package/dist/src/workflow-declaration.d.ts +31 -2
  434. package/dist/src/workflow-declaration.js +140 -16
  435. package/dist/src/workflow-discovery.d.ts +19 -0
  436. package/dist/src/workflow-discovery.js +36 -0
  437. package/dist/src/workflow-refusals.d.ts +6 -0
  438. package/dist/src/workflow-refusals.js +42 -0
  439. package/dist/src/workflow-schedule.d.ts +22 -0
  440. package/dist/src/workflow-schedule.js +53 -0
  441. package/dist/src/workflows.d.ts +12 -1
  442. package/dist/src/workflows.js +9 -0
  443. package/dist/tools/admit-workflow.d.ts +14 -0
  444. package/dist/tools/admit-workflow.js +107 -0
  445. package/dist/tools/doctor-adoption.d.ts +1 -0
  446. package/dist/tools/doctor-adoption.js +11 -0
  447. package/dist/tools/project-configuration.d.ts +4 -0
  448. package/dist/tools/project-configuration.js +47 -0
  449. package/dist/tools/self-host-processes.d.ts +1 -0
  450. package/dist/tools/self-host-processes.js +33 -22
  451. package/dist/tools/self-host-project.d.ts +21 -0
  452. package/dist/tools/self-host-project.js +224 -0
  453. package/dist/tools/self-host-runtime.d.ts +16 -0
  454. package/dist/tools/self-host-runtime.js +60 -0
  455. package/dist/tools/self-host-workflows.d.ts +1 -0
  456. package/dist/tools/self-host-workflows.js +36 -1
  457. package/dist/tools/self-host.js +106 -135
  458. package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
  459. package/dist/tools/workflow-bundle-dependencies.js +93 -0
  460. package/dist/tools/workflow-bundles.d.ts +20 -0
  461. package/dist/tools/workflow-bundles.js +173 -0
  462. package/dist/tools/workflow-candidate-counts.d.ts +12 -0
  463. package/dist/tools/workflow-candidate-counts.js +266 -0
  464. package/dist/tools/workflow-candidate-fields.d.ts +5 -0
  465. package/dist/tools/workflow-candidate-fields.js +24 -0
  466. package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
  467. package/dist/tools/workflow-candidate-helper-counts.js +129 -0
  468. package/dist/tools/workflow-candidate-program.d.ts +13 -0
  469. package/dist/tools/workflow-candidate-program.js +106 -0
  470. package/dist/tools/workflow-candidate-source.d.ts +6 -0
  471. package/dist/tools/workflow-candidate-source.js +169 -0
  472. package/dist/tools/workflow-candidate-syntax.d.ts +21 -0
  473. package/dist/tools/workflow-candidate-syntax.js +263 -0
  474. package/dist/tools/workflow-command.d.ts +1 -0
  475. package/dist/tools/workflow-command.js +143 -0
  476. package/dist/tools/workflow-folder-capture.d.ts +18 -0
  477. package/dist/tools/workflow-folder-capture.js +261 -0
  478. package/dist/tools/workflow-folders.d.ts +49 -0
  479. package/dist/tools/workflow-folders.js +203 -0
  480. package/dist/tools/workflow-source-effects.d.ts +10 -0
  481. package/dist/tools/workflow-source-effects.js +213 -0
  482. package/dist/tools/workflow-test-hook.d.ts +7 -0
  483. package/dist/tools/workflow-test-hook.js +16 -0
  484. package/dist/tools/workflow-test-loader.d.ts +1 -0
  485. package/dist/tools/workflow-test-loader.js +10 -0
  486. package/dist/workflows/develop-prd.js +71 -3
  487. package/dist/workflows/develop-ticket.js +6 -1
  488. package/dist/workflows/ticket-prompts.js +17 -3
  489. package/package.json +66 -6
  490. package/templates/develop/README.md +78 -0
  491. package/templates/develop/develop/accept.ts +11 -0
  492. package/templates/develop/develop/flow-tests.ts +357 -0
  493. package/templates/develop/develop/local.ts +40 -0
  494. package/templates/develop/develop/option-tests.ts +174 -0
  495. package/templates/develop/develop/partial-choice.ts +29 -0
  496. package/templates/develop/develop/partial.ts +28 -0
  497. package/templates/develop/develop/pull.ts +152 -0
  498. package/templates/develop/develop/queue-partial.ts +39 -0
  499. package/templates/develop/develop/refusal-tests.ts +174 -0
  500. package/templates/develop/develop/report.ts +156 -0
  501. package/templates/develop/develop/round.ts +40 -0
  502. package/templates/develop/develop/scenarios.ts +87 -0
  503. package/templates/develop/develop/turn.ts +67 -0
  504. package/templates/develop/develop.declaration.json +24 -0
  505. package/templates/develop/develop.test.ts +287 -0
  506. package/templates/develop/develop.ts +30 -0
  507. package/templates/develop/template.json +153 -0
  508. package/dist/src/chats/analysis-batches.d.ts +0 -24
  509. package/dist/src/chats/analysis-batches.js +0 -83
  510. package/dist/src/chats/analysis-contract.d.ts +0 -80
  511. package/dist/src/chats/analysis-contract.js +0 -16
  512. package/dist/src/chats/analysis-data.d.ts +0 -3
  513. package/dist/src/chats/analysis-data.js +0 -85
  514. package/dist/src/chats/analysis-input.d.ts +0 -12
  515. package/dist/src/chats/analysis-input.js +0 -83
  516. package/dist/src/chats/analysis-links.d.ts +0 -2
  517. package/dist/src/chats/analysis-links.js +0 -25
  518. package/dist/src/chats/analysis-prompt.d.ts +0 -10
  519. package/dist/src/chats/analysis-prompt.js +0 -16
  520. package/dist/src/chats/analysis-proposal.d.ts +0 -2
  521. package/dist/src/chats/analysis-proposal.js +0 -32
  522. package/dist/src/chats/analysis-provenance.d.ts +0 -4
  523. package/dist/src/chats/analysis-provenance.js +0 -99
  524. package/dist/src/chats/analysis-shape.d.ts +0 -3
  525. package/dist/src/chats/analysis-shape.js +0 -228
  526. package/dist/src/chats/analysis.d.ts +0 -3
  527. package/dist/src/chats/analysis.js +0 -42
  528. package/dist/src/chats/corpus-input.d.ts +0 -5
  529. package/dist/src/chats/corpus-input.js +0 -288
  530. package/dist/src/chats/destination.d.ts +0 -4
  531. package/dist/src/chats/destination.js +0 -96
  532. package/dist/src/chats/import.d.ts +0 -15
  533. package/dist/src/chats/import.js +0 -243
  534. package/dist/src/chats/input-file.d.ts +0 -3
  535. package/dist/src/chats/input-file.js +0 -32
  536. package/dist/src/chats/normalize.d.ts +0 -29
  537. package/dist/src/chats/normalize.js +0 -155
  538. package/dist/src/chats/previous-import.d.ts +0 -5
  539. package/dist/src/chats/previous-import.js +0 -34
  540. package/dist/src/chats/reader.d.ts +0 -21
  541. package/dist/src/chats/reader.js +0 -118
  542. package/dist/src/chats/redact-import.d.ts +0 -14
  543. package/dist/src/chats/redact-import.js +0 -141
  544. package/dist/src/chats/redaction.d.ts +0 -41
  545. package/dist/src/chats/redaction.js +0 -161
  546. package/dist/src/chats/revision-input.d.ts +0 -3
  547. package/dist/src/chats/revision-input.js +0 -180
  548. package/dist/src/chats/revision.d.ts +0 -48
  549. package/dist/src/chats/revision.js +0 -94
  550. package/dist/src/chats/selection.d.ts +0 -25
  551. package/dist/src/chats/selection.js +0 -109
  552. package/dist/src/chats/source.d.ts +0 -23
  553. package/dist/src/chats/source.js +0 -135
  554. package/dist/src/chats/structure.d.ts +0 -57
  555. package/dist/src/chats/structure.js +0 -216
  556. package/dist/src/daemon/analysis-launch.d.ts +0 -5
  557. package/dist/src/daemon/analysis-launch.js +0 -81
  558. package/dist/src/daemon/analysis-token.d.ts +0 -6
  559. package/dist/src/daemon/analysis-token.js +0 -88
  560. package/dist/src/daemon/analysis-worker.d.ts +0 -22
  561. package/dist/src/daemon/analysis-worker.js +0 -219
  562. package/dist/src/daemon/chats-files.d.ts +0 -15
  563. package/dist/src/daemon/chats-files.js +0 -113
  564. package/dist/src/daemon/chats-worker.d.ts +0 -12
  565. package/dist/src/daemon/chats-worker.js +0 -200
  566. package/dist/workflows/analyze-chats.d.ts +0 -10
  567. package/dist/workflows/analyze-chats.declaration.json +0 -9
  568. package/dist/workflows/analyze-chats.js +0 -73
@@ -1,9 +1,17 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { admitCompiled } from "../cli/validate.js";
3
+ import { isCommandWaits, workflowQueueRefusals, } from "../workflow-declaration.js";
3
4
  import { ticketCommandText, ticketText } from "./ticket-source.js";
4
- export const ticketWorkflow = "develop-ticket";
5
- export const promptWorkflow = "develop-prompt";
6
- export const issueWorkflow = "develop-issue";
5
+ import { declaredInput } from "./declared-input.js";
6
+ import { bundledWorkflowIds } from "../workflow-discovery.js";
7
+ import { declaredManifest } from "../execution-pin.js";
8
+ import { record } from "../protocol.js";
9
+ import { hasTicketField } from "../submission.js";
10
+ import { issueIdentity } from "../issue-identity.js";
11
+ import { ticketDependencyWaits, TicketDependencyReadError, } from "./ticket-dependency-waits.js";
12
+ export const ticketWorkflow = bundledWorkflowIds.ticket;
13
+ export const promptWorkflow = bundledWorkflowIds.prompt;
14
+ export const issueWorkflow = bundledWorkflowIds.issue;
7
15
  export const ticketCapabilities = ["claude", "github"];
8
16
  const ticketIdentifier = /^[A-Za-z0-9._:-]{1,64}$/;
9
17
  function rejected(code, detail) {
@@ -38,7 +46,15 @@ async function ticket(source, request) {
38
46
  async function nextTicket(source, request) {
39
47
  if (source.nextCommand === undefined)
40
48
  return rejected("next-source-not-configured", "The daemon has no next-ticket command. Set CLOVING_NEXT_COMMAND.");
41
- const selected = await ticketCommandText(source.nextCommand, request.signal);
49
+ const selected = await ticketCommandText(source.nextCommand, {
50
+ signal: request.signal,
51
+ skipTickets: [
52
+ ...new Set([
53
+ ...(request.activeTickets ?? []).flatMap((input) => typeof input["ticketId"] === "string" ? [input["ticketId"]] : []),
54
+ ...(source.skipTickets ?? []),
55
+ ]),
56
+ ].sort(),
57
+ });
42
58
  if (selected.kind === "failed")
43
59
  return rejected("next-ticket-not-available", selected.detail);
44
60
  if (selected.text === "")
@@ -55,18 +71,43 @@ export function ticketResolver(source) {
55
71
  };
56
72
  }
57
73
  export function issueResolver(source) {
74
+ const waits = ticketDependencyWaits(source);
58
75
  return {
59
76
  id: "issue-command",
60
77
  version: "1",
61
- resolve: async (request) => {
62
- const resolution = await ticket(source, request);
63
- if (resolution.kind === "rejected")
64
- return resolution;
65
- return {
66
- kind: "resolved",
67
- input: { ...Object(resolution.input), delivery: "pull-request" },
68
- };
69
- },
78
+ skippedTickets: waits.skipped,
79
+ resolve: (request) => issueTicket({ source, waits }, request).catch((error) => {
80
+ if (!(error instanceof TicketDependencyReadError))
81
+ throw error;
82
+ return rejected("ticket-not-available", "The ticket dependencies could not be read. Retry this command.");
83
+ }),
84
+ };
85
+ }
86
+ async function issueTicket(context, request) {
87
+ const { source, waits } = context;
88
+ const skipTickets = request.submission["ticket"] === "next"
89
+ ? await waits.refresh(request.signal)
90
+ : [];
91
+ const resolution = await ticket({ ...source, skipTickets }, request);
92
+ if (resolution.kind === "rejected")
93
+ return resolution;
94
+ const input = record(resolution.input) ?? {};
95
+ const identity = issueIdentity(input["ticket"]);
96
+ if ((request.activeTickets ?? []).some((active) => active["ticketId"] === input["ticketId"] ||
97
+ (identity !== null &&
98
+ JSON.stringify(issueIdentity(active["ticket"])) ===
99
+ JSON.stringify(identity))))
100
+ return rejected("ticket-active", "An active run already works on this ticket.");
101
+ const dependencies = await waits.check({
102
+ ticketId: String(input["ticketId"]),
103
+ ticket: String(input["ticket"]),
104
+ signal: request.signal,
105
+ });
106
+ if (dependencies.length > 0)
107
+ return rejected("ticket-dependency-open", `Ticket ${String(input["ticketId"])} needs open issues: ${dependencies.map((id) => `#${id}`).join(", ")}.`);
108
+ return {
109
+ kind: "resolved",
110
+ input: { ...input, delivery: "pull-request" },
70
111
  };
71
112
  }
72
113
  export function promptResolver(repository) {
@@ -89,6 +130,7 @@ export function ticketRegistrationTable(source, declarations = []) {
89
130
  workflowId: ticketWorkflow,
90
131
  functionName: "developTicket",
91
132
  effectLimit: 8,
133
+ handoffs: [],
92
134
  submission: { maximumBytes: 4_096, fields: { ticket: "string" } },
93
135
  resolver: ticketResolver(source),
94
136
  },
@@ -96,13 +138,15 @@ export function ticketRegistrationTable(source, declarations = []) {
96
138
  workflowId: issueWorkflow,
97
139
  functionName: "developTicket",
98
140
  effectLimit: 20,
141
+ handoffs: [],
99
142
  submission: { maximumBytes: 4_096, fields: { ticket: "string" } },
100
143
  resolver: issueResolver(source),
101
144
  },
102
145
  {
103
- workflowId: "develop-prd",
146
+ workflowId: bundledWorkflowIds.prd,
104
147
  functionName: "developPrd",
105
148
  effectLimit: 8,
149
+ handoffs: [issueWorkflow],
106
150
  submission: { maximumBytes: 65_536, fields: { prompt: "string" } },
107
151
  resolver: promptResolver(source.repository),
108
152
  },
@@ -110,54 +154,64 @@ export function ticketRegistrationTable(source, declarations = []) {
110
154
  workflowId: promptWorkflow,
111
155
  functionName: "developTicket",
112
156
  effectLimit: 8,
157
+ handoffs: [],
113
158
  submission: { maximumBytes: 65_536, fields: { prompt: "string" } },
114
159
  resolver: promptResolver(source.repository),
115
160
  },
116
- ...declarations.map((declaration) => ({
117
- workflowId: declaration.workflowId,
118
- functionName: declaration.functionName,
119
- effectLimit: declaration.effectLimit,
120
- capabilities: declaration.capabilities,
121
- submission: declaration.input,
122
- resolver: declaredResolver(source.repository),
161
+ ...declarations.map(({ input, ...declaration }) => ({
162
+ ...declaration,
163
+ submission: input,
164
+ resolver: declaredResolver(source, input),
123
165
  })),
124
166
  ];
125
167
  }
126
- function declaredResolver(repository) {
168
+ function declaredResolver(source, contract) {
169
+ const tickets = hasTicketField(contract) ? issueResolver(source) : undefined;
127
170
  return {
128
171
  id: "declared-input",
129
172
  version: "1",
130
- resolve: (request) => Promise.resolve({
131
- kind: "resolved",
132
- input: {
133
- cycleId: `task-${digest(request.commandId).slice(0, 12)}`,
134
- repository,
135
- input: request.submission,
136
- },
137
- }),
173
+ ...(tickets?.skippedTickets === undefined
174
+ ? {}
175
+ : { skippedTickets: tickets.skippedTickets }),
176
+ resolve: async (request) => {
177
+ const resolution = tickets !== undefined && Object.hasOwn(request.submission, "ticket")
178
+ ? await tickets.resolve(request)
179
+ : undefined;
180
+ if (resolution?.kind === "rejected")
181
+ return resolution;
182
+ const ticket = resolution === undefined ? undefined : (record(resolution.input) ?? {});
183
+ const input = ticket === undefined
184
+ ? request.submission
185
+ : {
186
+ ...request.submission,
187
+ ticket: { id: ticket["ticketId"], text: ticket["ticket"] },
188
+ };
189
+ return {
190
+ kind: "resolved",
191
+ input: declaredInput(source.repository, {
192
+ commandId: request.commandId,
193
+ submission: input,
194
+ }),
195
+ };
196
+ },
138
197
  };
139
198
  }
140
199
  export async function ticketRegistrations(manifests, options) {
141
- const ids = new Set();
142
- for (const row of options.table) {
143
- if (ids.has(row.workflowId))
144
- return {
145
- kind: "rejected",
146
- detail: `duplicate-workflow-id: ${row.workflowId}`,
147
- };
148
- ids.add(row.workflowId);
149
- }
200
+ const refusal = registrationRefusal(options.table, options.commands ?? {});
201
+ if (refusal !== undefined)
202
+ return { kind: "rejected", detail: refusal };
150
203
  const registrations = [];
151
204
  for (const row of options.table) {
152
- const manifest = manifests[row.functionName];
205
+ const { functionName, capabilities = ticketCapabilities, ...registration } = row;
206
+ const manifest = manifests[functionName];
153
207
  if (manifest === undefined)
154
208
  return {
155
209
  kind: "rejected",
156
- detail: `Missing manifest for workflow function ${row.functionName}.`,
210
+ detail: `Missing manifest for workflow function ${functionName}.`,
157
211
  };
158
212
  const admission = await admitCompiled(manifest, {
159
213
  file: manifest,
160
- capabilities: row.capabilities ?? ticketCapabilities,
214
+ capabilities,
161
215
  });
162
216
  if (admission.kind === "rejected")
163
217
  return {
@@ -165,13 +219,58 @@ export async function ticketRegistrations(manifests, options) {
165
219
  detail: `${admission.error.code}: ${admission.error.detail}`,
166
220
  };
167
221
  registrations.push({
168
- workflowId: row.workflowId,
169
- manifest: admission.manifest,
222
+ ...registration,
223
+ manifest: declaredManifest(admission.manifest, {
224
+ ...row,
225
+ bundleDigest: options.bundleDigest,
226
+ }),
170
227
  availability: "available",
171
- effectLimit: row.effectLimit,
172
- submission: row.submission,
173
- resolver: row.resolver,
174
228
  });
175
229
  }
176
230
  return { kind: "admitted", registrations };
177
231
  }
232
+ function registrationRefusal(table, commands) {
233
+ const queueRefusal = queueRegistrationRefusal(table);
234
+ if (queueRefusal !== undefined)
235
+ return queueRefusal;
236
+ const ids = new Set();
237
+ for (const row of table) {
238
+ if (ids.has(row.workflowId))
239
+ return `duplicate-workflow-id: ${row.workflowId}`;
240
+ ids.add(row.workflowId);
241
+ }
242
+ for (const row of table) {
243
+ const unknown = row.handoffs?.find((target) => !ids.has(target));
244
+ if (unknown !== undefined)
245
+ return `unknown-handoff-target: ${row.workflowId} -> ${unknown}`;
246
+ }
247
+ for (const row of table) {
248
+ const refusal = commandRegistrationRefusal(row, commands);
249
+ if (refusal !== undefined)
250
+ return refusal;
251
+ }
252
+ return undefined;
253
+ }
254
+ function commandRegistrationRefusal(row, commands) {
255
+ if (Object.hasOwn(row, "commandWaits") &&
256
+ !isCommandWaits(row.commandWaits, {
257
+ capabilities: row.capabilities ?? ticketCapabilities,
258
+ commands: row.commands ?? [],
259
+ }))
260
+ return `invalid-command-waits: ${row.workflowId}`;
261
+ const unknown = row.commands?.find((name) => !Object.hasOwn(commands, name));
262
+ return unknown === undefined
263
+ ? undefined
264
+ : `command-unknown: ${row.workflowId} -> ${unknown}`;
265
+ }
266
+ function queueRegistrationRefusal(table) {
267
+ const queued = table.filter((row) => row.queue === true);
268
+ if (queued.length > 1)
269
+ return `queue-workflow-conflict: ${queued.map((row) => row.workflowId).join(", ")}`;
270
+ for (const row of queued) {
271
+ const codes = workflowQueueRefusals({ queue: true, input: row.submission });
272
+ if (codes.length > 0)
273
+ return `${codes.join(", ")}: ${row.workflowId}`;
274
+ }
275
+ return undefined;
276
+ }
@@ -14,4 +14,7 @@ export interface TicketRequest {
14
14
  readonly signal: AbortSignal;
15
15
  }
16
16
  export declare function ticketText(command: readonly string[], request: TicketRequest): Promise<TicketRead>;
17
- export declare function ticketCommandText(command: readonly string[], signal: AbortSignal): Promise<TicketRead>;
17
+ export declare function ticketCommandText(command: readonly string[], request: AbortSignal | {
18
+ readonly signal: AbortSignal;
19
+ readonly skipTickets: readonly string[];
20
+ }): Promise<TicketRead>;
@@ -26,10 +26,16 @@ export function ticketText(command, request) {
26
26
  const [executable = "", ...fixed] = command;
27
27
  return ticketCommandText([executable, ...fixed, request.ticketId], request.signal).then((result) => result.kind === "failed" ? result : printed(result.text));
28
28
  }
29
- export function ticketCommandText(command, signal) {
29
+ export function ticketCommandText(command, request) {
30
30
  const [executable = "", ...fixed] = command;
31
31
  return executed(executable, fixed, {
32
- signal,
32
+ signal: request instanceof AbortSignal ? request : request.signal,
33
+ env: request instanceof AbortSignal
34
+ ? process.env
35
+ : {
36
+ ...process.env,
37
+ CLOVING_SKIP_TICKETS: request.skipTickets.join(" "),
38
+ },
33
39
  maxBuffer: 4 * ticketLimits.textBytes,
34
40
  encoding: "utf8",
35
41
  }).then((output) => ({ kind: "read", text: output.stdout.trim() }), ended);
@@ -0,0 +1,10 @@
1
+ export interface CommandStart {
2
+ readonly output?: string | undefined;
3
+ readonly worker?: string | undefined;
4
+ readonly command: readonly string[];
5
+ readonly prompt: string;
6
+ }
7
+ export declare function turnCommand(start: CommandStart): {
8
+ readonly parts: readonly string[];
9
+ readonly standardInput: string | undefined;
10
+ };
@@ -0,0 +1,33 @@
1
+ function argumentPrompt(prompt) {
2
+ return Buffer.byteLength(prompt, "utf8") < 64 * 1024;
3
+ }
4
+ export function turnCommand(start) {
5
+ if (start.output === "text")
6
+ return {
7
+ parts: start.command.map((part) => part === "{prompt}" ? start.prompt : part),
8
+ standardInput: start.command.includes("{prompt}")
9
+ ? undefined
10
+ : start.prompt,
11
+ };
12
+ if (start.worker === "gemini" && argumentPrompt(start.prompt))
13
+ return {
14
+ parts: [...start.command, "-p", start.prompt],
15
+ standardInput: undefined,
16
+ };
17
+ if (start.worker === "opencode")
18
+ return {
19
+ parts: [...start.command, start.prompt],
20
+ standardInput: undefined,
21
+ };
22
+ if (start.worker === "cursor-agent" && argumentPrompt(start.prompt))
23
+ return {
24
+ parts: [...start.command, start.prompt],
25
+ standardInput: undefined,
26
+ };
27
+ if (start.worker !== "grok")
28
+ return { parts: start.command, standardInput: start.prompt };
29
+ const command = [...start.command];
30
+ const index = command.findIndex((argument, position) => position > 0 && ["-p", "--single"].includes(argument));
31
+ command.splice(index < 0 ? command.length : index + 1, 0, start.prompt);
32
+ return { parts: command, standardInput: undefined };
33
+ }
@@ -0,0 +1,18 @@
1
+ import { type WorkTree } from "./work-tree.ts";
2
+ import type { StreamResult } from "./claude-turn.ts";
3
+ interface ReportLimits {
4
+ readonly summaryCharacters: number;
5
+ readonly resultBytes: number;
6
+ }
7
+ export declare function turnReport(start: {
8
+ readonly harness: {
9
+ readonly worker: string;
10
+ readonly output?: "text";
11
+ };
12
+ readonly tree: WorkTree;
13
+ readonly limits: ReportLimits;
14
+ }, result: StreamResult): Promise<{
15
+ readonly text?: string;
16
+ readonly reason?: string;
17
+ }>;
18
+ export {};
@@ -0,0 +1,79 @@
1
+ import { ticketStatus } from "../ticket-status.js";
2
+ import { reviewReport } from "../review-subject.js";
3
+ import { sumPrices } from "../worker-usage.js";
4
+ import { changes } from "./work-tree.js";
5
+ function tailReport(fields, limit) {
6
+ let text = JSON.stringify({ ...fields, summary: "" });
7
+ if (Buffer.byteLength(text) > limit)
8
+ return undefined;
9
+ let minimum = 1;
10
+ let maximum = fields.summary.length;
11
+ while (minimum <= maximum) {
12
+ const kept = Math.floor((minimum + maximum) / 2);
13
+ const candidate = JSON.stringify({
14
+ ...fields,
15
+ summary: fields.summary.slice(-kept),
16
+ });
17
+ if (Buffer.byteLength(candidate) > limit) {
18
+ maximum = kept - 1;
19
+ continue;
20
+ }
21
+ text = candidate;
22
+ minimum = kept + 1;
23
+ }
24
+ return text;
25
+ }
26
+ function boundedReport(fields, options) {
27
+ const text = JSON.stringify(fields);
28
+ const excess = Buffer.byteLength(text) - options.limit;
29
+ if (excess <= 0)
30
+ return { text };
31
+ if (options.output === "text") {
32
+ const shortened = tailReport(fields, options.limit);
33
+ return shortened === undefined
34
+ ? { reason: "claude-result-too-large" }
35
+ : { text: shortened };
36
+ }
37
+ const kept = Math.max(0, fields.summary.length - excess);
38
+ const shortened = JSON.stringify({
39
+ ...fields,
40
+ summary: fields.summary.slice(0, kept),
41
+ });
42
+ if (Buffer.byteLength(shortened) <= options.limit)
43
+ return { text: shortened };
44
+ const metadata = JSON.stringify({
45
+ ...fields,
46
+ ticketStatus: undefined,
47
+ summary: "",
48
+ });
49
+ return {
50
+ reason: "claude-result-too-large",
51
+ ...(Buffer.byteLength(metadata) <= options.limit ? { text: metadata } : {}),
52
+ };
53
+ }
54
+ export async function turnReport(start, result) {
55
+ if (result.ticketStatusTooLarge === true)
56
+ return { reason: "claude-result-too-large" };
57
+ const { harness, tree, limits } = start;
58
+ const review = reviewReport(result.text);
59
+ const feedback = result.reviewFeedback ?? review.feedback;
60
+ return boundedReport({
61
+ harness: harness.worker,
62
+ ticketStatus: ticketStatus(result.text, result.ticketStatus),
63
+ reviewVerdict: result.reviewVerdict === undefined
64
+ ? review.reviewVerdict
65
+ : result.reviewVerdict,
66
+ summary: harness.output === "text"
67
+ ? feedback.slice(-limits.summaryCharacters)
68
+ : feedback.slice(0, limits.summaryCharacters),
69
+ ...(await changes(tree)),
70
+ worktree: tree.path,
71
+ costUsd: result.costUsd,
72
+ usage: result.usage,
73
+ model: result.model,
74
+ ...(result.attempts === undefined ? {} : { attempts: result.attempts }),
75
+ estimatedCostUsd: sumPrices((result.attempts ?? []).map((attempt) => attempt.estimatedCostUsd)),
76
+ sessionId: result.sessionId,
77
+ turns: result.turns,
78
+ }, { ...harness, limit: limits.resultBytes });
79
+ }
@@ -12,9 +12,10 @@ export interface TreeRequest {
12
12
  }
13
13
  export interface Changes {
14
14
  readonly branch: string;
15
+ readonly commit: string | null;
15
16
  readonly commits: readonly string[];
16
17
  readonly files: readonly string[];
17
- readonly uncommitted: readonly string[];
18
+ readonly uncommitted: readonly string[] | null;
18
19
  }
19
20
  export declare function treeName(target: string): string;
20
21
  export declare function treePlace(request: Pick<TreeRequest, "worktrees" | "target">): {
@@ -186,21 +186,24 @@ export function treeFailure(error) {
186
186
  : "work-tree-not-available";
187
187
  }
188
188
  export async function changes(tree) {
189
- const lines = async (parts) => (await git({ directory: tree.path, parts }).catch(() => ""))
190
- .split("\n")
191
- .filter((line) => line.trim() !== "")
192
- .slice(0, lineLimit)
193
- .map((line) => line.slice(0, lineLength));
189
+ const lines = (parts) => changeLines({ directory: tree.path, parts });
194
190
  const range = `${tree.startCommit}..HEAD`;
195
- const [branch = tree.branch] = await lines([
196
- "rev-parse",
197
- "--abbrev-ref",
198
- "HEAD",
199
- ]);
191
+ const branch = (await lines(["rev-parse", "--abbrev-ref", "HEAD"]))?.[0] ?? tree.branch;
200
192
  return {
201
193
  branch,
202
- commits: await lines(["log", "--oneline", range]),
203
- files: await lines(["diff", "--stat", range]),
194
+ commit: (await lines(["rev-parse", "HEAD"]))?.[0] ?? null,
195
+ commits: (await lines(["log", "--oneline", range])) ?? [],
196
+ files: (await lines(["diff", "--stat", range])) ?? [],
204
197
  uncommitted: await lines(["status", "--short"]),
205
198
  };
206
199
  }
200
+ async function changeLines(call) {
201
+ const output = await git(call).catch(() => null);
202
+ if (output === null)
203
+ return null;
204
+ return output
205
+ .split("\n")
206
+ .filter((line) => line.trim() !== "")
207
+ .slice(0, lineLimit)
208
+ .map((line) => line.slice(0, lineLength));
209
+ }
@@ -0,0 +1,32 @@
1
+ import type { HostPorts } from "../service/service.ts";
2
+ import type { WorkflowFunction } from "../host/start-delivery.ts";
3
+ import type { WorkflowHandler } from "../host/world-host.ts";
4
+ import type { ExecutionManifest } from "../workflow-admission.ts";
5
+ import { type WorkflowRegistration } from "../service/registry.ts";
6
+ export interface WorkflowGeneration {
7
+ readonly workflows: Readonly<Record<string, unknown>>;
8
+ readonly handler: WorkflowHandler;
9
+ }
10
+ export type WorkflowBundleLoader = (directory: string) => Promise<WorkflowGeneration>;
11
+ export declare function workflowGenerations(settings: {
12
+ readonly directory: string;
13
+ readonly repository: string;
14
+ readonly registrations: readonly WorkflowRegistration[];
15
+ readonly table: readonly {
16
+ readonly workflowId: string;
17
+ readonly functionName: string;
18
+ }[];
19
+ readonly workflows: Readonly<Record<string, WorkflowFunction | undefined>>;
20
+ readonly handler: WorkflowHandler;
21
+ readonly loadBundle?: WorkflowBundleLoader;
22
+ }): {
23
+ resolve: (manifest: ExecutionManifest | undefined) => Promise<{
24
+ workflow: WorkflowFunction;
25
+ handler: WorkflowHandler;
26
+ } | undefined>;
27
+ available: (manifest: ExecutionManifest) => Promise<ExecutionManifest | undefined>;
28
+ };
29
+ export declare function prepareWorkflowGenerations(ports: {
30
+ readonly state: HostPorts["state"];
31
+ readonly workflow: Pick<HostPorts["workflow"], "manifest">;
32
+ }, generations: Pick<ReturnType<typeof workflowGenerations>, "resolve">): Promise<void>;
@@ -0,0 +1,57 @@
1
+ import { join } from "node:path";
2
+ import { workflowRegistry, } from "../service/registry.js";
3
+ import { workflowPin } from "../broker/workflow-pin.js";
4
+ export function workflowGenerations(settings) {
5
+ const functions = Object.fromEntries(settings.table.map((row) => [
6
+ row.workflowId,
7
+ settings.workflows[row.functionName],
8
+ ]));
9
+ const registry = workflowRegistry(settings.registrations, {
10
+ workflowBundles: {
11
+ directory: join(settings.directory, "workflow-bundles"),
12
+ repository: settings.repository,
13
+ },
14
+ });
15
+ const resolve = async (manifest) => {
16
+ if (manifest === undefined)
17
+ return undefined;
18
+ const registered = registry.byPin(workflowPin(manifest));
19
+ if (registered !== undefined) {
20
+ const workflow = functions[registered.workflowId];
21
+ return workflow === undefined
22
+ ? undefined
23
+ : { workflow, handler: settings.handler };
24
+ }
25
+ if (manifest.bundleDigest === undefined ||
26
+ settings.loadBundle === undefined)
27
+ return undefined;
28
+ const directory = await registry.bundle(manifest);
29
+ if (directory === undefined)
30
+ return undefined;
31
+ try {
32
+ const generation = await settings.loadBundle(directory);
33
+ const workflow = Object.values(generation.workflows).find((candidate) => typeof candidate === "function" &&
34
+ Reflect.get(candidate, "workflowId") === manifest.workflowId);
35
+ return workflow === undefined
36
+ ? undefined
37
+ : { workflow, handler: generation.handler };
38
+ }
39
+ catch {
40
+ return undefined;
41
+ }
42
+ };
43
+ return {
44
+ resolve,
45
+ available: async (manifest) => (await resolve(manifest)) === undefined ? undefined : manifest,
46
+ };
47
+ }
48
+ export async function prepareWorkflowGenerations(ports, generations) {
49
+ const prepared = new Set();
50
+ for (const run of Object.values((await ports.state()).runs)) {
51
+ if (["completed", "failed", "cancelled"].includes(run.status) ||
52
+ prepared.has(run.workflow))
53
+ continue;
54
+ prepared.add(run.workflow);
55
+ await generations.resolve(await ports.workflow.manifest(run.runId));
56
+ }
57
+ }
@@ -0,0 +1,16 @@
1
+ import type { WorkflowHandler } from "../host/world-host.ts";
2
+ import type { AuthorityState } from "../authority/transitions.ts";
3
+ interface ReplayRun {
4
+ readonly runId: string;
5
+ readonly workflowId?: string;
6
+ }
7
+ interface ReplayPorts {
8
+ readonly state: () => Promise<Pick<AuthorityState, "details">>;
9
+ readonly run: (receipt: string) => Promise<ReplayRun | undefined>;
10
+ readonly available: (runId: string, workflowId?: string) => Promise<boolean>;
11
+ readonly submit: (command: Readonly<Record<string, unknown>>) => Promise<{
12
+ readonly kind: "accepted" | "duplicate" | "failed" | "rejected";
13
+ }>;
14
+ }
15
+ export declare function pinnedWorkflowHandler(handler: (request: Request, runId: string) => Promise<Response>, ports: ReplayPorts): WorkflowHandler;
16
+ export {};
@@ -0,0 +1,58 @@
1
+ import { record } from "../protocol.js";
2
+ import { setTimeout as delay } from "node:timers/promises";
3
+ function seeded(value) {
4
+ const input = record(record(value)?.["runInput"]);
5
+ const runId = record(input?.["attributes"])?.["cloving.run"];
6
+ const workflowId = input?.["workflowName"];
7
+ return typeof runId === "string" && typeof workflowId === "string"
8
+ ? { runId, workflowId }
9
+ : undefined;
10
+ }
11
+ async function located(ports, receipt) {
12
+ for (let attempt = 0; attempt < 20; attempt += 1) {
13
+ const run = await ports.run(receipt);
14
+ if (run !== undefined)
15
+ return run;
16
+ await delay(5);
17
+ }
18
+ return undefined;
19
+ }
20
+ async function observedReplay(ports, replay) {
21
+ const { runId, receipt, available } = replay;
22
+ const observation = (await ports.state()).details[runId]?.observation;
23
+ const unavailable = observation?.reason === "pinned-workflow-unavailable";
24
+ if (available !== unavailable)
25
+ return true;
26
+ const expectedObservation = observation?.sequence ?? 0;
27
+ const outcome = await ports.submit({
28
+ kind: "report-observation",
29
+ runId,
30
+ commandId: `pinned-workflow-${available ? "restored" : "unavailable"}:${receipt}:${String(expectedObservation)}`,
31
+ condition: available ? "working" : "infrastructure-failure",
32
+ reason: available ? "in-progress" : "pinned-workflow-unavailable",
33
+ expectedObservation,
34
+ });
35
+ return outcome.kind === "accepted" || outcome.kind === "duplicate";
36
+ }
37
+ export function pinnedWorkflowHandler(handler, ports) {
38
+ return async (request) => {
39
+ const value = await request
40
+ .clone()
41
+ .json()
42
+ .catch(() => undefined);
43
+ const receipt = record(value)?.["runId"];
44
+ if (typeof receipt !== "string")
45
+ return new Response("invalid-workflow-message", { status: 400 });
46
+ const run = (await ports.run(receipt)) ??
47
+ seeded(value) ??
48
+ (await located(ports, receipt));
49
+ if (run === undefined)
50
+ return new Response("unknown-world-run", { status: 503 });
51
+ const available = await ports.available(run.runId, run.workflowId);
52
+ if (!(await observedReplay(ports, { runId: run.runId, receipt, available })))
53
+ return new Response("workflow-observation-unavailable", { status: 503 });
54
+ if (available)
55
+ return handler(request, run.runId);
56
+ return new Response("pinned-workflow-unavailable", { status: 503 });
57
+ };
58
+ }