cloving 1.2.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 (518) hide show
  1. package/README.md +525 -185
  2. package/dist/src/agent-harness-shell.d.ts +12 -0
  3. package/dist/src/agent-harness-shell.js +90 -0
  4. package/dist/src/agent-harness-versions.d.ts +8 -0
  5. package/dist/src/agent-harness-versions.js +49 -0
  6. package/dist/src/agent-harnesses.d.ts +4 -0
  7. package/dist/src/agent-harnesses.js +13 -0
  8. package/dist/src/authority/commands.d.ts +1 -0
  9. package/dist/src/authority/commands.js +24 -4
  10. package/dist/src/authority/gate-reduction.d.ts +1 -0
  11. package/dist/src/authority/gate-reduction.js +18 -3
  12. package/dist/src/authority/gates.d.ts +2 -1
  13. package/dist/src/authority/gates.js +5 -1
  14. package/dist/src/authority/operations.js +1 -1
  15. package/dist/src/authority/reduction.d.ts +1 -1
  16. package/dist/src/authority/reduction.js +6 -1
  17. package/dist/src/authority/status-input.d.ts +1 -1
  18. package/dist/src/authority/status.d.ts +1 -0
  19. package/dist/src/authority/status.js +27 -3
  20. package/dist/src/authority/transitions.d.ts +5 -5
  21. package/dist/src/authority/transitions.js +6 -0
  22. package/dist/src/broker/actor/authority-delivery.js +1 -0
  23. package/dist/src/broker/actor/authority-queries.d.ts +7 -1
  24. package/dist/src/broker/actor/authority-queries.js +17 -2
  25. package/dist/src/broker/actor/authority-receipts.js +11 -1
  26. package/dist/src/broker/actor/authority-session.js +2 -2
  27. package/dist/src/broker/actor/authority-settings.js +4 -0
  28. package/dist/src/broker/actor/delivery-intents.d.ts +2 -1
  29. package/dist/src/broker/actor/delivery-intents.js +4 -4
  30. package/dist/src/broker/actor/effect-delivery.js +4 -1
  31. package/dist/src/broker/actor/effect-queries.d.ts +1 -0
  32. package/dist/src/broker/actor/effect-queries.js +7 -0
  33. package/dist/src/broker/actor/pin-check.js +1 -1
  34. package/dist/src/broker/actor/stop-plan.js +1 -1
  35. package/dist/src/broker/actor/turn-state.js +1 -1
  36. package/dist/src/broker/authority-admission.js +22 -9
  37. package/dist/src/broker/authority-restore.js +1 -0
  38. package/dist/src/broker/decision-restore.js +4 -4
  39. package/dist/src/broker/socket-address.d.ts +3 -1
  40. package/dist/src/broker/socket-address.js +2 -2
  41. package/dist/src/cli/arguments.d.ts +11 -13
  42. package/dist/src/cli/arguments.js +37 -107
  43. package/dist/src/cli/command-effects.d.ts +7 -0
  44. package/dist/src/cli/command-effects.js +39 -0
  45. package/dist/src/cli/commands.js +11 -4
  46. package/dist/src/cli/config-arguments.d.ts +11 -0
  47. package/dist/src/cli/config-arguments.js +59 -0
  48. package/dist/src/cli/config-command.d.ts +2 -0
  49. package/dist/src/cli/config-command.js +105 -0
  50. package/dist/src/cli/config-file.d.ts +3 -0
  51. package/dist/src/cli/config-file.js +50 -0
  52. package/dist/src/cli/config-lock.d.ts +7 -0
  53. package/dist/src/cli/config-lock.js +61 -0
  54. package/dist/src/cli/config-notice.d.ts +5 -0
  55. package/dist/src/cli/config-notice.js +46 -0
  56. package/dist/src/cli/doctor-github.d.ts +9 -0
  57. package/dist/src/cli/doctor-github.js +138 -0
  58. package/dist/src/cli/doctor-harness.d.ts +13 -0
  59. package/dist/src/cli/doctor-harness.js +242 -0
  60. package/dist/src/cli/doctor-local.d.ts +18 -0
  61. package/dist/src/cli/doctor-local.js +77 -0
  62. package/dist/src/cli/doctor-runtime.d.ts +15 -0
  63. package/dist/src/cli/doctor-runtime.js +176 -0
  64. package/dist/src/cli/doctor-service.d.ts +1 -0
  65. package/dist/src/cli/doctor-service.js +11 -0
  66. package/dist/src/cli/doctor-workflows.d.ts +3 -0
  67. package/dist/src/cli/doctor-workflows.js +45 -0
  68. package/dist/src/cli/doctor.d.ts +15 -0
  69. package/dist/src/cli/doctor.js +190 -0
  70. package/dist/src/cli/github-ci-progress.d.ts +8 -0
  71. package/dist/src/cli/github-ci-progress.js +83 -0
  72. package/dist/src/cli/github-retry.d.ts +6 -0
  73. package/dist/src/cli/github-retry.js +47 -0
  74. package/dist/src/cli/harness-probes.d.ts +22 -0
  75. package/dist/src/cli/harness-probes.js +183 -0
  76. package/dist/src/cli/main.d.ts +7 -1
  77. package/dist/src/cli/main.js +39 -61
  78. package/dist/src/cli/phone-arguments.d.ts +14 -0
  79. package/dist/src/cli/phone-arguments.js +37 -0
  80. package/dist/src/cli/phone-client.d.ts +2 -0
  81. package/dist/src/cli/phone-client.js +32 -0
  82. package/dist/src/cli/phone-command.d.ts +13 -0
  83. package/dist/src/cli/phone-command.js +101 -0
  84. package/dist/src/cli/probe-command.d.ts +36 -0
  85. package/dist/src/cli/probe-command.js +59 -0
  86. package/dist/src/cli/project-settings.d.ts +4 -0
  87. package/dist/src/cli/project-settings.js +33 -0
  88. package/dist/src/cli/render.d.ts +2 -1
  89. package/dist/src/cli/render.js +44 -28
  90. package/dist/src/cli/report-github.d.ts +18 -0
  91. package/dist/src/cli/report-github.js +200 -0
  92. package/dist/src/cli/report.d.ts +17 -0
  93. package/dist/src/cli/report.js +192 -0
  94. package/dist/src/cli/repository-arguments.d.ts +5 -0
  95. package/dist/src/cli/repository-arguments.js +34 -0
  96. package/dist/src/cli/runtime-arguments.d.ts +4 -0
  97. package/dist/src/cli/runtime-arguments.js +15 -0
  98. package/dist/src/cli/runtime-directory.d.ts +6 -2
  99. package/dist/src/cli/runtime-directory.js +72 -14
  100. package/dist/src/cli/toolchain.d.ts +2 -0
  101. package/dist/src/cli/toolchain.js +22 -2
  102. package/dist/src/cli/usage-render.d.ts +5 -0
  103. package/dist/src/cli/usage-render.js +40 -1
  104. package/dist/src/cli/usage.d.ts +3 -3
  105. package/dist/src/cli/usage.js +70 -44
  106. package/dist/src/cli/watch-actions.d.ts +2 -0
  107. package/dist/src/cli/watch-actions.js +4 -4
  108. package/dist/src/cli/watch-board-view.d.ts +1 -1
  109. package/dist/src/cli/watch-board-view.js +8 -2
  110. package/dist/src/cli/watch-board.js +23 -10
  111. package/dist/src/cli/watch-card-forms.js +2 -2
  112. package/dist/src/cli/watch-client.d.ts +1 -1
  113. package/dist/src/cli/watch-client.js +7 -2
  114. package/dist/src/cli/watch-header-view.d.ts +27 -0
  115. package/dist/src/cli/watch-header-view.js +116 -0
  116. package/dist/src/cli/watch-model.js +17 -4
  117. package/dist/src/cli/watch-page.js +48 -12
  118. package/dist/src/cli/watch-phone-client.d.ts +1 -0
  119. package/dist/src/cli/watch-phone-client.js +84 -0
  120. package/dist/src/cli/watch-phone-view.d.ts +56 -0
  121. package/dist/src/cli/watch-phone-view.js +113 -0
  122. package/dist/src/cli/watch-phone.d.ts +5 -0
  123. package/dist/src/cli/watch-phone.js +53 -0
  124. package/dist/src/cli/watch-pull-request.d.ts +3 -1
  125. package/dist/src/cli/watch-pull-request.js +4 -0
  126. package/dist/src/cli/watch-render.d.ts +9 -1
  127. package/dist/src/cli/watch-server.js +23 -5
  128. package/dist/src/cli/watch-turn.d.ts +4 -1
  129. package/dist/src/cli/watch-turn.js +37 -1
  130. package/dist/src/cli/watch-usage.js +5 -1
  131. package/dist/src/cli/watch-view.d.ts +6 -20
  132. package/dist/src/cli/watch-view.js +14 -106
  133. package/dist/src/cli.js +106 -23
  134. package/dist/src/command-settings.d.ts +16 -0
  135. package/dist/src/command-settings.js +42 -0
  136. package/dist/src/configuration-change.d.ts +11 -0
  137. package/dist/src/configuration-change.js +62 -0
  138. package/dist/src/configuration-display.d.ts +21 -0
  139. package/dist/src/configuration-display.js +69 -0
  140. package/dist/src/configuration-schema.d.ts +49 -0
  141. package/dist/src/configuration-schema.js +159 -0
  142. package/dist/src/daemon/claude-turn.d.ts +19 -5
  143. package/dist/src/daemon/claude-turn.js +116 -53
  144. package/dist/src/daemon/claude-worker.d.ts +3 -3
  145. package/dist/src/daemon/claude-worker.js +65 -76
  146. package/dist/src/daemon/command-journal.d.ts +5 -0
  147. package/dist/src/daemon/command-journal.js +50 -0
  148. package/dist/src/daemon/command-process.d.ts +28 -0
  149. package/dist/src/daemon/command-process.js +164 -0
  150. package/dist/src/daemon/command-worker.d.ts +19 -0
  151. package/dist/src/daemon/command-worker.js +182 -0
  152. package/dist/src/daemon/cursor-stream.d.ts +4 -0
  153. package/dist/src/daemon/cursor-stream.js +154 -0
  154. package/dist/src/daemon/daemon-adapters.d.ts +58 -0
  155. package/dist/src/daemon/daemon-adapters.js +102 -0
  156. package/dist/src/daemon/daemon-loops.d.ts +14 -0
  157. package/dist/src/daemon/daemon-loops.js +39 -0
  158. package/dist/src/daemon/daemon.d.ts +2 -33
  159. package/dist/src/daemon/daemon.js +126 -132
  160. package/dist/src/daemon/declared-input.d.ts +3 -0
  161. package/dist/src/daemon/declared-input.js +9 -0
  162. package/dist/src/daemon/delivery-router.js +1 -1
  163. package/dist/src/daemon/gemini-stream.d.ts +4 -0
  164. package/dist/src/daemon/gemini-stream.js +129 -0
  165. package/dist/src/daemon/github-ci-rerun.d.ts +26 -0
  166. package/dist/src/daemon/github-ci-rerun.js +92 -0
  167. package/dist/src/daemon/github-ci.js +89 -8
  168. package/dist/src/daemon/github-merge-call.d.ts +2 -0
  169. package/dist/src/daemon/github-merge.js +7 -3
  170. package/dist/src/daemon/github-methods.js +10 -0
  171. package/dist/src/daemon/github-operation.d.ts +1 -0
  172. package/dist/src/daemon/github-retry.js +8 -44
  173. package/dist/src/daemon/issue-queue.d.ts +1 -0
  174. package/dist/src/daemon/issue-queue.js +3 -26
  175. package/dist/src/daemon/notify.js +2 -1
  176. package/dist/src/daemon/opencode-stream.d.ts +5 -0
  177. package/dist/src/daemon/opencode-stream.js +87 -0
  178. package/dist/src/daemon/queue-status.d.ts +4 -0
  179. package/dist/src/daemon/queue-status.js +38 -0
  180. package/dist/src/daemon/retry-worktree.d.ts +18 -0
  181. package/dist/src/daemon/retry-worktree.js +139 -0
  182. package/dist/src/daemon/retrying-turn.d.ts +2 -0
  183. package/dist/src/daemon/retrying-turn.js +108 -30
  184. package/dist/src/daemon/schedule-journal.d.ts +19 -0
  185. package/dist/src/daemon/schedule-journal.js +57 -0
  186. package/dist/src/daemon/text-output.d.ts +18 -0
  187. package/dist/src/daemon/text-output.js +44 -0
  188. package/dist/src/daemon/ticket-registration.d.ts +5 -7
  189. package/dist/src/daemon/ticket-registration.js +85 -40
  190. package/dist/src/daemon/turn-command.d.ts +10 -0
  191. package/dist/src/daemon/turn-command.js +33 -0
  192. package/dist/src/daemon/turn-report.d.ts +18 -0
  193. package/dist/src/daemon/turn-report.js +79 -0
  194. package/dist/src/daemon/work-tree.d.ts +2 -1
  195. package/dist/src/daemon/work-tree.js +15 -12
  196. package/dist/src/daemon/workflow-generations.d.ts +32 -0
  197. package/dist/src/daemon/workflow-generations.js +57 -0
  198. package/dist/src/daemon/workflow-replay.d.ts +16 -0
  199. package/dist/src/daemon/workflow-replay.js +58 -0
  200. package/dist/src/daemon/workflow-schedules.d.ts +27 -0
  201. package/dist/src/daemon/workflow-schedules.js +185 -0
  202. package/dist/src/decision-wait.d.ts +1 -0
  203. package/dist/src/decision-wait.js +3 -0
  204. package/dist/src/delivery-backoff.d.ts +1 -0
  205. package/dist/src/delivery-backoff.js +3 -0
  206. package/dist/src/doctor-report.d.ts +24 -0
  207. package/dist/src/doctor-report.js +70 -0
  208. package/dist/src/execution-pin.d.ts +5 -0
  209. package/dist/src/execution-pin.js +67 -4
  210. package/dist/src/grok-result.d.ts +12 -0
  211. package/dist/src/grok-result.js +61 -0
  212. package/dist/src/harness-defaults.d.ts +35 -0
  213. package/dist/src/harness-defaults.js +121 -0
  214. package/dist/src/host/decision-resume.d.ts +35 -0
  215. package/dist/src/host/decision-resume.js +86 -0
  216. package/dist/src/host/gate-bridge.d.ts +48 -0
  217. package/dist/src/host/gate-bridge.js +124 -0
  218. package/dist/src/host/run-wait.d.ts +26 -0
  219. package/dist/src/host/run-wait.js +37 -0
  220. package/dist/src/host/start-delivery.d.ts +1 -1
  221. package/dist/src/host/start-delivery.js +10 -3
  222. package/dist/src/host/step-bridge-host.d.ts +6 -20
  223. package/dist/src/host/step-bridge-host.js +44 -58
  224. package/dist/src/merge-request.d.ts +19 -0
  225. package/dist/src/merge-request.js +32 -0
  226. package/dist/src/phone/canonical-json.d.ts +1 -0
  227. package/dist/src/phone/canonical-json.js +16 -0
  228. package/dist/src/phone/phone-link.d.ts +7 -0
  229. package/dist/src/phone/phone-link.js +21 -0
  230. package/dist/src/phone/qr-data.d.ts +8 -0
  231. package/dist/src/phone/qr-data.js +133 -0
  232. package/dist/src/phone/qr-matrix.d.ts +6 -0
  233. package/dist/src/phone/qr-matrix.js +175 -0
  234. package/dist/src/phone/qr-penalty.d.ts +3 -0
  235. package/dist/src/phone/qr-penalty.js +67 -0
  236. package/dist/src/phone/qr-picture.d.ts +5 -0
  237. package/dist/src/phone/qr-picture.js +24 -0
  238. package/dist/src/private-config.schema.json +263 -0
  239. package/dist/src/project-config.schema.json +65 -0
  240. package/dist/src/project-settings.d.ts +19 -0
  241. package/dist/src/project-settings.js +131 -0
  242. package/dist/src/relay/answer-check.d.ts +24 -0
  243. package/dist/src/relay/answer-check.js +145 -0
  244. package/dist/src/relay/answer-inbox.d.ts +15 -0
  245. package/dist/src/relay/answer-inbox.js +173 -0
  246. package/dist/src/relay/daemon-keys.d.ts +16 -0
  247. package/dist/src/relay/daemon-keys.js +75 -0
  248. package/dist/src/relay/decision-check.d.ts +3 -0
  249. package/dist/src/relay/decision-check.js +77 -0
  250. package/dist/src/relay/decision-close.d.ts +6 -0
  251. package/dist/src/relay/decision-close.js +72 -0
  252. package/dist/src/relay/decision-envelopes.d.ts +29 -0
  253. package/dist/src/relay/decision-envelopes.js +93 -0
  254. package/dist/src/relay/decision-watch.d.ts +14 -0
  255. package/dist/src/relay/decision-watch.js +68 -0
  256. package/dist/src/relay/envelope-post.d.ts +8 -0
  257. package/dist/src/relay/envelope-post.js +71 -0
  258. package/dist/src/relay/envelope.d.ts +28 -0
  259. package/dist/src/relay/envelope.js +53 -0
  260. package/dist/src/relay/hpke.d.ts +25 -0
  261. package/dist/src/relay/hpke.js +108 -0
  262. package/dist/src/relay/pairing-checks.d.ts +42 -0
  263. package/dist/src/relay/pairing-checks.js +172 -0
  264. package/dist/src/relay/pairing-follow.d.ts +8 -0
  265. package/dist/src/relay/pairing-follow.js +95 -0
  266. package/dist/src/relay/pairing-session.d.ts +29 -0
  267. package/dist/src/relay/pairing-session.js +87 -0
  268. package/dist/src/relay/phone-delivery.d.ts +51 -0
  269. package/dist/src/relay/phone-delivery.js +139 -0
  270. package/dist/src/relay/phone-devices.d.ts +36 -0
  271. package/dist/src/relay/phone-devices.js +46 -0
  272. package/dist/src/relay/phone-inbox.d.ts +18 -0
  273. package/dist/src/relay/phone-inbox.js +17 -0
  274. package/dist/src/relay/phone-operations.d.ts +18 -0
  275. package/dist/src/relay/phone-operations.js +121 -0
  276. package/dist/src/relay/phone-outbox.d.ts +21 -0
  277. package/dist/src/relay/phone-outbox.js +25 -0
  278. package/dist/src/relay/phone-socket.d.ts +6 -0
  279. package/dist/src/relay/phone-socket.js +63 -0
  280. package/dist/src/relay/relay-control.d.ts +7 -0
  281. package/dist/src/relay/relay-control.js +24 -0
  282. package/dist/src/relay/relay-files.d.ts +2 -0
  283. package/dist/src/relay/relay-files.js +23 -0
  284. package/dist/src/relay/relay-heartbeat.d.ts +17 -0
  285. package/dist/src/relay/relay-heartbeat.js +81 -0
  286. package/dist/src/relay/relay-http.d.ts +14 -0
  287. package/dist/src/relay/relay-http.js +63 -0
  288. package/dist/src/relay/relay-registration.d.ts +15 -0
  289. package/dist/src/relay/relay-registration.js +63 -0
  290. package/dist/src/relay/relay-service.d.ts +25 -0
  291. package/dist/src/relay/relay-service.js +216 -0
  292. package/dist/src/relay/relay-store.d.ts +48 -0
  293. package/dist/src/relay/relay-store.js +131 -0
  294. package/dist/src/relay/sealed-post.d.ts +25 -0
  295. package/dist/src/relay/sealed-post.js +52 -0
  296. package/dist/src/relay.d.ts +1 -0
  297. package/dist/src/relay.js +8 -0
  298. package/dist/src/report-statistics.d.ts +50 -0
  299. package/dist/src/report-statistics.js +70 -0
  300. package/dist/src/report.d.ts +171 -0
  301. package/dist/src/report.js +119 -0
  302. package/dist/src/repository-identity.d.ts +4 -0
  303. package/dist/src/repository-identity.js +4 -0
  304. package/dist/src/review-subject.d.ts +41 -0
  305. package/dist/src/review-subject.js +91 -0
  306. package/dist/src/run-wait.d.ts +23 -0
  307. package/dist/src/run-wait.js +20 -0
  308. package/dist/src/service/active-tickets.d.ts +4 -0
  309. package/dist/src/service/active-tickets.js +49 -0
  310. package/dist/src/service/command-effects.d.ts +4 -0
  311. package/dist/src/service/command-effects.js +16 -0
  312. package/dist/src/service/decision-handler.d.ts +4 -0
  313. package/dist/src/service/decision-handler.js +39 -4
  314. package/dist/src/service/gateway.js +18 -3
  315. package/dist/src/service/registry.d.ts +16 -3
  316. package/dist/src/service/registry.js +34 -3
  317. package/dist/src/service/replies.d.ts +9 -1
  318. package/dist/src/service/replies.js +12 -0
  319. package/dist/src/service/run-handlers.js +14 -55
  320. package/dist/src/service/run-metadata.d.ts +8 -0
  321. package/dist/src/service/run-metadata.js +53 -0
  322. package/dist/src/service/run-waits.d.ts +3 -0
  323. package/dist/src/service/run-waits.js +41 -0
  324. package/dist/src/service/service.d.ts +18 -2
  325. package/dist/src/service/service.js +23 -7
  326. package/dist/src/service/submission-handler.d.ts +0 -1
  327. package/dist/src/service/submission-handler.js +6 -34
  328. package/dist/src/service/worker-port.d.ts +1 -0
  329. package/dist/src/service/worker-totals.js +8 -23
  330. package/dist/src/step-bridge.d.ts +23 -0
  331. package/dist/src/steps/decision-gate.d.ts +2 -1
  332. package/dist/src/steps/decision-gate.js +7 -0
  333. package/dist/src/steps/merge-by-person.d.ts +2 -0
  334. package/dist/src/steps/merge-by-person.js +18 -0
  335. package/dist/src/steps/merge-when-green.d.ts +2 -0
  336. package/dist/src/steps/merge-when-green.js +62 -0
  337. package/dist/src/steps/review-by-agent.d.ts +5 -0
  338. package/dist/src/steps/review-by-agent.js +124 -0
  339. package/dist/src/steps/review-by-person.d.ts +4 -0
  340. package/dist/src/steps/review-by-person.js +16 -0
  341. package/dist/src/steps/review-subject.d.ts +2 -0
  342. package/dist/src/steps/review-subject.js +11 -0
  343. package/dist/src/steps/run-command.d.ts +2 -0
  344. package/dist/src/steps/run-command.js +15 -0
  345. package/dist/src/steps/sleep.d.ts +3 -0
  346. package/dist/src/steps/sleep.js +19 -0
  347. package/dist/src/steps/wait-for-decision.d.ts +2 -0
  348. package/dist/src/steps/wait-for-decision.js +71 -0
  349. package/dist/src/steps/wait-for-run.d.ts +5 -0
  350. package/dist/src/steps/wait-for-run.js +9 -0
  351. package/dist/src/storage/decision-snapshots.d.ts +1 -0
  352. package/dist/src/storage/decision-snapshots.js +7 -1
  353. package/dist/src/submission.d.ts +4 -0
  354. package/dist/src/submission.js +6 -2
  355. package/dist/src/testing.d.ts +29 -0
  356. package/dist/src/testing.js +264 -0
  357. package/dist/src/ticket-status-stream.d.ts +9 -0
  358. package/dist/src/ticket-status-stream.js +94 -0
  359. package/dist/src/token-prices.d.ts +12 -4
  360. package/dist/src/token-prices.js +15 -2
  361. package/dist/src/turn-profile.d.ts +1 -0
  362. package/dist/src/turn-profile.js +8 -1
  363. package/dist/src/worker-usage.d.ts +16 -0
  364. package/dist/src/worker-usage.js +57 -0
  365. package/dist/src/workflow-admission.d.ts +5 -0
  366. package/dist/src/workflow-candidate.d.ts +7 -2
  367. package/dist/src/workflow-candidate.js +47 -5
  368. package/dist/src/workflow-declaration.d.ts +21 -3
  369. package/dist/src/workflow-declaration.js +77 -9
  370. package/dist/src/workflow-discovery.d.ts +2 -1
  371. package/dist/src/workflow-discovery.js +4 -1
  372. package/dist/src/workflow-refusals.js +3 -0
  373. package/dist/src/workflow-schedule.d.ts +22 -0
  374. package/dist/src/workflow-schedule.js +53 -0
  375. package/dist/src/workflows.d.ts +11 -1
  376. package/dist/src/workflows.js +8 -0
  377. package/dist/tools/admit-workflow.d.ts +1 -0
  378. package/dist/tools/admit-workflow.js +18 -5
  379. package/dist/tools/doctor-adoption.d.ts +1 -0
  380. package/dist/tools/doctor-adoption.js +11 -0
  381. package/dist/tools/project-configuration.d.ts +4 -0
  382. package/dist/tools/project-configuration.js +47 -0
  383. package/dist/tools/self-host-processes.d.ts +1 -0
  384. package/dist/tools/self-host-processes.js +33 -22
  385. package/dist/tools/self-host-project.d.ts +4 -0
  386. package/dist/tools/self-host-project.js +61 -14
  387. package/dist/tools/self-host-runtime.d.ts +16 -0
  388. package/dist/tools/self-host-runtime.js +60 -0
  389. package/dist/tools/self-host-workflows.d.ts +1 -0
  390. package/dist/tools/self-host-workflows.js +36 -1
  391. package/dist/tools/self-host.js +86 -61
  392. package/dist/tools/workflow-candidate-counts.d.ts +6 -2
  393. package/dist/tools/workflow-candidate-counts.js +31 -16
  394. package/dist/tools/workflow-candidate-fields.d.ts +5 -0
  395. package/dist/tools/workflow-candidate-fields.js +24 -0
  396. package/dist/tools/workflow-candidate-helper-counts.d.ts +10 -0
  397. package/dist/tools/workflow-candidate-helper-counts.js +129 -0
  398. package/dist/tools/workflow-candidate-program.d.ts +2 -0
  399. package/dist/tools/workflow-candidate-program.js +36 -8
  400. package/dist/tools/workflow-candidate-source.js +77 -15
  401. package/dist/tools/workflow-candidate-syntax.d.ts +8 -2
  402. package/dist/tools/workflow-candidate-syntax.js +70 -26
  403. package/dist/tools/workflow-command.d.ts +1 -0
  404. package/dist/tools/workflow-command.js +143 -0
  405. package/dist/tools/workflow-folder-capture.d.ts +1 -0
  406. package/dist/tools/workflow-folder-capture.js +47 -2
  407. package/dist/tools/workflow-folders.d.ts +17 -1
  408. package/dist/tools/workflow-folders.js +59 -6
  409. package/dist/tools/workflow-test-hook.d.ts +7 -0
  410. package/dist/tools/workflow-test-hook.js +16 -0
  411. package/dist/tools/workflow-test-loader.d.ts +1 -0
  412. package/dist/tools/workflow-test-loader.js +10 -0
  413. package/dist/workflows/develop-ticket.js +1 -1
  414. package/dist/workflows/ticket-prompts.js +5 -1
  415. package/package.json +46 -4
  416. package/templates/develop/README.md +78 -0
  417. package/templates/develop/develop/accept.ts +11 -0
  418. package/templates/develop/develop/flow-tests.ts +357 -0
  419. package/templates/develop/develop/local.ts +40 -0
  420. package/templates/develop/develop/option-tests.ts +174 -0
  421. package/templates/develop/develop/partial-choice.ts +29 -0
  422. package/templates/develop/develop/partial.ts +28 -0
  423. package/templates/develop/develop/pull.ts +152 -0
  424. package/templates/develop/develop/queue-partial.ts +39 -0
  425. package/templates/develop/develop/refusal-tests.ts +174 -0
  426. package/templates/develop/develop/report.ts +156 -0
  427. package/templates/develop/develop/round.ts +40 -0
  428. package/templates/develop/develop/scenarios.ts +87 -0
  429. package/templates/develop/develop/turn.ts +67 -0
  430. package/templates/develop/develop.declaration.json +24 -0
  431. package/templates/develop/develop.test.ts +287 -0
  432. package/templates/develop/develop.ts +30 -0
  433. package/templates/develop/template.json +153 -0
  434. package/dist/src/chats/analysis-batches.d.ts +0 -42
  435. package/dist/src/chats/analysis-batches.js +0 -97
  436. package/dist/src/chats/analysis-checkpoint.d.ts +0 -29
  437. package/dist/src/chats/analysis-checkpoint.js +0 -31
  438. package/dist/src/chats/analysis-contract.d.ts +0 -80
  439. package/dist/src/chats/analysis-contract.js +0 -16
  440. package/dist/src/chats/analysis-data.d.ts +0 -3
  441. package/dist/src/chats/analysis-data.js +0 -85
  442. package/dist/src/chats/analysis-input.d.ts +0 -18
  443. package/dist/src/chats/analysis-input.js +0 -97
  444. package/dist/src/chats/analysis-links.d.ts +0 -2
  445. package/dist/src/chats/analysis-links.js +0 -25
  446. package/dist/src/chats/analysis-merge.d.ts +0 -16
  447. package/dist/src/chats/analysis-merge.js +0 -134
  448. package/dist/src/chats/analysis-prompt.d.ts +0 -18
  449. package/dist/src/chats/analysis-prompt.js +0 -42
  450. package/dist/src/chats/analysis-proposal.d.ts +0 -4
  451. package/dist/src/chats/analysis-proposal.js +0 -41
  452. package/dist/src/chats/analysis-provenance.d.ts +0 -4
  453. package/dist/src/chats/analysis-provenance.js +0 -99
  454. package/dist/src/chats/analysis-shape.d.ts +0 -4
  455. package/dist/src/chats/analysis-shape.js +0 -235
  456. package/dist/src/chats/analysis.d.ts +0 -3
  457. package/dist/src/chats/analysis.js +0 -42
  458. package/dist/src/chats/corpus-input.d.ts +0 -5
  459. package/dist/src/chats/corpus-input.js +0 -288
  460. package/dist/src/chats/destination.d.ts +0 -4
  461. package/dist/src/chats/destination.js +0 -96
  462. package/dist/src/chats/import.d.ts +0 -15
  463. package/dist/src/chats/import.js +0 -243
  464. package/dist/src/chats/input-file.d.ts +0 -3
  465. package/dist/src/chats/input-file.js +0 -32
  466. package/dist/src/chats/normalize.d.ts +0 -29
  467. package/dist/src/chats/normalize.js +0 -155
  468. package/dist/src/chats/previous-import.d.ts +0 -5
  469. package/dist/src/chats/previous-import.js +0 -34
  470. package/dist/src/chats/reader.d.ts +0 -21
  471. package/dist/src/chats/reader.js +0 -118
  472. package/dist/src/chats/redact-import.d.ts +0 -14
  473. package/dist/src/chats/redact-import.js +0 -141
  474. package/dist/src/chats/redaction.d.ts +0 -41
  475. package/dist/src/chats/redaction.js +0 -161
  476. package/dist/src/chats/reference-mapping.d.ts +0 -16
  477. package/dist/src/chats/reference-mapping.js +0 -153
  478. package/dist/src/chats/revision-input.d.ts +0 -3
  479. package/dist/src/chats/revision-input.js +0 -180
  480. package/dist/src/chats/revision.d.ts +0 -48
  481. package/dist/src/chats/revision.js +0 -94
  482. package/dist/src/chats/selection.d.ts +0 -25
  483. package/dist/src/chats/selection.js +0 -109
  484. package/dist/src/chats/source.d.ts +0 -23
  485. package/dist/src/chats/source.js +0 -135
  486. package/dist/src/chats/structure.d.ts +0 -57
  487. package/dist/src/chats/structure.js +0 -216
  488. package/dist/src/chats/workflow-generation-projection.d.ts +0 -8
  489. package/dist/src/chats/workflow-generation-projection.js +0 -75
  490. package/dist/src/chats/workflow-generation-source.d.ts +0 -25
  491. package/dist/src/chats/workflow-generation-source.js +0 -124
  492. package/dist/src/chats/workflow-generation-text.d.ts +0 -23
  493. package/dist/src/chats/workflow-generation-text.js +0 -74
  494. package/dist/src/chats/workflow-generation.d.ts +0 -69
  495. package/dist/src/chats/workflow-generation.js +0 -142
  496. package/dist/src/daemon/analysis-launch.d.ts +0 -5
  497. package/dist/src/daemon/analysis-launch.js +0 -81
  498. package/dist/src/daemon/analysis-token.d.ts +0 -6
  499. package/dist/src/daemon/analysis-token.js +0 -88
  500. package/dist/src/daemon/analysis-worker.d.ts +0 -20
  501. package/dist/src/daemon/analysis-worker.js +0 -271
  502. package/dist/src/daemon/chats-batch-binding.d.ts +0 -23
  503. package/dist/src/daemon/chats-batch-binding.js +0 -99
  504. package/dist/src/daemon/chats-capture.d.ts +0 -18
  505. package/dist/src/daemon/chats-capture.js +0 -194
  506. package/dist/src/daemon/chats-checkpoints.d.ts +0 -41
  507. package/dist/src/daemon/chats-checkpoints.js +0 -186
  508. package/dist/src/daemon/chats-files.d.ts +0 -42
  509. package/dist/src/daemon/chats-files.js +0 -252
  510. package/dist/src/daemon/chats-follow-up.d.ts +0 -38
  511. package/dist/src/daemon/chats-follow-up.js +0 -180
  512. package/dist/src/daemon/chats-question.d.ts +0 -15
  513. package/dist/src/daemon/chats-question.js +0 -93
  514. package/dist/src/daemon/chats-worker.d.ts +0 -13
  515. package/dist/src/daemon/chats-worker.js +0 -201
  516. package/dist/workflows/analyze-chats.d.ts +0 -15
  517. package/dist/workflows/analyze-chats.declaration.json +0 -22
  518. package/dist/workflows/analyze-chats.js +0 -250
@@ -0,0 +1,185 @@
1
+ import { join } from "node:path";
2
+ import { setTimeout as delay } from "node:timers/promises";
3
+ import { mutate } from "../cli/client.js";
4
+ import { record } from "../protocol.js";
5
+ import { runIdentity } from "../service/submission-handler.js";
6
+ import { configuredSchedules } from "../workflow-schedule.js";
7
+ import { declaredInput } from "./declared-input.js";
8
+ import { scheduleJournal, } from "./schedule-journal.js";
9
+ export function scheduledDeclarations(settings, limits) {
10
+ try {
11
+ const declarations = settings.declarations ?? [];
12
+ const configured = configuredSchedules(declarations, settings.schedules === undefined ? {} : settings.schedules);
13
+ if (limits !== undefined &&
14
+ Object.entries(configured).some(([workflowId, schedule]) => Buffer.byteLength(JSON.stringify(declaredInput(limits.repository, {
15
+ commandId: commandId(workflowId, 1),
16
+ submission: schedule.input,
17
+ }))) > limits.documentBytes))
18
+ throw new Error("invalid-schedule-input");
19
+ return {
20
+ kind: "configured",
21
+ declarations: declarations.map((entry) => {
22
+ const schedule = Object.hasOwn(configured, entry.workflowId)
23
+ ? configured[entry.workflowId]
24
+ : undefined;
25
+ return schedule === undefined ? entry : { ...entry, schedule };
26
+ }),
27
+ };
28
+ }
29
+ catch (error) {
30
+ return {
31
+ kind: "refused",
32
+ reason: "schedule-rejected",
33
+ detail: String(error),
34
+ };
35
+ }
36
+ }
37
+ function commandId(workflowId, slot) {
38
+ return `schedule:${workflowId}:${String(slot)}`;
39
+ }
40
+ async function request(settings, request) {
41
+ const interrupted = Promise.withResolvers();
42
+ const interrupt = () => {
43
+ interrupted.resolve(undefined);
44
+ };
45
+ settings.signal.addEventListener("abort", interrupt, { once: true });
46
+ try {
47
+ settings.signal.throwIfAborted();
48
+ return await mutate(settings.runtimeDirectory, {
49
+ request,
50
+ signal: interrupted.promise,
51
+ });
52
+ }
53
+ finally {
54
+ settings.signal.removeEventListener("abort", interrupt);
55
+ }
56
+ }
57
+ async function pending(settings, entry) {
58
+ settings.signal.throwIfAborted();
59
+ const { workflowId, progress } = entry;
60
+ const { pending: planned, ...rest } = progress;
61
+ if (planned === undefined)
62
+ return progress;
63
+ const identity = commandId(workflowId, progress.lastSlot);
64
+ if (planned.kind === "skip") {
65
+ const receipt = await settings.submit({
66
+ kind: "record-schedule-skip",
67
+ commandId: `skip:${identity}`,
68
+ runId: planned.runId,
69
+ workflowId,
70
+ slot: progress.lastSlot,
71
+ });
72
+ if (receipt.kind !== "accepted" && receipt.kind !== "duplicate")
73
+ throw new Error("schedule-skip-not-recorded");
74
+ return rest;
75
+ }
76
+ const reply = await request(settings, {
77
+ operation: "run",
78
+ parameters: {
79
+ workflowId,
80
+ source: "declared",
81
+ submission: planned.input,
82
+ commandId: identity,
83
+ },
84
+ });
85
+ if (reply.kind === "error")
86
+ throw new Error(reply.error.code);
87
+ return { ...rest, activeCommandId: identity };
88
+ }
89
+ async function active(settings, progress) {
90
+ if (progress.activeCommandId === undefined)
91
+ return undefined;
92
+ const runId = runIdentity(progress.activeCommandId);
93
+ const reply = await request(settings, {
94
+ operation: "status",
95
+ parameters: { runId },
96
+ });
97
+ if (reply.kind === "error")
98
+ throw new Error(reply.error.code);
99
+ const run = record(reply.result["run"]);
100
+ if (typeof run?.["state"] !== "string")
101
+ throw new Error("invalid-schedule-run");
102
+ if (run["condition"] === "cancelling")
103
+ return runId;
104
+ return ["completed", "failed", "cancelled"].includes(run["state"])
105
+ ? undefined
106
+ : runId;
107
+ }
108
+ async function tick(settings, journal) {
109
+ const now = (settings.scheduleClock ?? Date.now)();
110
+ for (const declaration of settings.declarations ?? []) {
111
+ settings.signal.throwIfAborted();
112
+ const { workflowId, schedule } = declaration;
113
+ if (schedule === undefined)
114
+ continue;
115
+ let progress = journal.entries.get(workflowId);
116
+ if (progress === undefined)
117
+ throw new Error("missing-schedule-state");
118
+ if (progress.pending !== undefined) {
119
+ progress = await pending(settings, { workflowId, progress });
120
+ journal.entries.set(workflowId, progress);
121
+ await journal.save();
122
+ }
123
+ if (now < progress.nextAt)
124
+ continue;
125
+ const runId = await active(settings, progress);
126
+ const planned = runId === undefined
127
+ ? { kind: "run", input: schedule.input }
128
+ : { kind: "skip", runId };
129
+ const elapsed = Math.floor((now - progress.nextAt) / (schedule.everySeconds * 1000)) + 1;
130
+ progress = {
131
+ ...progress,
132
+ lastSlot: progress.lastSlot + elapsed,
133
+ nextAt: progress.nextAt + elapsed * schedule.everySeconds * 1000,
134
+ pending: planned,
135
+ };
136
+ journal.entries.set(workflowId, progress);
137
+ await journal.save();
138
+ journal.entries.set(workflowId, await pending(settings, { workflowId, progress }));
139
+ await journal.save();
140
+ }
141
+ }
142
+ async function initialized(settings) {
143
+ const journal = await scheduleJournal(join(settings.directory, "state"));
144
+ const now = (settings.scheduleClock ?? Date.now)();
145
+ for (const declaration of settings.declarations ?? []) {
146
+ const { workflowId, schedule } = declaration;
147
+ if (schedule === undefined)
148
+ continue;
149
+ const prior = journal.entries.get(workflowId);
150
+ if (prior?.everySeconds === schedule.everySeconds)
151
+ continue;
152
+ journal.entries.set(workflowId, {
153
+ ...prior,
154
+ everySeconds: schedule.everySeconds,
155
+ lastSlot: prior?.lastSlot ?? 0,
156
+ nextAt: now + schedule.everySeconds * 1000,
157
+ });
158
+ }
159
+ await journal.save();
160
+ return journal;
161
+ }
162
+ export async function workflowSchedules(settings) {
163
+ if (!(settings.declarations ?? []).some((entry) => entry.schedule !== undefined))
164
+ return { stop: () => Promise.resolve() };
165
+ const journal = await initialized(settings);
166
+ const stopping = new AbortController();
167
+ const stopped = () => stopping.signal.aborted;
168
+ const running = (async () => {
169
+ while (!stopped()) {
170
+ await delay(250, undefined, { signal: stopping.signal }).catch(() => undefined);
171
+ if (stopped())
172
+ return;
173
+ await tick({ ...settings, signal: stopping.signal }, journal);
174
+ }
175
+ })().catch((error) => {
176
+ if (!stopped())
177
+ process.stderr.write(`Schedules stopped: ${String(error)}\n`);
178
+ });
179
+ return {
180
+ stop: async () => {
181
+ stopping.abort();
182
+ await running;
183
+ },
184
+ };
185
+ }
@@ -0,0 +1 @@
1
+ export declare function decisionToken(runId: string, gateId: string): string;
@@ -0,0 +1,3 @@
1
+ export function decisionToken(runId, gateId) {
2
+ return `cloving-decision/v1/${encodeURIComponent(runId)}/${encodeURIComponent(gateId)}`;
3
+ }
@@ -0,0 +1 @@
1
+ export declare const deliveryBackoffMilliseconds: readonly [0, 60000, 300000, 900000, 3600000];
@@ -0,0 +1,3 @@
1
+ export const deliveryBackoffMilliseconds = [
2
+ 0, 60_000, 300_000, 900_000, 3_600_000,
3
+ ];
@@ -0,0 +1,24 @@
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"];
3
+ export type DoctorCode = (typeof doctorCodes)[number];
4
+ export interface DoctorObservation {
5
+ readonly result: "ok" | "fail" | "skip";
6
+ readonly detail: string;
7
+ }
8
+ export interface DoctorCheck extends DoctorObservation {
9
+ readonly code: DoctorCode;
10
+ readonly required: boolean;
11
+ readonly fix: string;
12
+ }
13
+ export declare const doctorFixes: Readonly<Record<DoctorCode, string>>;
14
+ export declare function doctorExitCode(checks: readonly DoctorCheck[]): number;
15
+ export interface DoctorWorkflow {
16
+ readonly queue?: boolean;
17
+ readonly scope: "bundled" | "project" | "user";
18
+ readonly workflowId: string;
19
+ readonly capabilities: readonly string[];
20
+ readonly input?: SubmissionContract;
21
+ }
22
+ export declare function requiredDoctorCodes(workflows: readonly DoctorWorkflow[], options: {
23
+ readonly queueSeconds: string | undefined;
24
+ }): readonly DoctorCode[];
@@ -0,0 +1,70 @@
1
+ import { hasTicketField } from "./submission.js";
2
+ export const doctorCodes = [
3
+ "git-repository",
4
+ "node-version",
5
+ "harnesses",
6
+ "default-harness",
7
+ "gh-login",
8
+ "github-origin",
9
+ "greptile-review",
10
+ "settings-files",
11
+ "runtime-directory",
12
+ "service",
13
+ "ticket-command",
14
+ "next-command",
15
+ "check-command",
16
+ "queue-interval",
17
+ "private-texts",
18
+ ];
19
+ export const doctorFixes = {
20
+ "git-repository": "Change to the repository, or run: git init",
21
+ "node-version": "Install a supported Node version: nvm install 26 && nvm use 26",
22
+ harnesses: "Install a harness: npm install -g @anthropic-ai/claude-code",
23
+ "default-harness": "Install a harness: npm install -g @anthropic-ai/claude-code; select it: CLOVING_WORKER=claude cloving doctor; clear command overrides: unset CLOVING_CLAUDE_COMMAND CLOVING_CODEX_COMMAND; edit private harness.command if configured; for another harness: cloving config set harness.turn '[...]'",
24
+ "gh-login": "Log in with the configured GitHub command: gh auth login",
25
+ "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
+ "greptile-review": "Install the Greptile app at https://github.com/apps/greptile, then open a first pull request: gh pr create",
27
+ "settings-files": "Fix the project JSON: ${EDITOR:-vi} .cloving/config.json; for private JSON, edit <config>/cloving/projects/<repository-id>.json",
28
+ "runtime-directory": 'Select a private writable runtime: CLOVING_RUNTIME_DIR="$HOME/.local/state/cloving/doctor/run" cloving doctor',
29
+ service: "Start the service: cloving start",
30
+ "ticket-command": "Set tickets.command to an executable list: ${EDITOR:-vi} .cloving/config.json",
31
+ "next-command": "Set tickets.nextCommand to an executable list: ${EDITOR:-vi} .cloving/config.json",
32
+ "check-command": "Set checks.beforeMerge to an executable list: ${EDITOR:-vi} .cloving/config.json",
33
+ "queue-interval": "Set an interval from 10 to 3600: CLOVING_QUEUE_SECONDS=30 cloving doctor",
34
+ "private-texts": `Set a nonblank private text: CLOVING_PRIVATE_TEXTS='["TEXT TO KEEP PRIVATE"]' cloving doctor`,
35
+ };
36
+ export function doctorExitCode(checks) {
37
+ return checks.some((check) => check.required && check.result !== "ok")
38
+ ? 1
39
+ : 0;
40
+ }
41
+ export function requiredDoctorCodes(workflows, options) {
42
+ const codes = new Set([
43
+ "git-repository",
44
+ "node-version",
45
+ "default-harness",
46
+ "settings-files",
47
+ "runtime-directory",
48
+ ]);
49
+ if (workflows.some((workflow) => workflow.capabilities.includes("github"))) {
50
+ codes.add("gh-login");
51
+ codes.add("github-origin");
52
+ }
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)) {
61
+ codes.add("next-command");
62
+ codes.add("queue-interval");
63
+ }
64
+ if (workflows.some((workflow) => hasTicketField(workflow.input)) ||
65
+ bundled.some((name) => ["develop-ticket", "develop-issue"].includes(name)))
66
+ codes.add("ticket-command");
67
+ if (bundled.includes("develop-prd"))
68
+ codes.add("private-texts");
69
+ return [...codes];
70
+ }
@@ -1,8 +1,13 @@
1
1
  import type { AdmissionResult, ExecutionManifest } from "./workflow-admission.ts";
2
+ import { type CommandWaits } from "./workflow-declaration.ts";
2
3
  export declare function executionCapabilities(manifest: ExecutionManifest): string;
3
4
  export declare function pinnedIdentity(manifest: ExecutionManifest): string;
4
5
  export declare function resumePinned(pinned: ExecutionManifest, available: ExecutionManifest): AdmissionResult;
5
6
  export declare function readExecutionManifest(value: unknown): ExecutionManifest;
6
7
  export declare function declaredManifest(manifest: ExecutionManifest, declaration: {
7
8
  readonly handoffs?: readonly string[];
9
+ readonly commands?: readonly string[];
10
+ readonly commandWaits?: CommandWaits;
11
+ readonly bundleDigest?: string | undefined;
12
+ readonly queue?: boolean;
8
13
  }): ExecutionManifest;
@@ -1,10 +1,21 @@
1
- import { isWorkflowHandoffs } from "./workflow-declaration.js";
1
+ import { isCommandWaits, isWorkflowNames, } from "./workflow-declaration.js";
2
2
  const canonical = {
3
+ queue: (manifest) => JSON.stringify(manifest.queue === true),
3
4
  name: (manifest) => JSON.stringify(manifest.name),
4
5
  workflowId: (manifest) => JSON.stringify(manifest.workflowId),
5
6
  steps: (manifest) => JSON.stringify([...manifest.steps].sort()),
6
7
  capabilities: (manifest) => JSON.stringify([...manifest.capabilities].sort()),
7
8
  handoffs: (manifest) => JSON.stringify([...(manifest.handoffs ?? [])].sort()),
9
+ commands: (manifest) => JSON.stringify([...(manifest.commands ?? [])].sort()),
10
+ commandWaits: (manifest) => JSON.stringify(Object.entries(manifest.commandWaits ?? {})
11
+ .sort(([first], [second]) => first < second ? -1 : Number(first > second))
12
+ .map(([name, wait]) => [
13
+ name,
14
+ wait.command,
15
+ wait.maximumWaitSeconds,
16
+ wait.pollEverySeconds,
17
+ ])),
18
+ bundleDigest: (manifest) => JSON.stringify(manifest.bundleDigest),
8
19
  artifacts: (manifest) => JSON.stringify(Object.keys(manifest.artifacts)
9
20
  .sort()
10
21
  .map((name) => [name, manifest.artifacts[name]])),
@@ -30,10 +41,25 @@ export function pinnedIdentity(manifest) {
30
41
  const identity = fields.map((field) => canonical[field](manifest));
31
42
  if (manifest.handoffs?.length)
32
43
  identity.push(canonical.handoffs(manifest));
44
+ if (manifest.commands?.length)
45
+ identity.push(JSON.stringify(["commands", canonical.commands(manifest)]));
46
+ if (Object.keys(manifest.commandWaits ?? {}).length > 0)
47
+ identity.push(JSON.stringify(["commandWaits", canonical.commandWaits(manifest)]));
48
+ if (manifest.bundleDigest !== undefined)
49
+ identity.push(canonical.bundleDigest(manifest));
50
+ if (manifest.queue === true)
51
+ identity.push(JSON.stringify(["queue", true]));
33
52
  return JSON.stringify(identity);
34
53
  }
35
54
  export function resumePinned(pinned, available) {
36
- const changed = [...fields, "handoffs"].find((field) => canonical[field](pinned) !== canonical[field](available));
55
+ const changed = [
56
+ ...fields,
57
+ "handoffs",
58
+ "commands",
59
+ "commandWaits",
60
+ "bundleDigest",
61
+ "queue",
62
+ ].find((field) => canonical[field](pinned) !== canonical[field](available));
37
63
  if (changed !== undefined)
38
64
  return {
39
65
  kind: "rejected",
@@ -46,14 +72,23 @@ export function readExecutionManifest(value) {
46
72
  const fields = record(value);
47
73
  const toolchain = record(fields["toolchain"]);
48
74
  const handoffs = fields["handoffs"];
49
- if (Object.hasOwn(fields, "handoffs") && !isWorkflowHandoffs(handoffs))
75
+ const commands = fields["commands"];
76
+ if (Object.hasOwn(fields, "handoffs") && !isWorkflowNames(handoffs))
50
77
  throw new Error("invalid-handoffs");
78
+ if (Object.hasOwn(fields, "commands") && !isWorkflowNames(commands))
79
+ throw new Error("invalid-commands");
51
80
  return {
52
81
  name: text(fields["name"]),
53
82
  workflowId: text(fields["workflowId"]),
54
83
  steps: texts(fields["steps"]),
55
84
  capabilities: texts(fields["capabilities"]),
56
- ...(isWorkflowHandoffs(handoffs) ? { handoffs: [...handoffs] } : {}),
85
+ ...queueMetadata(fields),
86
+ ...(isWorkflowNames(handoffs) ? { handoffs: [...handoffs] } : {}),
87
+ ...(isWorkflowNames(commands) ? { commands: [...commands] } : {}),
88
+ ...readCommandWaits(fields),
89
+ ...(Object.hasOwn(fields, "bundleDigest")
90
+ ? { bundleDigest: text(fields["bundleDigest"]) }
91
+ : {}),
57
92
  artifacts: textRecord(fields["artifacts"]),
58
93
  resources: textRecord(fields["resources"]),
59
94
  toolchain: {
@@ -65,12 +100,35 @@ export function readExecutionManifest(value) {
65
100
  },
66
101
  };
67
102
  }
103
+ function readCommandWaits(fields) {
104
+ if (!Object.hasOwn(fields, "commandWaits"))
105
+ return {};
106
+ const commandWaits = fields["commandWaits"];
107
+ if (!isCommandWaits(commandWaits, {
108
+ capabilities: texts(fields["capabilities"]),
109
+ commands: texts(fields["commands"]),
110
+ }))
111
+ throw new Error("invalid-command-waits");
112
+ return {
113
+ commandWaits: Object.fromEntries(Object.entries(commandWaits).map(([name, wait]) => [name, { ...wait }])),
114
+ };
115
+ }
68
116
  export function declaredManifest(manifest, declaration) {
69
117
  return readExecutionManifest({
70
118
  ...manifest,
119
+ ...(declaration.queue === undefined ? {} : { queue: declaration.queue }),
120
+ ...(declaration.commands === undefined
121
+ ? {}
122
+ : { commands: declaration.commands }),
123
+ ...(declaration.commandWaits === undefined
124
+ ? {}
125
+ : { commandWaits: declaration.commandWaits }),
71
126
  ...(declaration.handoffs === undefined
72
127
  ? {}
73
128
  : { handoffs: declaration.handoffs }),
129
+ ...(declaration.bundleDigest === undefined
130
+ ? {}
131
+ : { bundleDigest: declaration.bundleDigest }),
74
132
  });
75
133
  }
76
134
  function record(value) {
@@ -87,3 +145,8 @@ function texts(value) {
87
145
  function textRecord(value) {
88
146
  return Object.fromEntries(Object.entries(record(value)).map(([key, item]) => [key, text(item)]));
89
147
  }
148
+ function queueMetadata(fields) {
149
+ if (Object.hasOwn(fields, "queue") && typeof fields["queue"] !== "boolean")
150
+ throw new Error("invalid-queue");
151
+ return fields["queue"] === true ? { queue: true } : {};
152
+ }
@@ -0,0 +1,12 @@
1
+ import { type WorkerUsage } from "./worker-usage.ts";
2
+ export declare function grokResultFields(value: unknown): {
3
+ readonly usage: WorkerUsage;
4
+ readonly failed: boolean;
5
+ readonly pricingModel: string | null;
6
+ readonly costUsd: number | null;
7
+ readonly model?: string;
8
+ };
9
+ export declare function grokUsageWarnings(): {
10
+ readonly write: (chunk: string) => void;
11
+ readonly incomplete: () => boolean;
12
+ };
@@ -0,0 +1,61 @@
1
+ import { record } from "./protocol.js";
2
+ import { tokenCount, usageOf } from "./worker-usage.js";
3
+ function grokUsage(value) {
4
+ const fields = record(value) ?? {};
5
+ const input = tokenCount(fields["input_tokens"]);
6
+ const creation = tokenCount(fields["cache_creation_input_tokens"]);
7
+ const read = tokenCount(fields["cache_read_input_tokens"]);
8
+ const output = tokenCount(fields["output_tokens"]);
9
+ if (input === null || creation === null || read === null || output === null)
10
+ return usageOf(null);
11
+ if (input + creation + read + output === 0)
12
+ return usageOf(null);
13
+ return {
14
+ input_tokens: tokenCount(input + creation),
15
+ cache_read_input_tokens: read,
16
+ output_tokens: output,
17
+ };
18
+ }
19
+ function attributedModel(result) {
20
+ const entries = Object.entries(record(result["modelUsage"]) ?? {});
21
+ const [entry] = entries;
22
+ if (entries.length !== 1 || entry === undefined)
23
+ return null;
24
+ const [model, row] = entry;
25
+ const counts = record(row) ?? {};
26
+ const aggregate = record(result["usage"]) ?? {};
27
+ const fields = [
28
+ ["input_tokens", "inputTokens"],
29
+ ["cache_creation_input_tokens", "cacheCreationInputTokens"],
30
+ ["cache_read_input_tokens", "cacheReadInputTokens"],
31
+ ["output_tokens", "outputTokens"],
32
+ ];
33
+ return fields.every(([total, key]) => tokenCount(aggregate[total]) !== null && aggregate[total] === counts[key])
34
+ ? model
35
+ : null;
36
+ }
37
+ export function grokResultFields(value) {
38
+ const fields = record(value) ?? {};
39
+ const usage = grokUsage(fields["usage"]);
40
+ const model = attributedModel(fields);
41
+ return {
42
+ usage,
43
+ failed: fields["subtype"] !== "success" || fields["is_error"] !== false,
44
+ pricingModel: model,
45
+ costUsd: null,
46
+ ...(model === null ? {} : { model }),
47
+ };
48
+ }
49
+ export function grokUsageWarnings() {
50
+ let tail = "";
51
+ let incomplete = false;
52
+ return {
53
+ write: (chunk) => {
54
+ const text = tail + chunk;
55
+ incomplete ||=
56
+ /streaming-messages-json: (usage is incomplete|no aggregate usage ledger at turn end)/.test(text);
57
+ tail = text.slice(-128);
58
+ },
59
+ incomplete: () => incomplete,
60
+ };
61
+ }
@@ -0,0 +1,35 @@
1
+ export declare const defaultCommand: string[];
2
+ export declare const defaultCodexCommand: string[];
3
+ export declare const defaultGeminiCommand: string[];
4
+ export declare const defaultCursorCommand: string[];
5
+ export declare const defaultOpencodeCommand: string[];
6
+ export declare const defaultGrokCommand: string[];
7
+ export type NativeHarness = "claude" | "codex" | "gemini" | "grok" | "opencode" | "cursor-agent";
8
+ export interface HarnessSettings {
9
+ readonly worker?: string;
10
+ readonly command?: readonly string[];
11
+ readonly workerCommands?: Readonly<Partial<Record<NativeHarness, readonly string[]>>>;
12
+ readonly harness?: {
13
+ readonly name?: string;
14
+ readonly kind?: "file" | "shell";
15
+ readonly path?: string;
16
+ readonly command?: readonly string[];
17
+ readonly turn?: readonly string[];
18
+ readonly output?: "text";
19
+ };
20
+ readonly shell?: string;
21
+ }
22
+ export declare function isTurnCommand(value: unknown): value is readonly string[];
23
+ export declare function harnessDefaults(value: unknown): {
24
+ readonly command: readonly string[];
25
+ readonly variable?: string;
26
+ };
27
+ export declare function turnHarness(settings: HarnessSettings, profile?: {
28
+ readonly harness?: string;
29
+ }): {
30
+ readonly worker: string;
31
+ readonly command: readonly string[];
32
+ readonly shell?: string;
33
+ readonly output?: "text";
34
+ };
35
+ export declare function nativeHarness(name: string): name is NativeHarness;
@@ -0,0 +1,121 @@
1
+ export const defaultCommand = [
2
+ "claude",
3
+ "-p",
4
+ "--output-format",
5
+ "stream-json",
6
+ "--verbose",
7
+ "--permission-mode",
8
+ "acceptEdits",
9
+ "--allowedTools",
10
+ "Bash,Read,Edit,Write,Glob,Grep,WebSearch,WebFetch",
11
+ "--max-budget-usd",
12
+ "5",
13
+ ];
14
+ export const defaultCodexCommand = [
15
+ "codex",
16
+ "exec",
17
+ "--json",
18
+ "--dangerously-bypass-approvals-and-sandbox",
19
+ "--skip-git-repo-check",
20
+ "-",
21
+ ];
22
+ export const defaultGeminiCommand = [
23
+ "gemini",
24
+ "--output-format",
25
+ "stream-json",
26
+ "--approval-mode",
27
+ "yolo",
28
+ ];
29
+ export const defaultCursorCommand = [
30
+ "cursor-agent",
31
+ "-p",
32
+ "--output-format",
33
+ "stream-json",
34
+ "--force",
35
+ ];
36
+ export const defaultOpencodeCommand = ["opencode", "run", "--format", "json"];
37
+ export const defaultGrokCommand = [
38
+ "grok",
39
+ "--output-format",
40
+ "streaming-messages-json",
41
+ "--always-approve",
42
+ "-p",
43
+ ];
44
+ const defaultCommands = {
45
+ claude: defaultCommand,
46
+ codex: defaultCodexCommand,
47
+ gemini: defaultGeminiCommand,
48
+ grok: defaultGrokCommand,
49
+ opencode: defaultOpencodeCommand,
50
+ "cursor-agent": defaultCursorCommand,
51
+ };
52
+ function matchingHarness(settings, name) {
53
+ return (settings.harness?.name ?? "claude") === name
54
+ ? (settings.harness ?? {})
55
+ : {};
56
+ }
57
+ function nativeCommand(settings, name) {
58
+ const command = settings.workerCommands?.[name];
59
+ if (command !== undefined)
60
+ return command;
61
+ if (name === (settings.worker ?? "claude") && settings.command !== undefined)
62
+ return settings.command;
63
+ const saved = matchingHarness(settings, name);
64
+ if (saved.command !== undefined)
65
+ return saved.command;
66
+ const defaults = harnessDefaults(name).command;
67
+ return [saved.path ?? name, ...defaults.slice(1)];
68
+ }
69
+ export function isTurnCommand(value) {
70
+ if (!Array.isArray(value))
71
+ return false;
72
+ const program = value[0];
73
+ return (typeof program === "string" &&
74
+ program !== "" &&
75
+ program !== "{prompt}" &&
76
+ value.every((part) => typeof part === "string" && !part.includes("\u0000")) &&
77
+ value.filter((part) => part === "{prompt}").length <= 1);
78
+ }
79
+ export function harnessDefaults(value) {
80
+ const name = typeof value === "string" && nativeHarness(value) ? value : "claude";
81
+ const variable = {
82
+ claude: "CLOVING_CLAUDE_COMMAND",
83
+ codex: "CLOVING_CODEX_COMMAND",
84
+ gemini: "CLOVING_GEMINI_COMMAND",
85
+ grok: "CLOVING_GROK_COMMAND",
86
+ opencode: "CLOVING_OPENCODE_COMMAND",
87
+ "cursor-agent": undefined,
88
+ }[name];
89
+ return {
90
+ command: defaultCommands[name],
91
+ ...(variable === undefined ? {} : { variable }),
92
+ };
93
+ }
94
+ function selectedCommand(settings, name) {
95
+ if (nativeHarness(name))
96
+ return { command: nativeCommand(settings, name) };
97
+ const saved = matchingHarness(settings, name);
98
+ if (saved.turn === undefined)
99
+ throw new Error(`harness-no-worker: ${name}`);
100
+ if (!isTurnCommand(saved.turn))
101
+ throw new Error("invalid-setting: harness.turn");
102
+ return {
103
+ command: saved.command ?? [
104
+ saved.path ?? saved.turn[0] ?? "",
105
+ ...saved.turn.slice(1),
106
+ ],
107
+ output: "text",
108
+ };
109
+ }
110
+ export function turnHarness(settings, profile = {}) {
111
+ const name = profile.harness ?? settings.worker ?? settings.harness?.name ?? "claude";
112
+ const saved = matchingHarness(settings, name);
113
+ return {
114
+ worker: name,
115
+ ...selectedCommand(settings, name),
116
+ ...(saved.kind === "shell" ? { shell: settings.shell ?? "/bin/sh" } : {}),
117
+ };
118
+ }
119
+ export function nativeHarness(name) {
120
+ return Object.hasOwn(defaultCommands, name);
121
+ }