cloving 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. package/README.md +329 -215
  2. package/dist/src/agent-harness-shell.d.ts +2 -1
  3. package/dist/src/agent-harness-shell.js +8 -5
  4. package/dist/src/authority/command-wait-checks.d.ts +8 -0
  5. package/dist/src/authority/command-wait-checks.js +88 -0
  6. package/dist/src/authority/command-wait-results.d.ts +15 -0
  7. package/dist/src/authority/command-wait-results.js +73 -0
  8. package/dist/src/authority/command-wait-view.d.ts +21 -0
  9. package/dist/src/authority/command-wait-view.js +34 -0
  10. package/dist/src/authority/command-waits.d.ts +39 -0
  11. package/dist/src/authority/command-waits.js +97 -0
  12. package/dist/src/authority/commands.js +22 -1
  13. package/dist/src/authority/dispatch-decision.d.ts +8 -0
  14. package/dist/src/authority/dispatch-decision.js +26 -1
  15. package/dist/src/authority/effect-requests.js +6 -3
  16. package/dist/src/authority/effect-results.js +4 -2
  17. package/dist/src/authority/history-state.d.ts +2 -0
  18. package/dist/src/authority/history-state.js +13 -1
  19. package/dist/src/authority/instants.d.ts +1 -0
  20. package/dist/src/authority/instants.js +21 -0
  21. package/dist/src/authority/reduction-state.d.ts +2 -0
  22. package/dist/src/authority/reduction-state.js +5 -0
  23. package/dist/src/authority/reduction.js +24 -0
  24. package/dist/src/authority/status-input.d.ts +2 -0
  25. package/dist/src/authority/status.d.ts +2 -0
  26. package/dist/src/authority/status.js +1 -0
  27. package/dist/src/authority/stop-sequence.d.ts +1 -0
  28. package/dist/src/authority/stop-sequence.js +2 -1
  29. package/dist/src/authority/transitions.d.ts +6 -4
  30. package/dist/src/authority/transitions.js +7 -0
  31. package/dist/src/broker/actor/authority-health.d.ts +9 -0
  32. package/dist/src/broker/actor/authority-health.js +24 -0
  33. package/dist/src/broker/actor/authority-queries.d.ts +2 -1
  34. package/dist/src/broker/actor/authority-queries.js +14 -5
  35. package/dist/src/broker/actor/authority-receipts.js +1 -1
  36. package/dist/src/broker/actor/authority-runtime.d.ts +4 -2
  37. package/dist/src/broker/actor/authority-runtime.js +29 -20
  38. package/dist/src/broker/actor/authority-session.d.ts +6 -19
  39. package/dist/src/broker/actor/authority-session.js +66 -88
  40. package/dist/src/broker/actor/authority-settings.d.ts +2 -1
  41. package/dist/src/broker/actor/authority-settings.js +6 -3
  42. package/dist/src/broker/actor/authority-upgrades.d.ts +23 -2
  43. package/dist/src/broker/actor/authority-upgrades.js +8 -2
  44. package/dist/src/broker/actor/authority-watchdog.d.ts +6 -2
  45. package/dist/src/broker/actor/authority-watchdog.js +31 -9
  46. package/dist/src/broker/actor/authority.js +3 -1
  47. package/dist/src/broker/actor/delivery-intents.js +2 -0
  48. package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
  49. package/dist/src/broker/actor/effect-delivery.js +15 -2
  50. package/dist/src/broker/actor/effect-plan.js +11 -2
  51. package/dist/src/broker/actor/effect-queries.d.ts +4 -0
  52. package/dist/src/broker/actor/effect-queries.js +9 -1
  53. package/dist/src/broker/actor/effect-turn.js +2 -0
  54. package/dist/src/broker/actor/projection-memory.d.ts +43 -0
  55. package/dist/src/broker/actor/projection-memory.js +207 -0
  56. package/dist/src/broker/actor/runtime-parts.d.ts +5 -0
  57. package/dist/src/broker/actor/runtime-parts.js +8 -3
  58. package/dist/src/broker/actor/stop-plan.js +9 -3
  59. package/dist/src/broker/actor/stop-turn.d.ts +2 -0
  60. package/dist/src/broker/actor/stop-turn.js +24 -11
  61. package/dist/src/broker/actor/turn-draft.d.ts +1 -0
  62. package/dist/src/broker/actor/turn-draft.js +4 -0
  63. package/dist/src/broker/actor/turn-state.js +5 -1
  64. package/dist/src/broker/authority-admission.js +60 -0
  65. package/dist/src/broker/authority-restore.d.ts +2 -0
  66. package/dist/src/broker/authority-restore.js +35 -1
  67. package/dist/src/broker/command-wait-restore.d.ts +31 -0
  68. package/dist/src/broker/command-wait-restore.js +86 -0
  69. package/dist/src/broker/decision-restore.d.ts +1 -1
  70. package/dist/src/broker/decision-restore.js +1 -0
  71. package/dist/src/broker/effect-upgrade.d.ts +3 -0
  72. package/dist/src/broker/effect-upgrade.js +11 -2
  73. package/dist/src/cli/arguments.d.ts +13 -0
  74. package/dist/src/cli/arguments.js +43 -3
  75. package/dist/src/cli/chat-stores.d.ts +2 -0
  76. package/dist/src/cli/chat-stores.js +113 -0
  77. package/dist/src/cli/client.d.ts +7 -2
  78. package/dist/src/cli/client.js +13 -7
  79. package/dist/src/cli/command-requests.d.ts +46 -0
  80. package/dist/src/cli/command-requests.js +84 -0
  81. package/dist/src/cli/command-waits.d.ts +9 -0
  82. package/dist/src/cli/command-waits.js +51 -0
  83. package/dist/src/cli/commands.js +70 -88
  84. package/dist/src/cli/config-file.d.ts +2 -2
  85. package/dist/src/cli/config-file.js +4 -2
  86. package/dist/src/cli/config-notice.js +5 -2
  87. package/dist/src/cli/doctor-retention.d.ts +2 -0
  88. package/dist/src/cli/doctor-retention.js +93 -0
  89. package/dist/src/cli/doctor-workflows.d.ts +5 -2
  90. package/dist/src/cli/doctor-workflows.js +12 -7
  91. package/dist/src/cli/doctor.js +11 -9
  92. package/dist/src/cli/harness-probes.d.ts +2 -0
  93. package/dist/src/cli/harness-probes.js +1 -1
  94. package/dist/src/cli/harness-processes.d.ts +6 -0
  95. package/dist/src/cli/harness-processes.js +36 -0
  96. package/dist/src/cli/init-command.d.ts +9 -0
  97. package/dist/src/cli/init-command.js +52 -0
  98. package/dist/src/cli/init-prompt-command.d.ts +10 -0
  99. package/dist/src/cli/init-prompt-command.js +145 -0
  100. package/dist/src/cli/init-prompt.d.ts +35 -0
  101. package/dist/src/cli/init-prompt.js +74 -0
  102. package/dist/src/cli/init-selection.d.ts +13 -0
  103. package/dist/src/cli/init-selection.js +75 -0
  104. package/dist/src/cli/main.d.ts +2 -0
  105. package/dist/src/cli/main.js +37 -7
  106. package/dist/src/cli/mcp-server.d.ts +1 -0
  107. package/dist/src/cli/mcp-server.js +156 -0
  108. package/dist/src/cli/mcp-tools.d.ts +15 -0
  109. package/dist/src/cli/mcp-tools.js +242 -0
  110. package/dist/src/cli/queue-arguments.d.ts +15 -0
  111. package/dist/src/cli/queue-arguments.js +31 -0
  112. package/dist/src/cli/queue-render.d.ts +3 -0
  113. package/dist/src/cli/queue-render.js +26 -0
  114. package/dist/src/cli/reload-render.d.ts +2 -0
  115. package/dist/src/cli/reload-render.js +12 -0
  116. package/dist/src/cli/render.d.ts +1 -1
  117. package/dist/src/cli/render.js +54 -38
  118. package/dist/src/cli/report-ci-jobs.d.ts +23 -0
  119. package/dist/src/cli/report-ci-jobs.js +103 -0
  120. package/dist/src/cli/report-ci-usage.d.ts +9 -0
  121. package/dist/src/cli/report-ci-usage.js +185 -0
  122. package/dist/src/cli/report-ci.d.ts +13 -0
  123. package/dist/src/cli/report-ci.js +74 -0
  124. package/dist/src/cli/report-closures.d.ts +6 -0
  125. package/dist/src/cli/report-closures.js +97 -0
  126. package/dist/src/cli/report-flow.d.ts +7 -0
  127. package/dist/src/cli/report-flow.js +122 -0
  128. package/dist/src/cli/report-github-reader.d.ts +29 -0
  129. package/dist/src/cli/report-github-reader.js +157 -0
  130. package/dist/src/cli/report-github.d.ts +15 -8
  131. package/dist/src/cli/report-github.js +131 -150
  132. package/dist/src/cli/report-operator.d.ts +3 -0
  133. package/dist/src/cli/report-operator.js +40 -0
  134. package/dist/src/cli/report-ready.d.ts +3 -0
  135. package/dist/src/cli/report-ready.js +96 -0
  136. package/dist/src/cli/report-text.d.ts +9 -0
  137. package/dist/src/cli/report-text.js +33 -0
  138. package/dist/src/cli/report.d.ts +1 -0
  139. package/dist/src/cli/report.js +104 -27
  140. package/dist/src/cli/runtime-arguments.d.ts +18 -3
  141. package/dist/src/cli/runtime-arguments.js +29 -20
  142. package/dist/src/cli/schedule-arguments.d.ts +14 -0
  143. package/dist/src/cli/schedule-arguments.js +26 -0
  144. package/dist/src/cli/schedule-render.d.ts +22 -0
  145. package/dist/src/cli/schedule-render.js +73 -0
  146. package/dist/src/cli/terminal-text.d.ts +3 -0
  147. package/dist/src/cli/terminal-text.js +28 -0
  148. package/dist/src/cli/toolchain.d.ts +1 -0
  149. package/dist/src/cli/toolchain.js +1 -0
  150. package/dist/src/cli/usage-render.d.ts +1 -0
  151. package/dist/src/cli/usage-render.js +28 -1
  152. package/dist/src/cli/usage.d.ts +2 -2
  153. package/dist/src/cli/usage.js +89 -11
  154. package/dist/src/cli/watch-actions.js +2 -2
  155. package/dist/src/cli/watch-api-document.d.ts +430 -0
  156. package/dist/src/cli/watch-api-document.js +291 -0
  157. package/dist/src/cli/watch-api-run.d.ts +56 -0
  158. package/dist/src/cli/watch-api-run.js +112 -0
  159. package/dist/src/cli/watch-api.d.ts +17 -0
  160. package/dist/src/cli/watch-api.js +230 -0
  161. package/dist/src/cli/watch-board-view.js +19 -2
  162. package/dist/src/cli/watch-board.d.ts +4 -2
  163. package/dist/src/cli/watch-board.js +53 -43
  164. package/dist/src/cli/watch-card-forms.d.ts +1 -1
  165. package/dist/src/cli/watch-card-forms.js +11 -10
  166. package/dist/src/cli/watch-client.d.ts +1 -1
  167. package/dist/src/cli/watch-client.js +2 -11
  168. package/dist/src/cli/watch-header-view.d.ts +1 -5
  169. package/dist/src/cli/watch-header-view.js +17 -21
  170. package/dist/src/cli/watch-model.d.ts +5 -1
  171. package/dist/src/cli/watch-model.js +20 -11
  172. package/dist/src/cli/watch-page.js +15 -15
  173. package/dist/src/cli/watch-phases.d.ts +12 -3
  174. package/dist/src/cli/watch-phases.js +68 -11
  175. package/dist/src/cli/watch-pr-board.js +1 -1
  176. package/dist/src/cli/watch-pr-command.d.ts +1 -0
  177. package/dist/src/cli/watch-pull-request.js +18 -8
  178. package/dist/src/cli/watch-reads.d.ts +3 -0
  179. package/dist/src/cli/watch-reads.js +22 -20
  180. package/dist/src/cli/watch-render.d.ts +15 -0
  181. package/dist/src/cli/watch-run-input.d.ts +0 -1
  182. package/dist/src/cli/watch-run-input.js +0 -13
  183. package/dist/src/cli/watch-server.js +24 -10
  184. package/dist/src/cli/watch-view.d.ts +0 -3
  185. package/dist/src/cli/watch-view.js +13 -13
  186. package/dist/src/cli.js +73 -12
  187. package/dist/src/command-wait.d.ts +4 -0
  188. package/dist/src/command-wait.js +45 -0
  189. package/dist/src/configuration-change.d.ts +7 -0
  190. package/dist/src/configuration-change.js +14 -0
  191. package/dist/src/configuration-display.js +2 -0
  192. package/dist/src/configuration-schema.d.ts +14 -0
  193. package/dist/src/configuration-schema.js +6 -2
  194. package/dist/src/daemon/attachment-file.d.ts +6 -0
  195. package/dist/src/daemon/attachment-file.js +86 -0
  196. package/dist/src/daemon/attachments.d.ts +14 -0
  197. package/dist/src/daemon/attachments.js +17 -0
  198. package/dist/src/daemon/claude-recovery.d.ts +50 -0
  199. package/dist/src/daemon/claude-recovery.js +208 -0
  200. package/dist/src/daemon/claude-stream.d.ts +27 -0
  201. package/dist/src/daemon/claude-stream.js +63 -0
  202. package/dist/src/daemon/claude-turn.d.ts +11 -25
  203. package/dist/src/daemon/claude-turn.js +64 -81
  204. package/dist/src/daemon/claude-worker.d.ts +5 -4
  205. package/dist/src/daemon/claude-worker.js +127 -126
  206. package/dist/src/daemon/daemon-adapters.d.ts +9 -0
  207. package/dist/src/daemon/daemon-adapters.js +33 -5
  208. package/dist/src/daemon/daemon-loops.d.ts +5 -1
  209. package/dist/src/daemon/daemon-loops.js +18 -10
  210. package/dist/src/daemon/daemon.js +80 -61
  211. package/dist/src/daemon/github-attach.d.ts +2 -0
  212. package/dist/src/daemon/github-attach.js +222 -0
  213. package/dist/src/daemon/github-calls.js +1 -1
  214. package/dist/src/daemon/github-ci-filters.d.ts +6 -0
  215. package/dist/src/daemon/github-ci-filters.js +138 -0
  216. package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
  217. package/dist/src/daemon/github-ci-workflows.js +148 -0
  218. package/dist/src/daemon/github-ci.js +22 -4
  219. package/dist/src/daemon/github-issue-methods.d.ts +2 -0
  220. package/dist/src/daemon/github-issue-methods.js +37 -2
  221. package/dist/src/daemon/github-merge-call.d.ts +2 -1
  222. package/dist/src/daemon/github-merge-call.js +10 -3
  223. package/dist/src/daemon/github-merge.js +52 -24
  224. package/dist/src/daemon/github-methods.js +18 -4
  225. package/dist/src/daemon/github-operation.d.ts +4 -0
  226. package/dist/src/daemon/github-operation.js +6 -0
  227. package/dist/src/daemon/github-worker.d.ts +4 -0
  228. package/dist/src/daemon/github-worker.js +6 -0
  229. package/dist/src/daemon/issue-queue.d.ts +4 -1
  230. package/dist/src/daemon/issue-queue.js +76 -78
  231. package/dist/src/daemon/merge-turns.d.ts +10 -0
  232. package/dist/src/daemon/merge-turns.js +37 -0
  233. package/dist/src/daemon/notify-events.d.ts +6 -0
  234. package/dist/src/daemon/notify-events.js +84 -0
  235. package/dist/src/daemon/notify-journal.js +1 -1
  236. package/dist/src/daemon/notify-message.d.ts +4 -1
  237. package/dist/src/daemon/notify-message.js +36 -0
  238. package/dist/src/daemon/notify.d.ts +1 -1
  239. package/dist/src/daemon/notify.js +5 -77
  240. package/dist/src/daemon/operation-journal.d.ts +1 -0
  241. package/dist/src/daemon/queue-control.d.ts +13 -0
  242. package/dist/src/daemon/queue-control.js +86 -0
  243. package/dist/src/daemon/queue-journal.d.ts +20 -0
  244. package/dist/src/daemon/queue-journal.js +89 -0
  245. package/dist/src/daemon/queue-status.d.ts +9 -3
  246. package/dist/src/daemon/queue-status.js +17 -4
  247. package/dist/src/daemon/record-archive.d.ts +19 -0
  248. package/dist/src/daemon/record-archive.js +82 -0
  249. package/dist/src/daemon/record-sweep.d.ts +24 -0
  250. package/dist/src/daemon/record-sweep.js +147 -0
  251. package/dist/src/daemon/resume-index-lock.d.ts +13 -0
  252. package/dist/src/daemon/resume-index-lock.js +160 -0
  253. package/dist/src/daemon/resume-worktree.d.ts +7 -0
  254. package/dist/src/daemon/resume-worktree.js +29 -0
  255. package/dist/src/daemon/retrying-turn.d.ts +2 -12
  256. package/dist/src/daemon/retrying-turn.js +98 -172
  257. package/dist/src/daemon/schedule-control.d.ts +26 -0
  258. package/dist/src/daemon/schedule-control.js +110 -0
  259. package/dist/src/daemon/schedule-journal.d.ts +2 -15
  260. package/dist/src/daemon/schedule-journal.js +67 -4
  261. package/dist/src/daemon/settings-reload.d.ts +26 -0
  262. package/dist/src/daemon/settings-reload.js +82 -0
  263. package/dist/src/daemon/ticket-registration.d.ts +2 -7
  264. package/dist/src/daemon/ticket-registration.js +15 -81
  265. package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
  266. package/dist/src/daemon/turn-attempt-journal.js +136 -0
  267. package/dist/src/daemon/turn-attempts.d.ts +47 -0
  268. package/dist/src/daemon/turn-attempts.js +166 -0
  269. package/dist/src/daemon/turn-details.d.ts +4 -0
  270. package/dist/src/daemon/turn-details.js +33 -0
  271. package/dist/src/daemon/turn-report.d.ts +8 -1
  272. package/dist/src/daemon/turn-report.js +39 -0
  273. package/dist/src/daemon/work-tree.d.ts +9 -0
  274. package/dist/src/daemon/work-tree.js +20 -0
  275. package/dist/src/daemon/worker-profile.d.ts +9 -0
  276. package/dist/src/daemon/worker-profile.js +44 -0
  277. package/dist/src/daemon/workflow-generations.d.ts +7 -4
  278. package/dist/src/daemon/workflow-generations.js +22 -14
  279. package/dist/src/daemon/workflow-reload.d.ts +41 -0
  280. package/dist/src/daemon/workflow-reload.js +244 -0
  281. package/dist/src/daemon/workflow-replay.d.ts +2 -1
  282. package/dist/src/daemon/workflow-replay.js +7 -3
  283. package/dist/src/daemon/workflow-schedules.d.ts +3 -0
  284. package/dist/src/daemon/workflow-schedules.js +98 -45
  285. package/dist/src/daemon/worktree-processes.d.ts +9 -0
  286. package/dist/src/daemon/worktree-processes.js +151 -0
  287. package/dist/src/doctor-report.d.ts +4 -6
  288. package/dist/src/doctor-report.js +8 -13
  289. package/dist/src/harness-start.d.ts +15 -0
  290. package/dist/src/harness-start.js +37 -0
  291. package/dist/src/host/command-wait.d.ts +38 -0
  292. package/dist/src/host/command-wait.js +115 -0
  293. package/dist/src/host/start-delivery.d.ts +5 -7
  294. package/dist/src/host/start-delivery.js +3 -15
  295. package/dist/src/host/step-bridge-host.d.ts +2 -0
  296. package/dist/src/host/step-bridge-host.js +21 -0
  297. package/dist/src/operation-identity.d.ts +1 -0
  298. package/dist/src/operation-identity.js +4 -0
  299. package/dist/src/private-config.schema.json +71 -0
  300. package/dist/src/project-config.schema.json +40 -0
  301. package/dist/src/project-settings.d.ts +16 -2
  302. package/dist/src/project-settings.js +35 -1
  303. package/dist/src/queue-spend.d.ts +4 -0
  304. package/dist/src/queue-spend.js +21 -0
  305. package/dist/src/queue-state.d.ts +26 -0
  306. package/dist/src/queue-state.js +34 -0
  307. package/dist/src/record-retention.d.ts +46 -0
  308. package/dist/src/record-retention.js +81 -0
  309. package/dist/src/relay/relay-service.d.ts +3 -0
  310. package/dist/src/relay/relay-service.js +5 -3
  311. package/dist/src/report-ci.d.ts +164 -0
  312. package/dist/src/report-ci.js +32 -0
  313. package/dist/src/report-effects.d.ts +15 -0
  314. package/dist/src/report-effects.js +212 -0
  315. package/dist/src/report-flow-types.d.ts +38 -0
  316. package/dist/src/report-flow-types.js +7 -0
  317. package/dist/src/report-flow.d.ts +43 -0
  318. package/dist/src/report-flow.js +193 -0
  319. package/dist/src/report-operator.d.ts +67 -0
  320. package/dist/src/report-operator.js +25 -0
  321. package/dist/src/report-quality.d.ts +221 -0
  322. package/dist/src/report-quality.js +94 -0
  323. package/dist/src/report-ready.d.ts +23 -0
  324. package/dist/src/report-ready.js +117 -0
  325. package/dist/src/report-statistics.d.ts +2 -1
  326. package/dist/src/report-statistics.js +40 -4
  327. package/dist/src/report.d.ts +588 -47
  328. package/dist/src/report.js +156 -41
  329. package/dist/src/schedule-progress.d.ts +33 -0
  330. package/dist/src/schedule-progress.js +45 -0
  331. package/dist/src/service/active-tickets.js +11 -6
  332. package/dist/src/service/command-waits.d.ts +34 -0
  333. package/dist/src/service/command-waits.js +86 -0
  334. package/dist/src/service/dispatcher.d.ts +4 -0
  335. package/dist/src/service/dispatcher.js +33 -0
  336. package/dist/src/service/expiry.js +2 -0
  337. package/dist/src/service/gateway.js +3 -1
  338. package/dist/src/service/queue-handlers.d.ts +4 -0
  339. package/dist/src/service/queue-handlers.js +32 -0
  340. package/dist/src/service/queue-spend.d.ts +6 -0
  341. package/dist/src/service/queue-spend.js +68 -0
  342. package/dist/src/service/registry.d.ts +28 -2
  343. package/dist/src/service/registry.js +48 -0
  344. package/dist/src/service/replies.d.ts +22 -8
  345. package/dist/src/service/replies.js +16 -2
  346. package/dist/src/service/run-handlers.js +37 -12
  347. package/dist/src/service/run-metadata.d.ts +15 -1
  348. package/dist/src/service/run-metadata.js +93 -8
  349. package/dist/src/service/service.d.ts +11 -3
  350. package/dist/src/service/service.js +22 -37
  351. package/dist/src/service/submission-handler.js +18 -4
  352. package/dist/src/service/worker-port.js +9 -1
  353. package/dist/src/service/worker-totals.d.ts +6 -0
  354. package/dist/src/service/worker-totals.js +8 -1
  355. package/dist/src/service/workflow-reload.d.ts +35 -0
  356. package/dist/src/service/workflow-reload.js +52 -0
  357. package/dist/src/step-bridge.d.ts +20 -0
  358. package/dist/src/steps/command-wait.d.ts +12 -0
  359. package/dist/src/steps/command-wait.js +26 -0
  360. package/dist/src/steps/open-decision-wait.d.ts +2 -0
  361. package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
  362. package/dist/src/steps/review-by-person.js +4 -1
  363. package/dist/src/steps/wait-for-command.d.ts +3 -0
  364. package/dist/src/steps/wait-for-command.js +17 -0
  365. package/dist/src/steps/wait-for-decision.js +1 -1
  366. package/dist/src/storage/command-wait-rows.d.ts +30 -0
  367. package/dist/src/storage/command-wait-rows.js +96 -0
  368. package/dist/src/storage/decision-snapshots.d.ts +8 -2
  369. package/dist/src/storage/decision-snapshots.js +16 -8
  370. package/dist/src/storage/domain-changes.d.ts +3 -1
  371. package/dist/src/storage/domain-changes.js +4 -0
  372. package/dist/src/storage/domain-schema.d.ts +16 -1
  373. package/dist/src/storage/domain-schema.js +35 -4
  374. package/dist/src/storage/effect-schema.d.ts +2 -0
  375. package/dist/src/storage/effect-schema.js +9 -0
  376. package/dist/src/storage/projection-changes.d.ts +12 -0
  377. package/dist/src/storage/projection-changes.js +194 -0
  378. package/dist/src/storage/projection-lookups.d.ts +7 -0
  379. package/dist/src/storage/projection-lookups.js +30 -0
  380. package/dist/src/testing-requests.d.ts +15 -0
  381. package/dist/src/testing-requests.js +93 -0
  382. package/dist/src/testing.d.ts +4 -10
  383. package/dist/src/testing.js +33 -86
  384. package/dist/src/worker-usage.d.ts +1 -0
  385. package/dist/src/worker-usage.js +3 -0
  386. package/dist/src/workflow-candidate.d.ts +1 -0
  387. package/dist/src/workflow-candidate.js +12 -1
  388. package/dist/src/workflow-contracts.d.ts +1 -0
  389. package/dist/src/workflow-contracts.js +9 -2
  390. package/dist/src/workflow-declaration.d.ts +1 -0
  391. package/dist/src/workflow-declaration.js +3 -0
  392. package/dist/src/workflow-discovery.d.ts +2 -13
  393. package/dist/src/workflow-discovery.js +1 -13
  394. package/dist/src/workflow-refusals.js +0 -1
  395. package/dist/src/workflows.d.ts +1 -1
  396. package/dist/src/workflows.js +1 -1
  397. package/dist/tools/compile-workflows.js +3 -0
  398. package/dist/tools/project-configuration.d.ts +7 -2
  399. package/dist/tools/project-configuration.js +30 -1
  400. package/dist/tools/red-green-command.d.ts +1 -0
  401. package/dist/tools/red-green-command.js +174 -0
  402. package/dist/tools/red-green-process.d.ts +10 -0
  403. package/dist/tools/red-green-process.js +59 -0
  404. package/dist/tools/self-host-processes.d.ts +2 -0
  405. package/dist/tools/self-host-processes.js +69 -26
  406. package/dist/tools/self-host-project.d.ts +2 -0
  407. package/dist/tools/self-host-project.js +30 -77
  408. package/dist/tools/self-host-runtime.js +1 -1
  409. package/dist/tools/self-host.js +76 -34
  410. package/dist/tools/template-command.d.ts +1 -0
  411. package/dist/tools/template-command.js +160 -0
  412. package/dist/tools/template-copy.d.ts +11 -0
  413. package/dist/tools/template-copy.js +130 -0
  414. package/dist/tools/template-files.d.ts +17 -0
  415. package/dist/tools/template-files.js +74 -0
  416. package/dist/tools/workflow-bundles.js +1 -0
  417. package/dist/tools/workflow-candidate-counts.js +2 -2
  418. package/dist/tools/workflow-candidate-program.d.ts +4 -2
  419. package/dist/tools/workflow-candidate-program.js +30 -11
  420. package/dist/tools/workflow-candidate-shape.d.ts +3 -0
  421. package/dist/tools/workflow-candidate-shape.js +90 -0
  422. package/dist/tools/workflow-candidate-source.d.ts +1 -0
  423. package/dist/tools/workflow-candidate-source.js +26 -4
  424. package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
  425. package/dist/tools/workflow-candidate-syntax.js +24 -94
  426. package/dist/tools/workflow-command.js +1 -2
  427. package/dist/tools/workflow-folders.d.ts +2 -3
  428. package/dist/tools/workflow-folders.js +1 -1
  429. package/package.json +17 -9
  430. package/templates/develop/README.md +93 -4
  431. package/templates/develop/develop/flow-tests.ts +38 -1
  432. package/templates/develop/develop/interruption-tests.ts +157 -0
  433. package/templates/develop/develop/local.ts +1 -0
  434. package/templates/develop/develop/option-tests.ts +138 -9
  435. package/templates/develop/develop/pull.ts +5 -1
  436. package/templates/develop/develop/red-green.ts +55 -0
  437. package/templates/develop/develop/refusal-tests.ts +77 -0
  438. package/templates/develop/develop/report.ts +31 -11
  439. package/templates/develop/develop/round.ts +1 -0
  440. package/templates/develop/develop/scenarios.ts +27 -0
  441. package/templates/develop/develop/turn.ts +28 -7
  442. package/templates/develop/develop.declaration.json +1 -1
  443. package/templates/develop/develop.test.ts +4 -0
  444. package/templates/develop/template.json +29 -2
  445. package/templates/idea-to-issue/README.md +27 -0
  446. package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
  447. package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
  448. package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
  449. package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
  450. package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
  451. package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
  452. package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
  453. package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
  454. package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
  455. package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
  456. package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
  457. package/templates/idea-to-issue/idea-to-issue.ts +49 -0
  458. package/templates/idea-to-issue/template.json +81 -0
  459. package/templates/review-day/README.md +97 -0
  460. package/templates/review-day/review-day/critique.ts +58 -0
  461. package/templates/review-day/review-day/decision.ts +29 -0
  462. package/templates/review-day/review-day/facts.ts +69 -0
  463. package/templates/review-day/review-day/label.ts +29 -0
  464. package/templates/review-day/review-day/next.ts +28 -0
  465. package/templates/review-day/review-day/post.ts +27 -0
  466. package/templates/review-day/review-day/report.ts +98 -0
  467. package/templates/review-day/review-day/rules.ts +12 -0
  468. package/templates/review-day/review-day/scenarios.ts +76 -0
  469. package/templates/review-day/review-day/turn.ts +73 -0
  470. package/templates/review-day/review-day.declaration.json +16 -0
  471. package/templates/review-day/review-day.test.ts +362 -0
  472. package/templates/review-day/review-day.ts +37 -0
  473. package/templates/review-day/template.json +56 -0
  474. package/dist/src/cli/watch-start-view.d.ts +0 -18
  475. package/dist/src/cli/watch-start-view.js +0 -77
  476. package/dist/src/steps/decision-gate.d.ts +0 -3
  477. package/dist/workflows/develop-prd.d.ts +0 -7
  478. package/dist/workflows/develop-prd.js +0 -165
  479. package/dist/workflows/develop-ticket.d.ts +0 -9
  480. package/dist/workflows/develop-ticket.js +0 -207
  481. package/dist/workflows/issue-labels.d.ts +0 -16
  482. package/dist/workflows/issue-labels.js +0 -70
  483. package/dist/workflows/ticket-prompts.d.ts +0 -35
  484. package/dist/workflows/ticket-prompts.js +0 -147
@@ -0,0 +1,160 @@
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import { absoluteWorkflowFolder } from "../src/project-settings.js";
6
+ import { record } from "../src/protocol.js";
7
+ import { isCandidateDeclaration } from "../src/workflow-candidate.js";
8
+ import { projectConfiguration, projectRoot } from "./project-configuration.js";
9
+ import { copyTemplate } from "./template-copy.js";
10
+ import { exportedFunctions, readTemplate, templateList, templateRoot, } from "./template-files.js";
11
+ import { userLocation } from "./workflow-folders.js";
12
+ const usage = "Usage: cloving templates list [--json]\n cloving templates show <name> [--json]\n cloving templates copy <name> [--id <workflow-id>] [--json] [--repository <directory>]\n";
13
+ function invocation(argumentsList) {
14
+ const { values, positionals } = parseArgs({
15
+ args: [...argumentsList],
16
+ allowPositionals: true,
17
+ options: {
18
+ json: { type: "boolean" },
19
+ id: { type: "string" },
20
+ repository: { type: "string" },
21
+ help: { type: "boolean", short: "h" },
22
+ },
23
+ });
24
+ const [command, name, ...extra] = positionals;
25
+ if (values.help === true)
26
+ return { ...values, command: "help", name: "" };
27
+ if (!["list", "show", "copy"].includes(command ?? ""))
28
+ throw new Error("unknown-command");
29
+ if (extra.length > 0 || (command === "list") !== (name === undefined))
30
+ throw new Error("unexpected-argument");
31
+ if (command !== "copy" && (values.id !== undefined || values.repository))
32
+ throw new Error("unexpected-option");
33
+ return { ...values, command, name: name ?? "" };
34
+ }
35
+ export async function templateCommand(argumentsList) {
36
+ let selected;
37
+ try {
38
+ selected = invocation(argumentsList);
39
+ }
40
+ catch {
41
+ process.stderr.write("invalid-invocation: " + usage);
42
+ return 2;
43
+ }
44
+ if (selected.help) {
45
+ process.stdout.write(usage);
46
+ return 0;
47
+ }
48
+ try {
49
+ const root = templateRoot();
50
+ const json = selected.json === true;
51
+ if (selected.command === "list")
52
+ return await listed(root, { json });
53
+ if (selected.command === "show")
54
+ return await shown(root, { name: selected.name, json });
55
+ return await copied(root, {
56
+ name: selected.name,
57
+ id: selected.id ?? selected.name,
58
+ json,
59
+ repository: selected.repository ?? process.cwd(),
60
+ });
61
+ }
62
+ catch (error) {
63
+ process.stderr.write((error instanceof Error ? error.message : "template-command-failed") +
64
+ "\n");
65
+ return 1;
66
+ }
67
+ }
68
+ async function listed(root, input) {
69
+ const templates = await templateList(root);
70
+ if (input.json)
71
+ process.stdout.write(JSON.stringify(templates) + "\n");
72
+ else
73
+ for (const template of templates)
74
+ process.stdout.write(`${template.name}: ${template.summary} (${String(template.points)} decision points)\n`);
75
+ return 0;
76
+ }
77
+ async function shown(root, input) {
78
+ const template = await readTemplate(root, input.name);
79
+ if (input.json) {
80
+ process.stdout.write(JSON.stringify({
81
+ template: template.description,
82
+ files: template.files,
83
+ }) + "\n");
84
+ return 0;
85
+ }
86
+ process.stdout.write(`${template.name}: ${String(template.description["summary"])}\n${pointText(template.points)}Files:\n${template.files.map((file) => ` ${file}\n`).join("")}`);
87
+ return 0;
88
+ }
89
+ async function copied(root, input) {
90
+ const repository = await projectRoot(input.repository);
91
+ const folder = join(repository, ".cloving", "workflows");
92
+ const folders = [folder, await userFolder(repository)];
93
+ const packageRoot = dirname(root);
94
+ const takenNames = await exportedFunctions([
95
+ join(packageRoot, "workflows"),
96
+ join(packageRoot, "dist", "workflows"),
97
+ ...folders,
98
+ ]);
99
+ const result = await copyTemplate({ ...input, root, folder, takenNames });
100
+ const queued = (await Promise.all(folders.map(queuedIn))).flat().sort();
101
+ if (input.json)
102
+ process.stdout.write(JSON.stringify({
103
+ workflowId: input.id,
104
+ template: input.name,
105
+ files: result.files,
106
+ queueWorkflows: queued,
107
+ }) + "\n");
108
+ else
109
+ process.stdout.write(`Copied the template ${input.name} to .cloving/workflows as the workflow ${input.id}.\nDecision points:\n${pointText(result.template.points)}Next: cloving workflows test ${input.id}\n`);
110
+ if (queued.length > 1)
111
+ process.stderr.write(`queue-workflow-conflict: ${queued.join(", ")} have "queue": true. Select "a person" for the select point of one copy: remove workflow.queue from its declaration.\n`);
112
+ return 0;
113
+ }
114
+ function pointText(points) {
115
+ return points
116
+ .map((value) => {
117
+ const point = record(value);
118
+ const options = point?.["options"];
119
+ const lines = (Array.isArray(options) ? options : []).map((option, index) => {
120
+ const fields = record(option);
121
+ return ` - ${String(fields?.["id"])}: ${String(fields?.["label"])}${index === 0 ? " (default)" : ""}\n`;
122
+ });
123
+ return ` ${String(point?.["id"])}: ${String(point?.["question"])}\n${lines.join("")}`;
124
+ })
125
+ .join("");
126
+ }
127
+ async function userFolder(repository) {
128
+ const settings = await projectConfiguration(repository, process.env);
129
+ const user = userLocation({
130
+ home: homedir(),
131
+ xdgConfigHome: process.env["XDG_CONFIG_HOME"],
132
+ userFolder: absoluteWorkflowFolder(settings.environment["CLOVING_WORKFLOW_FOLDER"]),
133
+ });
134
+ return join(user.root, ...user.parts);
135
+ }
136
+ async function queuedIn(folder) {
137
+ const names = await readdir(folder).catch(() => []);
138
+ const ids = await Promise.all(names
139
+ .filter((name) => name.endsWith(".declaration.json"))
140
+ .map((name) => queuedId(folder, name)));
141
+ return ids.flatMap((id) => (id === undefined ? [] : [id]));
142
+ }
143
+ async function queuedId(folder, name) {
144
+ const text = await readFile(join(folder, name), "utf8").catch(() => "");
145
+ let declaration;
146
+ try {
147
+ declaration = JSON.parse(text);
148
+ }
149
+ catch {
150
+ return undefined;
151
+ }
152
+ if (!isCandidateDeclaration(declaration) ||
153
+ declaration.workflow.queue !== true)
154
+ return undefined;
155
+ const source = join(folder, name.replace(/\.declaration\.json$/, ".ts"));
156
+ const entry = await stat(source).catch(() => undefined);
157
+ return entry?.isFile() === true ? declaration.workflow.workflowId : undefined;
158
+ }
159
+ if (process.argv[1] === import.meta.filename)
160
+ process.exitCode = await templateCommand(process.argv.slice(2));
@@ -0,0 +1,11 @@
1
+ import { type Template } from "./template-files.ts";
2
+ export declare function copyTemplate(input: {
3
+ readonly root: string;
4
+ readonly name: string;
5
+ readonly id: string;
6
+ readonly folder: string;
7
+ readonly takenNames: ReadonlySet<string>;
8
+ }): Promise<{
9
+ readonly template: Template;
10
+ readonly files: readonly string[];
11
+ }>;
@@ -0,0 +1,130 @@
1
+ import { link, mkdir, mkdtemp, readFile, rm, writeFile, } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import ts from "typescript";
4
+ import { record } from "../src/protocol.js";
5
+ import { readTemplate, templateName } from "./template-files.js";
6
+ export async function copyTemplate(input) {
7
+ if (!templateName.test(input.id) || input.id.length > 64)
8
+ throw new Error(`invalid-workflow-id: ${input.id}`);
9
+ const template = await readTemplate(input.root, input.name);
10
+ const sources = await Promise.all(template.files.map(async (file) => ({
11
+ file,
12
+ text: await readFile(join(input.root, input.name, file), "utf8"),
13
+ })));
14
+ const renaming = functionRenaming(sources, input);
15
+ const plan = sources.map(({ file, text }) => ({
16
+ target: input.id + file.slice(input.name.length),
17
+ content: copiedContent({ file, text }, renaming),
18
+ }));
19
+ await writePlan(input.folder, plan);
20
+ return { template, files: plan.map((item) => item.target) };
21
+ }
22
+ function camelName(id) {
23
+ return id.replace(/-([a-z0-9])/g, (_, letter) => letter.toUpperCase());
24
+ }
25
+ function functionRenaming(sources, input) {
26
+ const from = camelName(input.name);
27
+ const names = new Set(sources
28
+ .filter(({ file }) => file.endsWith(".ts"))
29
+ .flatMap(({ text }) => text.match(/[A-Za-z_$][\w$]*/g) ?? []));
30
+ for (const name of input.takenNames)
31
+ names.add(name);
32
+ let to = camelName(input.id);
33
+ while (to !== from && (names.has(to) || reservedWord(to)))
34
+ to += "Workflow";
35
+ return { template: input.name, id: input.id, from, to };
36
+ }
37
+ function reservedWord(name) {
38
+ const scanner = ts.createScanner(ts.ScriptTarget.Latest, true);
39
+ scanner.setText(name);
40
+ const kind = scanner.scan();
41
+ return ((kind >= ts.SyntaxKind.FirstReservedWord &&
42
+ kind <= ts.SyntaxKind.LastFutureReservedWord) ||
43
+ ["await", "eval", "arguments"].includes(name));
44
+ }
45
+ function copiedContent(source, renaming) {
46
+ const { file, text } = source;
47
+ if (file.endsWith(".declaration.json"))
48
+ return copiedDeclaration(text, renaming);
49
+ if (!file.endsWith(".ts") || renaming.id === renaming.template)
50
+ return text;
51
+ return renamedSource(source, renaming);
52
+ }
53
+ function copiedDeclaration(text, renaming) {
54
+ const declaration = record(JSON.parse(text));
55
+ const workflow = record(declaration?.["workflow"]);
56
+ if (declaration === undefined || workflow === undefined)
57
+ throw new Error(`invalid-template: ${renaming.template}`);
58
+ return (JSON.stringify({
59
+ template: renaming.template,
60
+ ...declaration,
61
+ workflow: { ...workflow, workflowId: renaming.id },
62
+ }, null, 2) + "\n");
63
+ }
64
+ function renamedSource(input, renaming) {
65
+ const { file, text } = input;
66
+ const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
67
+ const edits = [];
68
+ const prefix = new RegExp(`^(\\.\\.?/)${renaming.template}(?=[./])`);
69
+ const visit = (node) => {
70
+ if (ts.isIdentifier(node) && node.text === renaming.from)
71
+ edits.push({ start: node.getStart(), end: node.end, text: renaming.to });
72
+ if (ts.isStringLiteral(node) &&
73
+ (ts.isImportDeclaration(node.parent) ||
74
+ ts.isExportDeclaration(node.parent)) &&
75
+ prefix.test(node.text))
76
+ edits.push({
77
+ start: node.getStart() + 1,
78
+ end: node.end - 1,
79
+ text: node.text.replace(prefix, `$1${renaming.id}`),
80
+ });
81
+ ts.forEachChild(node, visit);
82
+ };
83
+ visit(source);
84
+ return edits
85
+ .sort((left, right) => right.start - left.start)
86
+ .reduce((current, edit) => current.slice(0, edit.start) + edit.text + current.slice(edit.end), text);
87
+ }
88
+ async function writePlan(folder, plan) {
89
+ await mkdir(folder, { recursive: true });
90
+ const staging = await mkdtemp(join(dirname(folder), ".template-copy-"));
91
+ const created = [];
92
+ try {
93
+ for (const item of plan) {
94
+ await mkdir(dirname(join(staging, item.target)), { recursive: true });
95
+ await writeFile(join(staging, item.target), item.content);
96
+ }
97
+ for (const item of plan)
98
+ await placed({ folder, staging, item }, created);
99
+ }
100
+ catch (error) {
101
+ for (const path of created.reverse())
102
+ await rm(path, { recursive: true, force: true });
103
+ throw error;
104
+ }
105
+ finally {
106
+ await rm(staging, { recursive: true, force: true });
107
+ }
108
+ }
109
+ async function placed(input, created) {
110
+ const parts = input.item.target.split("/");
111
+ for (let depth = 1; depth < parts.length; depth += 1) {
112
+ const directory = join(input.folder, ...parts.slice(0, depth));
113
+ if (created.includes(directory))
114
+ continue;
115
+ await mkdir(directory).catch((error) => {
116
+ throw present(error, parts.slice(0, depth).join("/"));
117
+ });
118
+ created.push(directory);
119
+ }
120
+ const target = join(input.folder, input.item.target);
121
+ await link(join(input.staging, input.item.target), target).catch((error) => {
122
+ throw present(error, input.item.target);
123
+ });
124
+ created.push(target);
125
+ }
126
+ function present(error, target) {
127
+ return error instanceof Error && "code" in error && error.code === "EEXIST"
128
+ ? new Error(`workflow-exists: ${target}`)
129
+ : error;
130
+ }
@@ -0,0 +1,17 @@
1
+ import { type Fields } from "../src/protocol.ts";
2
+ export interface TemplateSummary {
3
+ readonly name: string;
4
+ readonly summary: string;
5
+ readonly points: number;
6
+ }
7
+ export interface Template {
8
+ readonly name: string;
9
+ readonly description: Fields;
10
+ readonly points: readonly unknown[];
11
+ readonly files: readonly string[];
12
+ }
13
+ export declare const templateName: RegExp;
14
+ export declare function templateRoot(start?: string): string;
15
+ export declare function templateList(root: string): Promise<readonly TemplateSummary[]>;
16
+ export declare function readTemplate(root: string, name: string): Promise<Template>;
17
+ export declare function exportedFunctions(folders: readonly string[]): Promise<ReadonlySet<string>>;
@@ -0,0 +1,74 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { record } from "../src/protocol.js";
5
+ export const templateName = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
6
+ const descriptionFiles = ["template.json", "README.md"];
7
+ export function templateRoot(start = import.meta.dirname) {
8
+ let directory = start;
9
+ while (!existsSync(join(directory, "package.json"))) {
10
+ const parent = dirname(directory);
11
+ if (parent === directory)
12
+ throw new Error("templates-not-found");
13
+ directory = parent;
14
+ }
15
+ return join(directory, "templates");
16
+ }
17
+ export async function templateList(root) {
18
+ const entries = await readdir(root, { withFileTypes: true });
19
+ const names = entries
20
+ .filter((entry) => entry.isDirectory() && templateName.test(entry.name))
21
+ .map((entry) => entry.name)
22
+ .sort();
23
+ const templates = await Promise.all(names.map((name) => readTemplate(root, name).catch(() => undefined)));
24
+ return templates.flatMap((template) => template === undefined
25
+ ? []
26
+ : [
27
+ {
28
+ name: template.name,
29
+ summary: String(template.description["summary"]),
30
+ points: template.points.length,
31
+ },
32
+ ]);
33
+ }
34
+ export async function readTemplate(root, name) {
35
+ if (!templateName.test(name))
36
+ throw new Error(`unknown-template: ${name}`);
37
+ const folder = join(root, name);
38
+ const text = await readFile(join(folder, "template.json"), "utf8").catch(() => {
39
+ throw new Error(`unknown-template: ${name}`);
40
+ });
41
+ const description = record(JSON.parse(text));
42
+ const points = description?.["points"];
43
+ if (description === undefined ||
44
+ typeof description["summary"] !== "string" ||
45
+ !Array.isArray(points))
46
+ throw new Error(`invalid-template: ${name}`);
47
+ return { name, description, points, files: await workflowFiles(folder) };
48
+ }
49
+ export async function exportedFunctions(folders) {
50
+ const names = new Set();
51
+ for (const folder of folders) {
52
+ const files = await readdir(folder).catch(() => []);
53
+ for (const file of files.filter((name) => /^[^.].*(?<!\.test|\.d)\.[jt]s$/.test(name))) {
54
+ const text = await readFile(join(folder, file), "utf8").catch(() => "");
55
+ for (const match of text.matchAll(/export\s+(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/g))
56
+ names.add(String(match[1]));
57
+ }
58
+ }
59
+ return names;
60
+ }
61
+ async function workflowFiles(folder) {
62
+ const entries = await readdir(folder, {
63
+ recursive: true,
64
+ withFileTypes: true,
65
+ });
66
+ return entries
67
+ .filter((entry) => entry.isFile())
68
+ .map((entry) => join(entry.parentPath, entry.name)
69
+ .slice(folder.length + 1)
70
+ .split("\\")
71
+ .join("/"))
72
+ .filter((file) => !descriptionFiles.includes(file))
73
+ .sort();
74
+ }
@@ -153,6 +153,7 @@ export async function retainWorkflowBundle(input) {
153
153
  }
154
154
  const temporary = await mkdtemp(join(input.directory, ".pending-"));
155
155
  try {
156
+ await mkdir(join(temporary, "workflows"), { mode: 0o700 });
156
157
  for (const { name, bytes } of files) {
157
158
  const path = join(temporary, name);
158
159
  await mkdir(dirname(path), { recursive: true, mode: 0o700 });
@@ -1,5 +1,5 @@
1
1
  import ts from "typescript";
2
- import { protectedCall, helperCall, } from "./workflow-candidate-syntax.js";
2
+ import { protectedCall, commandWaitCall, helperCall, } from "./workflow-candidate-syntax.js";
3
3
  import { propertyName } from "./workflow-candidate-fields.js";
4
4
  import { referenceSymbol } from "./workflow-source-effects.js";
5
5
  const zero = { knownCallCount: 0, knownUnitTotal: 0 };
@@ -218,7 +218,7 @@ function nodeTotals(node, input) {
218
218
  if (local && ts.isFunctionLike(node))
219
219
  return local;
220
220
  let total = local ??
221
- (protectedCall(node, input.symbols)
221
+ (protectedCall(node, input.symbols) && !commandWaitCall(node, input.symbols)
222
222
  ? { knownCallCount: 1, knownUnitTotal: units(node, input.symbols) }
223
223
  : zero);
224
224
  ts.forEachChild(node, (child) => {
@@ -5,9 +5,11 @@ export interface CandidatePackageOptions {
5
5
  readonly helpers?: Readonly<Record<string, string>>;
6
6
  }
7
7
  export declare function resolvedSymbol(checker: ts.TypeChecker, symbol: ts.Symbol | undefined): ts.Symbol | undefined;
8
- export declare function candidateProgram(text: string, installed?: CandidatePackageOptions): {
8
+ export interface CandidateProgram {
9
9
  readonly program: ts.Program;
10
10
  readonly source: ts.SourceFile;
11
11
  readonly sources: readonly ts.SourceFile[];
12
12
  readonly modules: ReadonlyMap<string, ts.SourceFile>;
13
- };
13
+ }
14
+ export declare function candidateProgram(text: string, installed?: CandidatePackageOptions): CandidateProgram;
15
+ export declare function candidateCompiler(installed?: CandidatePackageOptions): (text: string) => CandidateProgram;
@@ -10,9 +10,12 @@ export function resolvedSymbol(checker, symbol) {
10
10
  return checker.getAliasedSymbol(symbol);
11
11
  }
12
12
  export function candidateProgram(text, installed = {}) {
13
+ return candidateCompiler(installed)(text);
14
+ }
15
+ export function candidateCompiler(installed = {}) {
13
16
  const packageRoot = resolve(installed.packageRoot ?? candidatePackageRoot);
14
17
  const candidate = join(packageRoot, "candidate.ts");
15
- const sources = new Map([[candidate, text]]);
18
+ const sources = new Map([[candidate, ""]]);
16
19
  for (const [name, content] of Object.entries(installed.helpers ?? {})) {
17
20
  if (workflowHelperPath("candidate.ts", `./${name}`) !== name)
18
21
  throw new Error("invalid-workflow-helper");
@@ -32,12 +35,18 @@ export function candidateProgram(text, installed = {}) {
32
35
  noEmit: true,
33
36
  };
34
37
  const host = trustedHost({ sources, options, entries, packageRoot });
35
- const program = ts.createProgram([...sources.keys(), ...entries.values()], options, host);
36
- const source = program.getSourceFile(candidate);
38
+ return (text) => {
39
+ sources.set(candidate, text);
40
+ const program = ts.createProgram([...sources.keys(), ...entries.values()], options, host);
41
+ return compiledCandidate(program, { candidate, sources, entries });
42
+ };
43
+ }
44
+ function compiledCandidate(program, input) {
45
+ const source = program.getSourceFile(input.candidate);
37
46
  if (!source)
38
47
  throw new Error("candidate-analysis-unavailable");
39
48
  const modules = new Map();
40
- for (const [name, file] of entries) {
49
+ for (const [name, file] of input.entries) {
41
50
  const declaration = program.getSourceFile(file);
42
51
  if (!declaration)
43
52
  throw new Error("candidate-surface-unavailable");
@@ -47,7 +56,7 @@ export function candidateProgram(text, installed = {}) {
47
56
  program,
48
57
  source,
49
58
  modules,
50
- sources: [...sources.keys()].map((name) => {
59
+ sources: [...input.sources.keys()].map((name) => {
51
60
  const entry = program.getSourceFile(name);
52
61
  if (!entry)
53
62
  throw new Error("candidate-analysis-unavailable");
@@ -55,6 +64,21 @@ export function candidateProgram(text, installed = {}) {
55
64
  }),
56
65
  };
57
66
  }
67
+ function sourceReader(readFile) {
68
+ const declarations = new Map();
69
+ return (file, languageVersion) => {
70
+ const content = readFile(file);
71
+ if (content === undefined)
72
+ return undefined;
73
+ const cached = declarations.get(file);
74
+ if (cached?.text === content)
75
+ return cached;
76
+ const source = ts.createSourceFile(file, content, languageVersion, true);
77
+ if (file.endsWith(".d.ts"))
78
+ declarations.set(file, source);
79
+ return source;
80
+ };
81
+ }
58
82
  function trustedHost(input) {
59
83
  const { sources, options, entries, packageRoot } = input;
60
84
  const libraries = dirname(ts.getDefaultLibFilePath(options)) + sep;
@@ -72,12 +96,7 @@ function trustedHost(input) {
72
96
  const host = ts.createCompilerHost(options);
73
97
  host.readFile = readFile;
74
98
  host.fileExists = (file) => readFile(file) !== undefined;
75
- host.getSourceFile = (file, languageVersion) => {
76
- const content = readFile(file);
77
- return content === undefined
78
- ? undefined
79
- : ts.createSourceFile(file, content, languageVersion, true);
80
- };
99
+ host.getSourceFile = sourceReader(readFile);
81
100
  host.resolveModuleNameLiterals = (names, containingFile) => names.map(({ text: name }) => {
82
101
  const installed = entries.get(name);
83
102
  if (installed)
@@ -0,0 +1,3 @@
1
+ import ts from "typescript";
2
+ export declare function workflowShape(source: ts.SourceFile): boolean;
3
+ export declare function passiveCandidateModule(source: ts.SourceFile, kind?: "workflow" | "helper"): boolean;
@@ -0,0 +1,90 @@
1
+ import ts from "typescript";
2
+ export function workflowShape(source) {
3
+ const exported = source.statements.filter((node) => ts.isFunctionDeclaration(node) &&
4
+ (ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
5
+ const candidate = exported[0];
6
+ if (exported.length !== 1 ||
7
+ !candidate ||
8
+ !ts.isFunctionDeclaration(candidate))
9
+ return false;
10
+ if (!workflowFunction(candidate))
11
+ return false;
12
+ const directives = [];
13
+ function visit(node) {
14
+ if (ts.isStringLiteral(node) && node.text === "use workflow")
15
+ directives.push(node);
16
+ ts.forEachChild(node, visit);
17
+ }
18
+ visit(source);
19
+ return directives.length === 1;
20
+ }
21
+ function workflowFunction(candidate) {
22
+ if (!candidate.name || !candidate.body || candidate.asteriskToken)
23
+ return false;
24
+ const modifiers = ts.getModifiers(candidate) ?? [];
25
+ if (!modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ||
26
+ modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword))
27
+ return false;
28
+ const first = candidate.body.statements[0];
29
+ return first !== undefined && workflowDirective(first);
30
+ }
31
+ function workflowDirective(node) {
32
+ return (ts.isExpressionStatement(node) &&
33
+ ts.isStringLiteral(node.expression) &&
34
+ node.expression.text === "use workflow");
35
+ }
36
+ function unwrappedInitializer(node) {
37
+ if (ts.isParenthesizedExpression(node) ||
38
+ ts.isAsExpression(node) ||
39
+ ts.isSatisfiesExpression(node) ||
40
+ ts.isTypeAssertionExpression(node))
41
+ return node.expression;
42
+ return undefined;
43
+ }
44
+ function passiveCompound(node) {
45
+ if (ts.isArrayLiteralExpression(node))
46
+ return node.elements.every((element) => ts.isOmittedExpression(element) || passiveInitializer(element));
47
+ if (ts.isObjectLiteralExpression(node))
48
+ return node.properties.every((property) => ts.isPropertyAssignment(property) &&
49
+ !ts.isComputedPropertyName(property.name) &&
50
+ passiveInitializer(property.initializer));
51
+ return false;
52
+ }
53
+ function passiveInitializer(node) {
54
+ if (!node)
55
+ return false;
56
+ if (ts.isLiteralExpression(node))
57
+ return true;
58
+ if ([
59
+ ts.SyntaxKind.TrueKeyword,
60
+ ts.SyntaxKind.FalseKeyword,
61
+ ts.SyntaxKind.NullKeyword,
62
+ ].includes(node.kind))
63
+ return true;
64
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
65
+ return true;
66
+ if (ts.isPrefixUnaryExpression(node))
67
+ return ([ts.SyntaxKind.PlusToken, ts.SyntaxKind.MinusToken].includes(node.operator) && ts.isNumericLiteral(node.operand));
68
+ const inner = unwrappedInitializer(node);
69
+ return inner ? passiveInitializer(inner) : passiveCompound(node);
70
+ }
71
+ function passiveStatement(node, kind) {
72
+ if (ts.isVariableStatement(node))
73
+ return ((node.declarationList.flags & ts.NodeFlags.Const) !== 0 &&
74
+ node.declarationList.declarations.every((declaration) => (kind === "helper" ||
75
+ (ts.getCombinedModifierFlags(declaration) &
76
+ ts.ModifierFlags.Export) ===
77
+ 0) &&
78
+ ts.isIdentifier(declaration.name) &&
79
+ passiveInitializer(declaration.initializer)));
80
+ if (ts.isExpressionStatement(node))
81
+ return ts.isStringLiteral(node.expression);
82
+ return (ts.isImportDeclaration(node) ||
83
+ ts.isTypeAliasDeclaration(node) ||
84
+ ts.isInterfaceDeclaration(node) ||
85
+ ts.isFunctionDeclaration(node) ||
86
+ ts.isEmptyStatement(node));
87
+ }
88
+ export function passiveCandidateModule(source, kind = "workflow") {
89
+ return source.statements.every((node) => passiveStatement(node, kind));
90
+ }
@@ -1,5 +1,6 @@
1
1
  import { type CandidatePackageOptions } from "./workflow-candidate-program.ts";
2
2
  import type { CandidateAnalysis, InstalledWorkflowExports } from "../src/workflow-candidate.ts";
3
+ export declare function createWorkflowCandidateAnalyzer(installed?: CandidatePackageOptions): (text: string) => ReturnType<typeof analyzeWorkflowCandidate>;
3
4
  export declare function analyzeWorkflowCandidate(text: string, installed?: CandidatePackageOptions): {
4
5
  readonly analysis: CandidateAnalysis;
5
6
  readonly installedExports: InstalledWorkflowExports;