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,16 @@
1
+ import { snapshotReviewSubject } from "./review-subject.js";
2
+ import { waitForDecision } from "./wait-for-decision.js";
3
+ export async function reviewByPerson(request) {
4
+ const snapshot = await snapshotReviewSubject(request.subject);
5
+ const decision = await waitForDecision({
6
+ gateId: `review:${snapshot.subjectDigest}`,
7
+ kind: "approval",
8
+ prompt: `Review this subject:\n${snapshot.prompt}`,
9
+ });
10
+ return {
11
+ accepted: decision.decision === "approved",
12
+ feedback: decision.answer ?? "",
13
+ commit: snapshot.commit,
14
+ subjectDigest: snapshot.subjectDigest,
15
+ };
16
+ }
@@ -0,0 +1,2 @@
1
+ import { type ReviewSubject, type ReviewSnapshot } from "../review-subject.ts";
2
+ export declare function snapshotReviewSubject(subject: ReviewSubject): Promise<ReviewSnapshot>;
@@ -0,0 +1,11 @@
1
+ import { operationDigest } from "../broker/operation-digest.js";
2
+ import { reviewSubjectText, } from "../review-subject.js";
3
+ export async function snapshotReviewSubject(subject) {
4
+ "use step";
5
+ const prompt = reviewSubjectText(subject);
6
+ return Promise.resolve({
7
+ commit: "draft" in subject ? null : subject.commit,
8
+ subjectDigest: `sha256:${operationDigest(prompt)}`,
9
+ prompt,
10
+ });
11
+ }
@@ -0,0 +1,2 @@
1
+ import { type CommandRequest, type ProtectedResult } from "../step-bridge.ts";
2
+ export declare function runCommand(request: CommandRequest): Promise<ProtectedResult>;
@@ -0,0 +1,15 @@
1
+ import { isStepBridge, stepBridgeKey, } from "../step-bridge.js";
2
+ export async function runCommand(request) {
3
+ "use step";
4
+ const bridge = Reflect.get(globalThis, Symbol.for(stepBridgeKey));
5
+ if (!isStepBridge(bridge))
6
+ return { kind: "unavailable", reason: "cloving-host-unavailable" };
7
+ return await bridge.effect({
8
+ scope: request.scope,
9
+ capability: "command",
10
+ method: `run:${request.name}`,
11
+ target: request.name,
12
+ payload: JSON.stringify(request.input),
13
+ units: 1,
14
+ });
15
+ }
@@ -0,0 +1,3 @@
1
+ export declare function sleep(request: {
2
+ readonly seconds: number;
3
+ }): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { sleep as sdkSleep } from "workflow";
2
+ export async function sleep(request) {
3
+ await sdkSleep(sleepSeconds(request) * 1000);
4
+ }
5
+ function sleepSeconds(request) {
6
+ if (typeof request !== "object" ||
7
+ request === null ||
8
+ Reflect.ownKeys(request).length !== 1)
9
+ throw new Error("invalid-sleep-seconds");
10
+ const field = Object.getOwnPropertyDescriptor(request, "seconds") ?? {};
11
+ const seconds = field.value;
12
+ if (field.enumerable !== true ||
13
+ typeof seconds !== "number" ||
14
+ !Number.isInteger(seconds) ||
15
+ seconds < 1 ||
16
+ seconds > 86400)
17
+ throw new Error("invalid-sleep-seconds");
18
+ return seconds;
19
+ }
@@ -0,0 +1,2 @@
1
+ import type { DecisionResult, GateRequest } from "../step-bridge.ts";
2
+ export declare function waitForDecision(request: GateRequest): Promise<DecisionResult>;
@@ -0,0 +1,71 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import { createHook } from "workflow";
54
+ import { openDecisionWait } from "./decision-gate.js";
55
+ export async function waitForDecision(request) {
56
+ const env_1 = { stack: [], error: void 0, hasError: false };
57
+ try {
58
+ const wait = await openDecisionWait(request);
59
+ if ("decision" in wait)
60
+ return wait;
61
+ const hook = __addDisposableResource(env_1, createHook({ token: wait.token }), false);
62
+ return await hook;
63
+ }
64
+ catch (e_1) {
65
+ env_1.error = e_1;
66
+ env_1.hasError = true;
67
+ }
68
+ finally {
69
+ __disposeResources(env_1);
70
+ }
71
+ }
@@ -0,0 +1,5 @@
1
+ import { type RunWaitOutcome, type RunWaitRequest } from "../step-bridge.ts";
2
+ export declare function waitForRun(request: RunWaitRequest): Promise<RunWaitOutcome>;
3
+ export declare namespace waitForRun {
4
+ var maxRetries: number;
5
+ }
@@ -0,0 +1,9 @@
1
+ import { isStepBridge, stepBridgeKey, } from "../step-bridge.js";
2
+ export async function waitForRun(request) {
3
+ "use step";
4
+ const bridge = Reflect.get(globalThis, Symbol.for(stepBridgeKey));
5
+ if (!isStepBridge(bridge) || bridge.waitForRun === undefined)
6
+ throw new Error("cloving-host-unavailable");
7
+ return await bridge.waitForRun(request);
8
+ }
9
+ waitForRun.maxRetries = 86401;
@@ -12,6 +12,7 @@ export interface DecidedSnapshot extends DomainSnapshot, DecisionRows {
12
12
  export interface CurrentSnapshot extends DecidedSnapshot {
13
13
  readonly effects: EffectRows;
14
14
  }
15
+ export declare function loadOperationSnapshot(connection: SqlConnection): Promise<Pick<ProjectionSnapshot, "outbox" | "deliveries">>;
15
16
  export declare function loadProjections(connection: SqlConnection): Promise<ProjectionSnapshot>;
16
17
  export declare function loadDecided(connection: SqlConnection): Promise<DecidedSnapshot>;
17
18
  export declare function loadCurrent(connection: SqlConnection): Promise<CurrentSnapshot>;
@@ -1,6 +1,12 @@
1
1
  import { loadDecisions, loadDocuments, } from "./decision-rows.js";
2
- import { latestSequence, loadAttempts, loadSnapshot, projectionRows, text, } from "./domain-rows.js";
2
+ import { latestSequence, loadAttempts, loadSnapshot, outboxRow, projectionRows, text, } from "./domain-rows.js";
3
3
  import { loadEffects } from "./effect-rows.js";
4
+ export async function loadOperationSnapshot(connection) {
5
+ return {
6
+ outbox: (await connection.all("SELECT operation_id, kind, run_id, created_sequence, released_sequence FROM outbox ORDER BY created_sequence, rowid")).map(outboxRow),
7
+ deliveries: await loadAttempts(connection),
8
+ };
9
+ }
4
10
  export async function loadProjections(connection) {
5
11
  return {
6
12
  ...(await projectionRows(connection)),
@@ -5,6 +5,9 @@ export type SubmissionField = {
5
5
  } | {
6
6
  readonly type: "boolean";
7
7
  readonly optional?: boolean;
8
+ } | {
9
+ readonly type: "ticket";
10
+ readonly optional?: boolean;
8
11
  } | {
9
12
  readonly type: "integer";
10
13
  readonly optional?: boolean;
@@ -15,6 +18,7 @@ export interface SubmissionContract {
15
18
  readonly maximumBytes: number;
16
19
  readonly fields: Readonly<Record<string, "string" | SubmissionField>>;
17
20
  }
21
+ export declare function hasTicketField(contract: SubmissionContract | undefined): boolean;
18
22
  export type SubmissionCheck = {
19
23
  readonly kind: "valid";
20
24
  readonly normalized: string;
@@ -1,4 +1,8 @@
1
1
  import { record } from "./protocol.js";
2
+ export function hasTicketField(contract) {
3
+ const rule = contract?.fields["ticket"];
4
+ return rule !== undefined && rule !== "string" && rule.type === "ticket";
5
+ }
2
6
  function rejected(code, detail) {
3
7
  return { kind: "rejected", code, detail };
4
8
  }
@@ -14,11 +18,11 @@ function invalidField(contract, submission) {
14
18
  return Object.entries(contract.fields).find(([key, rule]) => {
15
19
  if (rule !== "string" && rule.optional && !Object.hasOwn(submission, key))
16
20
  return false;
17
- return !validValue(rule, submission[key]);
21
+ return !validValue(rule === "string" ? { type: "string" } : rule, submission[key]);
18
22
  })?.[0];
19
23
  }
20
24
  function validValue(rule, value) {
21
- if (rule === "string" || rule.type === "string")
25
+ if (rule.type === "string" || rule.type === "ticket")
22
26
  return typeof value === "string" && value.trim().length > 0;
23
27
  if (rule.type === "boolean")
24
28
  return typeof value === "boolean";
@@ -0,0 +1,29 @@
1
+ import { type HandoffValue, type ProtectedResult, type GateResult, type DecisionResult, type RunWaitOutcome, type ProtectedRequest, type GateRequest, type HandoffRequest, type RunWaitRequest } from "./step-bridge.ts";
2
+ export interface StepScenario {
3
+ readonly turn?: ProtectedResult;
4
+ readonly effects?: Readonly<Record<string, readonly ProtectedResult[]>>;
5
+ readonly gate?: GateResult;
6
+ readonly waits?: readonly RunWaitOutcome[];
7
+ readonly decisions?: readonly DecisionResult[];
8
+ readonly effectLimit?: number;
9
+ }
10
+ export interface WorkflowScenario extends StepScenario {
11
+ readonly workflow: string;
12
+ readonly exportName: string;
13
+ readonly input: HandoffValue;
14
+ readonly decision?: HandoffValue;
15
+ }
16
+ export type ScenarioRequest = readonly ["effect", ProtectedRequest] | readonly ["gate", GateRequest] | readonly ["waitForDecision", GateRequest] | readonly ["handoff", HandoffRequest] | readonly ["waitForRun", RunWaitRequest] | readonly ["sleep", {
17
+ readonly seconds: number;
18
+ }];
19
+ export interface ScenarioResult {
20
+ readonly spent?: number;
21
+ readonly outcome: unknown;
22
+ readonly requests: readonly ScenarioRequest[];
23
+ }
24
+ export declare function fakeStepBridge(scenario: StepScenario): {
25
+ requests: ScenarioRequest[];
26
+ readonly spent: number;
27
+ [Symbol.dispose](): void;
28
+ };
29
+ export declare function runScenario(scenario: WorkflowScenario): Promise<ScenarioResult>;
@@ -0,0 +1,264 @@
1
+ import { spawn } from "node:child_process";
2
+ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join, resolve } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ import { workflowTestLoader } from "../tools/workflow-test-loader.js";
7
+ import { authorizeEffect } from "./effect-authorization.js";
8
+ import { record } from "./protocol.js";
9
+ import { stepBridgeKey, } from "./step-bridge.js";
10
+ export function fakeStepBridge(scenario) {
11
+ const { bridge, requests, budget } = scenarioBridge(scenario);
12
+ const key = Symbol.for(stepBridgeKey);
13
+ const sleepKey = Symbol.for("WORKFLOW_SLEEP");
14
+ const previous = Object.getOwnPropertyDescriptor(globalThis, key);
15
+ const previousSleep = Object.getOwnPropertyDescriptor(globalThis, sleepKey);
16
+ if (Reflect.get(globalThis, key) !== undefined ||
17
+ Reflect.get(globalThis, sleepKey) !== undefined)
18
+ throw new Error("workflow-testing-host-active");
19
+ if (previous?.configurable === false || previousSleep?.configurable === false)
20
+ throw new Error("workflow-testing-host-locked");
21
+ Object.defineProperty(globalThis, key, { configurable: true, value: bridge });
22
+ Object.defineProperty(globalThis, sleepKey, {
23
+ configurable: true,
24
+ value: (milliseconds) => {
25
+ requests.push(["sleep", { seconds: milliseconds / 1000 }]);
26
+ return Promise.resolve();
27
+ },
28
+ });
29
+ return {
30
+ requests,
31
+ get spent() {
32
+ return budget.spent;
33
+ },
34
+ [Symbol.dispose]() {
35
+ if (previous === undefined)
36
+ Reflect.deleteProperty(globalThis, key);
37
+ else
38
+ Object.defineProperty(globalThis, key, previous);
39
+ if (previousSleep === undefined)
40
+ Reflect.deleteProperty(globalThis, sleepKey);
41
+ else
42
+ Object.defineProperty(globalThis, sleepKey, previousSleep);
43
+ },
44
+ };
45
+ }
46
+ function scenarioBridge(scenario) {
47
+ const requests = [];
48
+ const waits = [...(scenario.waits ?? [])];
49
+ const decisions = [...(scenario.decisions ?? [])];
50
+ const budget = { spent: 0 };
51
+ const bridge = {
52
+ ...scenarioEffects(scenario, { requests, budget }),
53
+ gate: (request) => {
54
+ requests.push(["gate", request]);
55
+ return Promise.resolve(scenario.gate ?? {
56
+ kind: "unavailable",
57
+ reason: "no-scenario-result",
58
+ });
59
+ },
60
+ waitForDecision: (request) => {
61
+ requests.push(["waitForDecision", request]);
62
+ const decision = decisions.shift();
63
+ if (decision === undefined)
64
+ return Promise.reject(new Error("no-scenario-result"));
65
+ return Promise.resolve(decision);
66
+ },
67
+ waitForRun: (request) => {
68
+ requests.push(["waitForRun", request]);
69
+ return Promise.resolve(waits.shift() ?? {
70
+ kind: "unavailable",
71
+ reason: "no-scenario-result",
72
+ promotionId: null,
73
+ });
74
+ },
75
+ };
76
+ return { bridge, requests, budget };
77
+ }
78
+ function scenarioEffects(scenario, state) {
79
+ const { requests, budget } = state;
80
+ const effects = new Map(Object.entries(scenario.effects ?? {}).map(([key, values]) => [
81
+ key,
82
+ [...values],
83
+ ]));
84
+ return {
85
+ effect: (request) => {
86
+ requests.push(["effect", request]);
87
+ const refusal = spend(scenario, { budget, request });
88
+ if (refusal !== undefined)
89
+ return Promise.resolve(refusal);
90
+ const result = scenario.effects === undefined
91
+ ? scenario.turn
92
+ : effects.get(request.capability + " " + request.method)?.shift();
93
+ return Promise.resolve(result ?? { kind: "unavailable", reason: "no-scenario-result" });
94
+ },
95
+ handoff: (request) => {
96
+ requests.push(["handoff", request]);
97
+ const refusal = spend(scenario, {
98
+ budget,
99
+ request: { capability: "handoff", units: 1 },
100
+ });
101
+ if (refusal !== undefined)
102
+ return Promise.resolve(refusal);
103
+ return Promise.resolve(effects.get("handoff")?.shift() ?? {
104
+ kind: "completed",
105
+ operationId: "handoff",
106
+ receipt: null,
107
+ result: "target-run",
108
+ });
109
+ },
110
+ };
111
+ }
112
+ function spend(scenario, effect) {
113
+ const { budget, request } = effect;
114
+ if (scenario.effectLimit === undefined)
115
+ return undefined;
116
+ const allowed = authorizeEffect({ capabilities: ["claude", "github", "command", "handoff"] }, {
117
+ budget: { limit: scenario.effectLimit, spent: budget.spent },
118
+ request,
119
+ });
120
+ if (allowed.kind === "rejected")
121
+ return { kind: "refused", reason: allowed.reason };
122
+ budget.spent = allowed.spent;
123
+ return undefined;
124
+ }
125
+ function scenarioScript(scenario) {
126
+ const workflow = scenario.workflow.startsWith("file:")
127
+ ? scenario.workflow
128
+ : pathToFileURL(resolve(scenario.workflow)).href;
129
+ return `import { writeFile } from "node:fs/promises";
130
+ import { fakeStepBridge } from ${JSON.stringify(import.meta.url)};
131
+ import * as workflows from ${JSON.stringify(workflow)};
132
+ const given = ${JSON.stringify(scenario)};
133
+ const workflow = workflows[given.exportName];
134
+ if (typeof workflow !== "function") throw new Error("workflow-test-export-missing");
135
+ using bridge = fakeStepBridge(given);
136
+ const outcome = await workflow(given.input, given.decision);
137
+ await writeFile(process.argv[2], JSON.stringify({ outcome, requests: bridge.requests,
138
+ ...(given.effectLimit === undefined ? {} : { spent: bridge.spent }) }));`;
139
+ }
140
+ function scenarioResult(value) {
141
+ const result = record(value);
142
+ return (result !== undefined &&
143
+ Object.hasOwn(result, "outcome") &&
144
+ Array.isArray(result["requests"]) &&
145
+ result["requests"].every(scenarioRequest) &&
146
+ (result["spent"] === undefined || typeof result["spent"] === "number"));
147
+ }
148
+ function scenarioRequest(value) {
149
+ if (!Array.isArray(value) || value.length !== 2)
150
+ return false;
151
+ const request = record(value[1]);
152
+ if (request === undefined)
153
+ return false;
154
+ switch (value[0]) {
155
+ case "effect":
156
+ return protectedRequest(request);
157
+ case "gate":
158
+ case "waitForDecision":
159
+ return gateRequest(request);
160
+ case "handoff":
161
+ return handoffRequest(request);
162
+ case "waitForRun":
163
+ return runWaitRequest(request);
164
+ case "sleep":
165
+ return sleepRequest(request);
166
+ default:
167
+ return false;
168
+ }
169
+ }
170
+ function runWaitRequest(request) {
171
+ return (typeof request["runId"] === "string" &&
172
+ typeof request["maximumWaitSeconds"] === "number");
173
+ }
174
+ function sleepRequest(request) {
175
+ const seconds = request["seconds"];
176
+ return (typeof seconds === "number" &&
177
+ Number.isInteger(seconds) &&
178
+ seconds >= 1 &&
179
+ seconds <= 86400);
180
+ }
181
+ function gateRequest(request) {
182
+ return (typeof request["gateId"] === "string" &&
183
+ (request["kind"] === "question" || request["kind"] === "approval") &&
184
+ typeof request["prompt"] === "string" &&
185
+ optionalText(request["expiresAt"]));
186
+ }
187
+ function handoffRequest(request) {
188
+ const input = record(request["input"]);
189
+ return (typeof request["workflowId"] === "string" &&
190
+ input !== undefined &&
191
+ Object.values(input).every(handoffValue));
192
+ }
193
+ function protectedRequest(request) {
194
+ return (protectedScope(request["scope"]) &&
195
+ ["capability", "method", "target", "payload"].every((key) => typeof request[key] === "string") &&
196
+ typeof request["units"] === "number" &&
197
+ optionalText(request["resource"]));
198
+ }
199
+ function protectedScope(value) {
200
+ const scope = record(value);
201
+ if (scope === undefined)
202
+ return false;
203
+ const stage = record(scope["stage"]);
204
+ return (typeof scope["phase"] === "string" &&
205
+ typeof scope["operation"] === "string" &&
206
+ typeof scope["round"] === "number" &&
207
+ optionalText(scope["key"]) &&
208
+ (scope["stage"] === undefined ||
209
+ (stage !== undefined &&
210
+ ["id", "visit", "branch"].every((key) => typeof stage[key] === "string"))));
211
+ }
212
+ function optionalText(value) {
213
+ return value === undefined || typeof value === "string";
214
+ }
215
+ function handoffValue(value) {
216
+ if (value === null || ["string", "boolean", "number"].includes(typeof value))
217
+ return true;
218
+ if (Array.isArray(value))
219
+ return value.every(handoffValue);
220
+ const fields = record(value);
221
+ return fields !== undefined && Object.values(fields).every(handoffValue);
222
+ }
223
+ export async function runScenario(scenario) {
224
+ const temporary = await mkdtemp(join(tmpdir(), "cloving-scenario-"));
225
+ try {
226
+ const script = join(temporary, "scenario.mjs");
227
+ const resultFile = join(temporary, "result.json");
228
+ await writeFile(script, scenarioScript(scenario));
229
+ await executeScenario(script, resultFile);
230
+ const value = JSON.parse(await readFile(resultFile, "utf8"));
231
+ if (!scenarioResult(value))
232
+ throw new Error("invalid-workflow-scenario-result");
233
+ return value;
234
+ }
235
+ finally {
236
+ await rm(temporary, { recursive: true, force: true });
237
+ }
238
+ }
239
+ function executeScenario(script, resultFile) {
240
+ return new Promise((settle, reject) => {
241
+ const child = spawn(process.execPath, [
242
+ "--experimental-strip-types",
243
+ "--import",
244
+ workflowTestLoader(),
245
+ script,
246
+ resultFile,
247
+ ], {
248
+ env: { ...process.env, NODE_TEST_CONTEXT: undefined },
249
+ stdio: ["ignore", "ignore", "pipe"],
250
+ });
251
+ let diagnostics = "";
252
+ child.stderr.setEncoding("utf8");
253
+ child.stderr.on("data", (text) => {
254
+ diagnostics = (diagnostics + text).slice(-65536);
255
+ });
256
+ child.once("error", reject);
257
+ child.once("close", (code, signal) => {
258
+ if (code === 0)
259
+ settle();
260
+ else
261
+ reject(new Error(`workflow-scenario-failed: ${String(code ?? signal)}\n${diagnostics}`));
262
+ });
263
+ });
264
+ }
@@ -0,0 +1,9 @@
1
+ import { type TicketStatus } from "./ticket-status.ts";
2
+ export interface StreamedTicketStatus {
3
+ readonly ticketStatus: TicketStatus;
4
+ readonly ticketStatusTooLarge?: true;
5
+ }
6
+ export declare function ticketStatusStream(limit: number): {
7
+ write: (chunk: string) => void;
8
+ result: () => StreamedTicketStatus;
9
+ };
@@ -0,0 +1,94 @@
1
+ import { ticketStatus } from "./ticket-status.js";
2
+ function emptyLine() {
3
+ return {
4
+ text: "",
5
+ length: 0,
6
+ contentLength: 0,
7
+ breaks: 0,
8
+ trailingCarriage: false,
9
+ };
10
+ }
11
+ function remainingLine(stream, line) {
12
+ if (line.length <= stream.limit && line.text === "Remaining:") {
13
+ stream.remaining = [];
14
+ stream.characters = 0;
15
+ stream.valid = true;
16
+ return;
17
+ }
18
+ if (!stream.valid)
19
+ return;
20
+ if (line.breaks > 0 || !/^- \S.*$/.test(line.text)) {
21
+ stream.valid = false;
22
+ return;
23
+ }
24
+ stream.characters = Math.min(stream.limit + 1, stream.characters + line.length + 1);
25
+ if (stream.characters <= stream.limit)
26
+ stream.remaining.push(line.text.slice(2));
27
+ }
28
+ function receivedLine(stream) {
29
+ const line = stream.line;
30
+ stream.line = emptyLine();
31
+ if (line.contentLength === 0)
32
+ return;
33
+ if (line.trailingCarriage)
34
+ line.breaks--;
35
+ if (line.length <= stream.limit + 1 && line.trailingCarriage) {
36
+ line.text = line.text.slice(0, -1);
37
+ line.length--;
38
+ }
39
+ if (stream.last !== undefined)
40
+ remainingLine(stream, stream.last);
41
+ if (/^Ticket status:/i.test(line.text))
42
+ stream.statuses = Math.min(2, stream.statuses + 1);
43
+ stream.last = line;
44
+ }
45
+ function writeStatus(stream, chunk) {
46
+ const parts = chunk.split("\n");
47
+ for (const [index, part] of parts.entries()) {
48
+ const { line, limit } = stream;
49
+ const content = part.trimEnd();
50
+ line.breaks = Math.min(2, line.breaks + (part.match(/[\r\u2028\u2029]/g)?.length ?? 0));
51
+ if (part !== "")
52
+ line.trailingCarriage = part.endsWith("\r");
53
+ if (content !== "")
54
+ line.contentLength = Math.min(limit + 1, line.length + content.length);
55
+ line.text = (line.text + part).slice(0, limit + 1);
56
+ line.length = Math.min(limit + 2, line.length + part.length);
57
+ if (index < parts.length - 1)
58
+ receivedLine(stream);
59
+ }
60
+ }
61
+ function statusResult(stream) {
62
+ receivedLine(stream);
63
+ const last = stream.last;
64
+ if (stream.statuses !== 1 || last === undefined)
65
+ return { ticketStatus: ticketStatus("") };
66
+ const status = last.contentLength > stream.limit ? "" : last.text.trimEnd();
67
+ if (status !== "Ticket status: partial" || !stream.valid)
68
+ return { ticketStatus: ticketStatus(status) };
69
+ if (stream.characters > stream.limit)
70
+ return {
71
+ ticketStatus: ticketStatus(status),
72
+ ticketStatusTooLarge: true,
73
+ };
74
+ return {
75
+ ticketStatus: ticketStatus(`Remaining:\n${stream.remaining.map((item) => `- ${item}`).join("\n")}\n${status}`),
76
+ };
77
+ }
78
+ export function ticketStatusStream(limit) {
79
+ const stream = {
80
+ limit,
81
+ line: emptyLine(),
82
+ last: undefined,
83
+ statuses: 0,
84
+ remaining: [],
85
+ characters: 0,
86
+ valid: false,
87
+ };
88
+ return {
89
+ write: (chunk) => {
90
+ writeStatus(stream, chunk);
91
+ },
92
+ result: () => statusResult(stream),
93
+ };
94
+ }
@@ -1,4 +1,5 @@
1
- import { type WorkerUsage } from "./worker-usage.ts";
1
+ import { type WorkerUsage, type WorkerModelUsage } from "./worker-usage.ts";
2
+ import type { NativeHarness } from "./harness-defaults.ts";
2
3
  export interface TokenPrice {
3
4
  readonly input: number;
4
5
  readonly cachedInput: number;
@@ -15,7 +16,14 @@ export declare function parseFallbackModels(value: string | undefined): readonly
15
16
  export declare function priceForModel(prices: TokenPrices, model: string | null): TokenPrice | undefined;
16
17
  export declare function commandModel(command: readonly string[]): string | null;
17
18
  export declare function replaceCommandModel(command: readonly string[], model: string): readonly string[];
18
- export declare function estimatedCostUsd(usage: WorkerUsage, pricing: {
19
- readonly worker: "claude" | "codex";
19
+ interface SinglePricing {
20
+ readonly worker: NativeHarness;
20
21
  readonly price: TokenPrice | undefined;
21
- }): number | null;
22
+ }
23
+ interface ModelPricing {
24
+ readonly worker: "gemini";
25
+ readonly models: readonly WorkerModelUsage[];
26
+ readonly prices: TokenPrices;
27
+ }
28
+ export declare function estimatedCostUsd(usage: WorkerUsage, pricing: SinglePricing | ModelPricing): number | null;
29
+ export {};