@intentius/chant 0.124.26 → 0.124.28

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 (459) hide show
  1. package/README.md +1 -1
  2. package/dist/__golden__/wave-loop/fan-out-gated.json +8 -0
  3. package/dist/__golden__/wave-loop/fan-out-no-members.json +4 -0
  4. package/dist/__golden__/wave-loop/fan-out-only.json +6 -0
  5. package/dist/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  6. package/dist/__golden__/wave-loop/op-cost-member.json +3 -0
  7. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  8. package/dist/__golden__/wave-loop/op-held-on.json +2 -0
  9. package/dist/__golden__/wave-loop/op-hooks-held.json +2 -0
  10. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  11. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  12. package/dist/__golden__/wave-loop/op-hooks-share.json +3 -0
  13. package/dist/__golden__/wave-loop/op-per-run.json +7 -0
  14. package/dist/__golden__/wave-loop/op-pr-review.json +7 -0
  15. package/dist/__golden__/wave-loop/op-sealed.json +3 -0
  16. package/dist/__golden__/wave-loop/op-spend.json +3 -0
  17. package/dist/__golden__/wave-loop/op-wave-commands.json +7 -0
  18. package/dist/__golden__/wave-loop/op-wide-waiting.json +4 -0
  19. package/dist/change-set-graph.d.ts +56 -0
  20. package/dist/change-set-graph.d.ts.map +1 -0
  21. package/dist/change-set-graph.js +128 -0
  22. package/dist/change-set.d.ts +52 -3
  23. package/dist/change-set.d.ts.map +1 -1
  24. package/dist/change-set.js +35 -4
  25. package/dist/chant-version.d.ts +9 -0
  26. package/dist/chant-version.d.ts.map +1 -0
  27. package/dist/chant-version.js +16 -0
  28. package/dist/cli/commands/build.d.ts +8 -0
  29. package/dist/cli/commands/build.d.ts.map +1 -1
  30. package/dist/cli/commands/build.js +9 -8
  31. package/dist/cli/commands/check-lexicon-docs.d.ts.map +1 -1
  32. package/dist/cli/commands/check-lexicon-docs.js +30 -2
  33. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  34. package/dist/cli/commands/check-lexicon.js +13 -2
  35. package/dist/cli/commands/init-lexicon/templates/docs.d.ts +4 -1
  36. package/dist/cli/commands/init-lexicon/templates/docs.d.ts.map +1 -1
  37. package/dist/cli/commands/init-lexicon/templates/docs.js +6 -6
  38. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  39. package/dist/cli/commands/init-lexicon.js +17 -8
  40. package/dist/cli/handlers/approve.d.ts.map +1 -1
  41. package/dist/cli/handlers/approve.js +19 -4
  42. package/dist/cli/handlers/build.d.ts.map +1 -1
  43. package/dist/cli/handlers/build.js +28 -0
  44. package/dist/cli/handlers/change-set.d.ts +10 -0
  45. package/dist/cli/handlers/change-set.d.ts.map +1 -1
  46. package/dist/cli/handlers/change-set.js +51 -1
  47. package/dist/cli/handlers/fan-out.d.ts +1 -1
  48. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  49. package/dist/cli/handlers/fan-out.js +14 -3
  50. package/dist/cli/handlers/pr.d.ts +8 -2
  51. package/dist/cli/handlers/pr.d.ts.map +1 -1
  52. package/dist/cli/handlers/pr.js +148 -24
  53. package/dist/cli/handlers/promote.d.ts.map +1 -1
  54. package/dist/cli/handlers/promote.js +256 -21
  55. package/dist/cli/handlers/release.d.ts +34 -0
  56. package/dist/cli/handlers/release.d.ts.map +1 -0
  57. package/dist/cli/handlers/release.js +203 -0
  58. package/dist/cli/handlers/run.d.ts +28 -2
  59. package/dist/cli/handlers/run.d.ts.map +1 -1
  60. package/dist/cli/handlers/run.js +170 -13
  61. package/dist/cli/main.d.ts.map +1 -1
  62. package/dist/cli/main.js +88 -13
  63. package/dist/cli/mcp/workspace-tools.js +1 -1
  64. package/dist/cli/parse-args.d.ts.map +1 -1
  65. package/dist/cli/parse-args.js +49 -3
  66. package/dist/cli/registry.d.ts +29 -3
  67. package/dist/cli/registry.d.ts.map +1 -1
  68. package/dist/cli/run-events.d.ts +29 -0
  69. package/dist/cli/run-events.d.ts.map +1 -0
  70. package/dist/cli/run-events.js +47 -0
  71. package/dist/cli/version.d.ts +3 -5
  72. package/dist/cli/version.d.ts.map +1 -1
  73. package/dist/cli/version.js +3 -13
  74. package/dist/codegen/docs-in-site.d.ts +71 -0
  75. package/dist/codegen/docs-in-site.d.ts.map +1 -0
  76. package/dist/codegen/docs-in-site.js +177 -0
  77. package/dist/codegen/docs-types.d.ts +14 -1
  78. package/dist/codegen/docs-types.d.ts.map +1 -1
  79. package/dist/codegen/docs.d.ts +18 -1
  80. package/dist/codegen/docs.d.ts.map +1 -1
  81. package/dist/codegen/docs.js +40 -7
  82. package/dist/codegen/rehype-base-url.mjs +15 -9
  83. package/dist/components/auto-release.d.ts +4 -1
  84. package/dist/components/auto-release.d.ts.map +1 -1
  85. package/dist/components/auto-release.js +2 -0
  86. package/dist/components/cli-support.d.ts +6 -0
  87. package/dist/components/cli-support.d.ts.map +1 -1
  88. package/dist/components/cli-support.js +10 -9
  89. package/dist/components/driver.d.ts +42 -9
  90. package/dist/components/driver.d.ts.map +1 -1
  91. package/dist/components/driver.js +81 -54
  92. package/dist/components/fan-out-run.d.ts +7 -0
  93. package/dist/components/fan-out-run.d.ts.map +1 -1
  94. package/dist/components/fan-out-run.js +35 -26
  95. package/dist/components/pr-run.d.ts +11 -0
  96. package/dist/components/pr-run.d.ts.map +1 -1
  97. package/dist/components/pr-run.js +20 -1
  98. package/dist/components/promote-order.d.ts +38 -0
  99. package/dist/components/promote-order.d.ts.map +1 -0
  100. package/dist/components/promote-order.js +62 -0
  101. package/dist/components/promote.d.ts +15 -2
  102. package/dist/components/promote.d.ts.map +1 -1
  103. package/dist/components/promote.js +17 -0
  104. package/dist/components/release-compile.d.ts +133 -0
  105. package/dist/components/release-compile.d.ts.map +1 -0
  106. package/dist/components/release-compile.js +376 -0
  107. package/dist/components/release-gate.d.ts +125 -0
  108. package/dist/components/release-gate.d.ts.map +1 -0
  109. package/dist/components/release-gate.js +282 -0
  110. package/dist/components/release-promote.d.ts +96 -0
  111. package/dist/components/release-promote.d.ts.map +1 -0
  112. package/dist/components/release-promote.js +204 -0
  113. package/dist/components/run-progress.d.ts +7 -0
  114. package/dist/components/run-progress.d.ts.map +1 -1
  115. package/dist/components/wave-plan.d.ts +3 -1
  116. package/dist/components/wave-plan.d.ts.map +1 -1
  117. package/dist/components/wave-plan.js +1 -1
  118. package/dist/config.d.ts +7 -0
  119. package/dist/config.d.ts.map +1 -1
  120. package/dist/config.js +1 -0
  121. package/dist/index.d.ts +1 -0
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +2 -0
  124. package/dist/lifecycle/change-set-store.d.ts +67 -0
  125. package/dist/lifecycle/change-set-store.d.ts.map +1 -0
  126. package/dist/lifecycle/change-set-store.js +96 -0
  127. package/dist/lifecycle/commit-sha.d.ts +13 -0
  128. package/dist/lifecycle/commit-sha.d.ts.map +1 -0
  129. package/dist/lifecycle/commit-sha.js +21 -0
  130. package/dist/lifecycle/gate-change-set.d.ts +69 -0
  131. package/dist/lifecycle/gate-change-set.d.ts.map +1 -0
  132. package/dist/lifecycle/gate-change-set.js +106 -0
  133. package/dist/lifecycle/gate-ledger.d.ts +49 -1
  134. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  135. package/dist/lifecycle/gate-ledger.js +18 -0
  136. package/dist/lifecycle/release-cut.d.ts +107 -0
  137. package/dist/lifecycle/release-cut.d.ts.map +1 -0
  138. package/dist/lifecycle/release-cut.js +273 -0
  139. package/dist/lifecycle/release-ledger.d.ts +54 -0
  140. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  141. package/dist/lifecycle/release-ledger.js +53 -20
  142. package/dist/lifecycle/release-store.d.ts +190 -0
  143. package/dist/lifecycle/release-store.d.ts.map +1 -0
  144. package/dist/lifecycle/release-store.js +318 -0
  145. package/dist/lifecycle/run-ledger.d.ts +4 -0
  146. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  147. package/dist/lifecycle/run-ledger.js +2 -0
  148. package/dist/op/activities/change-coverage.d.ts.map +1 -1
  149. package/dist/op/activities/change-coverage.js +4 -2
  150. package/dist/op/activities/source-release.d.ts.map +1 -1
  151. package/dist/op/activities/source-release.js +7 -3
  152. package/dist/op/activities/source-rollback.d.ts.map +1 -1
  153. package/dist/op/activities/source-rollback.js +7 -3
  154. package/dist/op/activity-registry.d.ts +6 -3
  155. package/dist/op/activity-registry.d.ts.map +1 -1
  156. package/dist/op/activity-registry.js +7 -5
  157. package/dist/op/discover.d.ts.map +1 -1
  158. package/dist/op/discover.js +14 -7
  159. package/dist/op/gate-name.d.ts +11 -2
  160. package/dist/op/gate-name.d.ts.map +1 -1
  161. package/dist/op/gate-name.js +12 -3
  162. package/dist/op/gate-run-locator.d.ts +22 -0
  163. package/dist/op/gate-run-locator.d.ts.map +1 -1
  164. package/dist/op/gate-run-locator.js +31 -0
  165. package/dist/op/gate.d.ts +27 -3
  166. package/dist/op/gate.d.ts.map +1 -1
  167. package/dist/op/gate.js +57 -3
  168. package/dist/op/local-executor.d.ts +36 -1
  169. package/dist/op/local-executor.d.ts.map +1 -1
  170. package/dist/op/local-executor.js +158 -52
  171. package/dist/op/op-waves-run.d.ts.map +1 -1
  172. package/dist/op/op-waves-run.js +4 -0
  173. package/dist/op/run-live.d.ts +2 -0
  174. package/dist/op/run-live.d.ts.map +1 -1
  175. package/dist/op/run-live.js +1 -1
  176. package/dist/op/runtime.d.ts +46 -0
  177. package/dist/op/runtime.d.ts.map +1 -1
  178. package/dist/op/runtimes/local.d.ts.map +1 -1
  179. package/dist/op/runtimes/local.js +12 -2
  180. package/dist/point-decision.d.ts +2 -0
  181. package/dist/point-decision.d.ts.map +1 -1
  182. package/dist/point-decision.js +9 -2
  183. package/dist/run-event-store.d.ts +77 -0
  184. package/dist/run-event-store.d.ts.map +1 -0
  185. package/dist/run-event-store.js +204 -0
  186. package/dist/run-event-stream.d.ts +132 -0
  187. package/dist/run-event-stream.d.ts.map +1 -0
  188. package/dist/run-event-stream.js +238 -0
  189. package/dist/run-event.d.ts +267 -0
  190. package/dist/run-event.d.ts.map +1 -0
  191. package/dist/run-event.js +207 -0
  192. package/dist/wave-runtime.mjs +225 -242
  193. package/dist/workspace/__fixtures__/run-event-check.d.ts +19 -0
  194. package/dist/workspace/__fixtures__/run-event-check.d.ts.map +1 -0
  195. package/dist/workspace/__fixtures__/run-event-check.js +59 -0
  196. package/dist/workspace/change-set-show.d.ts +56 -0
  197. package/dist/workspace/change-set-show.d.ts.map +1 -0
  198. package/dist/workspace/change-set-show.js +54 -0
  199. package/dist/workspace/change-set-show.schema.json +102 -0
  200. package/dist/workspace/change-set.schema.json +28 -1
  201. package/dist/workspace/changes-cli.d.ts.map +1 -1
  202. package/dist/workspace/changes-cli.js +10 -1
  203. package/dist/workspace/changes.d.ts +37 -0
  204. package/dist/workspace/changes.d.ts.map +1 -1
  205. package/dist/workspace/changes.js +49 -2
  206. package/dist/workspace/changes.schema.json +135 -0
  207. package/dist/workspace/ci-green-cli.d.ts +19 -4
  208. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  209. package/dist/workspace/ci-green-cli.js +75 -12
  210. package/dist/workspace/ci-green-forge.d.ts +20 -3
  211. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  212. package/dist/workspace/ci-green-forge.js +6 -4
  213. package/dist/workspace/ci-green-workflow.d.ts +11 -0
  214. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  215. package/dist/workspace/ci-green-workflow.js +6 -0
  216. package/dist/workspace/ci-green.d.ts +273 -13
  217. package/dist/workspace/ci-green.d.ts.map +1 -1
  218. package/dist/workspace/ci-green.js +449 -38
  219. package/dist/workspace/ci-last-green.schema.json +32 -2
  220. package/dist/workspace/ci-list.schema.json +525 -0
  221. package/dist/workspace/commit-links.d.ts +85 -0
  222. package/dist/workspace/commit-links.d.ts.map +1 -0
  223. package/dist/workspace/commit-links.js +163 -0
  224. package/dist/workspace/declaration.d.ts +19 -0
  225. package/dist/workspace/declaration.d.ts.map +1 -1
  226. package/dist/workspace/declaration.js +1 -1
  227. package/dist/workspace/declaration.schema.json +12 -0
  228. package/dist/workspace/identity-gate-rule.d.ts +37 -0
  229. package/dist/workspace/identity-gate-rule.d.ts.map +1 -1
  230. package/dist/workspace/identity-gate-rule.js +72 -7
  231. package/dist/workspace/identity.d.ts +12 -0
  232. package/dist/workspace/identity.d.ts.map +1 -1
  233. package/dist/workspace/identity.js +13 -1
  234. package/dist/workspace/intent.d.ts +6 -1
  235. package/dist/workspace/intent.d.ts.map +1 -1
  236. package/dist/workspace/intent.js +51 -1
  237. package/dist/workspace/ls.d.ts +4 -0
  238. package/dist/workspace/ls.d.ts.map +1 -1
  239. package/dist/workspace/ls.js +2 -0
  240. package/dist/workspace/ls.schema.json +3 -1
  241. package/dist/workspace/member-pipeline.d.ts +6 -0
  242. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  243. package/dist/workspace/member-pipeline.js +6 -0
  244. package/dist/workspace/promotion-order.d.ts +41 -0
  245. package/dist/workspace/promotion-order.d.ts.map +1 -0
  246. package/dist/workspace/promotion-order.js +95 -0
  247. package/dist/workspace/reason-codes.d.ts +2 -0
  248. package/dist/workspace/reason-codes.d.ts.map +1 -1
  249. package/dist/workspace/reason-codes.js +4 -1
  250. package/dist/workspace/releases.d.ts +72 -0
  251. package/dist/workspace/releases.d.ts.map +1 -0
  252. package/dist/workspace/releases.js +94 -0
  253. package/dist/workspace/releases.schema.json +391 -0
  254. package/dist/workspace/run-event.schema.json +288 -0
  255. package/dist/workspace/status-gates.d.ts +26 -1
  256. package/dist/workspace/status-gates.d.ts.map +1 -1
  257. package/dist/workspace/status-gates.js +31 -2
  258. package/dist/workspace/status-stewards.d.ts +4 -0
  259. package/dist/workspace/status-stewards.d.ts.map +1 -1
  260. package/dist/workspace/status-stewards.js +2 -0
  261. package/dist/workspace/status.d.ts +39 -0
  262. package/dist/workspace/status.d.ts.map +1 -1
  263. package/dist/workspace/status.js +48 -1
  264. package/dist/workspace/status.schema.json +70 -1
  265. package/dist/workspace/trust/ci-tag-statement.d.ts +102 -0
  266. package/dist/workspace/trust/ci-tag-statement.d.ts.map +1 -0
  267. package/dist/workspace/trust/ci-tag-statement.js +123 -0
  268. package/dist/workspace/trust/op-run-statement.d.ts +91 -0
  269. package/dist/workspace/trust/op-run-statement.d.ts.map +1 -0
  270. package/dist/workspace/trust/op-run-statement.js +143 -0
  271. package/dist/workspace/trust/rotation.d.ts +18 -2
  272. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  273. package/dist/workspace/trust/rotation.js +65 -16
  274. package/dist/workspace/trust/seal.d.ts +11 -0
  275. package/dist/workspace/trust/seal.d.ts.map +1 -1
  276. package/dist/workspace/trust/seal.js +9 -0
  277. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  278. package/dist/workspace/trust/ssh-commit.js +10 -10
  279. package/package.json +1 -1
  280. package/src/__golden__/wave-loop/fan-out-gated.json +8 -0
  281. package/src/__golden__/wave-loop/fan-out-no-members.json +4 -0
  282. package/src/__golden__/wave-loop/fan-out-only.json +6 -0
  283. package/src/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  284. package/src/__golden__/wave-loop/op-cost-member.json +3 -0
  285. package/src/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  286. package/src/__golden__/wave-loop/op-held-on.json +2 -0
  287. package/src/__golden__/wave-loop/op-hooks-held.json +2 -0
  288. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  289. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  290. package/src/__golden__/wave-loop/op-hooks-share.json +3 -0
  291. package/src/__golden__/wave-loop/op-per-run.json +7 -0
  292. package/src/__golden__/wave-loop/op-pr-review.json +7 -0
  293. package/src/__golden__/wave-loop/op-sealed.json +3 -0
  294. package/src/__golden__/wave-loop/op-spend.json +3 -0
  295. package/src/__golden__/wave-loop/op-wave-commands.json +7 -0
  296. package/src/__golden__/wave-loop/op-wide-waiting.json +4 -0
  297. package/src/change-set-graph.test.ts +72 -0
  298. package/src/change-set-graph.ts +133 -0
  299. package/src/change-set.ts +76 -6
  300. package/src/chant-version.ts +16 -0
  301. package/src/cli/commands/build.ts +19 -8
  302. package/src/cli/commands/check-lexicon-docs.test.ts +51 -0
  303. package/src/cli/commands/check-lexicon-docs.ts +39 -2
  304. package/src/cli/commands/check-lexicon.ts +14 -2
  305. package/src/cli/commands/init-lexicon/templates/docs.ts +7 -6
  306. package/src/cli/commands/init-lexicon.test.ts +25 -0
  307. package/src/cli/commands/init-lexicon.ts +18 -8
  308. package/src/cli/compiled-cli.e2e.test.ts +31 -6
  309. package/src/cli/handlers/approve-release.test.ts +80 -0
  310. package/src/cli/handlers/approve.ts +18 -2
  311. package/src/cli/handlers/build.test.ts +52 -0
  312. package/src/cli/handlers/build.ts +29 -0
  313. package/src/cli/handlers/change-set.ts +49 -1
  314. package/src/cli/handlers/fan-out.test.ts +48 -0
  315. package/src/cli/handlers/fan-out.ts +15 -3
  316. package/src/cli/handlers/operator.test.ts +37 -0
  317. package/src/cli/handlers/pr.test.ts +194 -0
  318. package/src/cli/handlers/pr.ts +168 -34
  319. package/src/cli/handlers/promote.test.ts +389 -5
  320. package/src/cli/handlers/promote.ts +279 -20
  321. package/src/cli/handlers/release-implicit.e2e.test.ts +153 -0
  322. package/src/cli/handlers/release.e2e.test.ts +85 -0
  323. package/src/cli/handlers/release.ts +206 -0
  324. package/src/cli/handlers/run-auto-release.test.ts +71 -0
  325. package/src/cli/handlers/run-events-cmd.test.ts +92 -0
  326. package/src/cli/handlers/run.test.ts +30 -0
  327. package/src/cli/handlers/run.ts +176 -15
  328. package/src/cli/main.test.ts +7 -0
  329. package/src/cli/main.ts +88 -13
  330. package/src/cli/mcp/never-over-mcp.test.ts +2 -0
  331. package/src/cli/mcp/workspace-tools.ts +1 -1
  332. package/src/cli/parse-args.ts +37 -3
  333. package/src/cli/registry.ts +29 -3
  334. package/src/cli/run-events.ts +54 -0
  335. package/src/cli/version.ts +3 -13
  336. package/src/codegen/docs-in-site.test.ts +166 -0
  337. package/src/codegen/docs-in-site.ts +182 -0
  338. package/src/codegen/docs-site/AgentPrompt.astro +26 -1
  339. package/src/codegen/docs-types.ts +14 -1
  340. package/src/codegen/docs.ts +60 -7
  341. package/src/codegen/rehype-base-url.d.mts +3 -1
  342. package/src/codegen/rehype-base-url.mjs +15 -9
  343. package/src/codegen/rehype-base-url.test.ts +34 -0
  344. package/src/components/auto-release.test.ts +21 -0
  345. package/src/components/auto-release.ts +6 -1
  346. package/src/components/cli-support.test.ts +82 -0
  347. package/src/components/cli-support.ts +16 -9
  348. package/src/components/driver.ts +129 -56
  349. package/src/components/fan-out-run.ts +56 -35
  350. package/src/components/pr-run.ts +30 -1
  351. package/src/components/promote-order.test.ts +90 -0
  352. package/src/components/promote-order.ts +75 -0
  353. package/src/components/promote.test.ts +10 -1
  354. package/src/components/promote.ts +26 -1
  355. package/src/components/release-compile.test.ts +147 -0
  356. package/src/components/release-compile.ts +445 -0
  357. package/src/components/release-gate.test.ts +215 -0
  358. package/src/components/release-gate.ts +341 -0
  359. package/src/components/release-promote.test.ts +159 -0
  360. package/src/components/release-promote.ts +232 -0
  361. package/src/components/run-progress.ts +7 -0
  362. package/src/components/wave-plan.ts +1 -1
  363. package/src/config.ts +7 -1
  364. package/src/index.ts +2 -0
  365. package/src/lifecycle/change-set-store.test.ts +217 -0
  366. package/src/lifecycle/change-set-store.ts +112 -0
  367. package/src/lifecycle/commit-sha.ts +23 -0
  368. package/src/lifecycle/gate-change-set.e2e.test.ts +122 -0
  369. package/src/lifecycle/gate-change-set.ts +133 -0
  370. package/src/lifecycle/gate-ledger.test.ts +33 -0
  371. package/src/lifecycle/gate-ledger.ts +66 -1
  372. package/src/lifecycle/release-cut-signed.test.ts +180 -0
  373. package/src/lifecycle/release-cut.test.ts +411 -0
  374. package/src/lifecycle/release-cut.ts +367 -0
  375. package/src/lifecycle/release-ledger.test.ts +14 -0
  376. package/src/lifecycle/release-ledger.ts +85 -17
  377. package/src/lifecycle/release-store.ts +423 -0
  378. package/src/lifecycle/run-ledger.test.ts +10 -0
  379. package/src/lifecycle/run-ledger.ts +6 -0
  380. package/src/op/activities/change-coverage.ts +4 -1
  381. package/src/op/activities/source-release.ts +8 -3
  382. package/src/op/activities/source-rollback.ts +8 -4
  383. package/src/op/activity-registry.ts +7 -5
  384. package/src/op/commit-run-gate-deploy-join.test.ts +117 -0
  385. package/src/op/discover-root.test.ts +39 -0
  386. package/src/op/discover.ts +15 -8
  387. package/src/op/gate-name.ts +13 -3
  388. package/src/op/gate-release.test.ts +126 -0
  389. package/src/op/gate-run-locator.test.ts +110 -0
  390. package/src/op/gate-run-locator.ts +35 -0
  391. package/src/op/gate.ts +88 -6
  392. package/src/op/local-executor.ts +207 -52
  393. package/src/op/op-waves-run.ts +4 -0
  394. package/src/op/run-events.test.ts +166 -0
  395. package/src/op/run-live.ts +1 -1
  396. package/src/op/runtime.ts +39 -0
  397. package/src/op/runtimes/local.test.ts +16 -0
  398. package/src/op/runtimes/local.ts +13 -2
  399. package/src/point-decision.ts +12 -2
  400. package/src/run-event-store.test.ts +144 -0
  401. package/src/run-event-store.ts +213 -0
  402. package/src/run-event-stream.test.ts +175 -0
  403. package/src/run-event-stream.ts +306 -0
  404. package/src/run-event.test.ts +277 -0
  405. package/src/run-event.ts +451 -0
  406. package/src/wave-loop-golden.test.ts +9 -0
  407. package/src/workspace/__fixtures__/run-event-check.ts +58 -0
  408. package/src/workspace/ancestry-index.test.ts +93 -0
  409. package/src/workspace/change-set-show.schema.json +102 -0
  410. package/src/workspace/change-set-show.ts +72 -0
  411. package/src/workspace/change-set.schema.json +28 -1
  412. package/src/workspace/changes-cli.ts +10 -1
  413. package/src/workspace/changes.schema.json +135 -0
  414. package/src/workspace/changes.test.ts +1 -1
  415. package/src/workspace/changes.ts +84 -2
  416. package/src/workspace/ci-green-cli.ts +75 -13
  417. package/src/workspace/ci-green-forge.ts +24 -4
  418. package/src/workspace/ci-green-runs.test.ts +242 -0
  419. package/src/workspace/ci-green-signed.test.ts +302 -0
  420. package/src/workspace/ci-green-workflow.test.ts +16 -0
  421. package/src/workspace/ci-green-workflow.ts +12 -0
  422. package/src/workspace/ci-green.test.ts +131 -2
  423. package/src/workspace/ci-green.ts +624 -42
  424. package/src/workspace/ci-last-green.schema.json +32 -2
  425. package/src/workspace/ci-list.schema.json +525 -0
  426. package/src/workspace/commit-links.test.ts +279 -0
  427. package/src/workspace/commit-links.ts +183 -0
  428. package/src/workspace/declaration.schema.json +12 -0
  429. package/src/workspace/declaration.ts +22 -2
  430. package/src/workspace/identity-gate-rule.ts +91 -7
  431. package/src/workspace/identity.ts +14 -1
  432. package/src/workspace/intent.ts +48 -1
  433. package/src/workspace/ls.schema.json +3 -1
  434. package/src/workspace/ls.ts +6 -0
  435. package/src/workspace/member-pipeline.test.ts +17 -0
  436. package/src/workspace/member-pipeline.ts +9 -0
  437. package/src/workspace/promotion-order.ts +97 -0
  438. package/src/workspace/read-contract.e2e.test.ts +4 -1
  439. package/src/workspace/reason-codes.test.ts +2 -1
  440. package/src/workspace/reason-codes.ts +4 -1
  441. package/src/workspace/releases.schema.json +391 -0
  442. package/src/workspace/releases.test.ts +108 -0
  443. package/src/workspace/releases.ts +122 -0
  444. package/src/workspace/run-event.schema.json +288 -0
  445. package/src/workspace/status-contract.test.ts +52 -1
  446. package/src/workspace/status-gates.ts +56 -1
  447. package/src/workspace/status-stewards.ts +6 -0
  448. package/src/workspace/status.schema.json +70 -1
  449. package/src/workspace/status.ts +80 -1
  450. package/src/workspace/trust/ci-tag-statement.ts +151 -0
  451. package/src/workspace/trust/op-run-statement.ts +148 -0
  452. package/src/workspace/trust/rotation.ts +61 -14
  453. package/src/workspace/trust/seal.ts +10 -0
  454. package/src/workspace/trust/ssh-commit.ts +10 -9
  455. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +0 -14
  456. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +0 -16
  457. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +0 -8
  458. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +0 -15
  459. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +0 -10
@@ -0,0 +1,282 @@
1
+ /**
2
+ * The release gate (#4045, ws-104 questions 2 and 6): the gate `chant
3
+ * components promote --release` passes for an environment.
4
+ *
5
+ * ## What it binds
6
+ *
7
+ * A promote under a release plans the release's change set for the
8
+ * environment it deploys to ({@link planReleaseChangeSet}), stores it on
9
+ * `chant/lifecycle` under its digest (`../lifecycle/gate-change-set.ts`), and
10
+ * decides every gate its components reach against three values:
11
+ *
12
+ * - the change-set document's `digest`, in `planDigest`;
13
+ * - the release, in `releaseDigest`;
14
+ * - the environment, in `environment`.
15
+ *
16
+ * An approval counts only when all three match (`evaluateGate` in
17
+ * `../op/gate.ts`). The document itself names the release and the environment
18
+ * it was planned for, and both are part of its digest, so a stored document
19
+ * names the one release its gate bound and two releases never share a digest.
20
+ *
21
+ * Every gate a promote under a release reaches is recorded in one ledger,
22
+ * {@link RELEASE_GATE_OP}, rather than in each component's. The gate name a
23
+ * composition authors is kept, so components that share a gate name share one
24
+ * gate per environment, and one approval of the release's change set passes
25
+ * each of them. A promote of one component (`--component`) plans that
26
+ * component's subset, which has its own digest and needs its own approval.
27
+ *
28
+ * ## Empty change sets
29
+ *
30
+ * When the change set changes nothing ({@link isEmptyChangeSet}), the
31
+ * promote writes an `empty: true` resolution for each gate, with the actor
32
+ * running it in `resolvedBy` ({@link emptyResolution}). A gate counts it only
33
+ * after it reads the stored document back and finds it empty
34
+ * ({@link emptyVerifier}). Quorum and signing rules don't apply to it.
35
+ *
36
+ * ## The members
37
+ *
38
+ * A component with a step whose capability can plan (`terraform-apply`) is
39
+ * planned by that capability, as a pull request's plan is. A plan that
40
+ * returns no change-set part is a hole, since nothing says what it changes.
41
+ *
42
+ * Any other component is a `chant` member compared with what the
43
+ * environment runs now: its latest deploy record and the release that record
44
+ * names. The artifact digest, each template the release's target records for
45
+ * the component, and the target's parameters are compared, and each one that
46
+ * differs is an attribute of one `update` entry (a `create` when the
47
+ * environment has no deploy of the component). When they are all equal the
48
+ * member has no entries. When the environment's deploy names no release, or
49
+ * the release it names can't be read, the member has a hole: nothing says
50
+ * what the environment runs, so the change can't be shown empty.
51
+ */
52
+ import { deployContext, resolveComponentGraph, resolveStepInput } from "./driver.js";
53
+ import { componentPlanDigest } from "./gate-plan.js";
54
+ import { gateName, RELEASE_GATE_OP } from "../op/gate-name.js";
55
+ import { capabilitySteps, readComponentOutputs } from "./wave-plan.js";
56
+ import { composeChangeSet, isEmptyChangeSet, } from "../change-set.js";
57
+ /** The gate ledger every release gate is recorded in: `_gates/release.jsonl`, under the member's prefix. */
58
+ export { RELEASE_GATE_OP };
59
+ /** The address and type a `chant` member's one entry has. */
60
+ export const RELEASE_COMPONENT_ENTRY_TYPE = "chant:component";
61
+ function isGate(step) {
62
+ return step.kind === "gate";
63
+ }
64
+ function isPhase(step) {
65
+ return typeof step.phase === "string" && Array.isArray(step.steps);
66
+ }
67
+ /** The name of every gate the compositions declare, nested phases included, sorted and distinct. */
68
+ export function gateNamesOf(components) {
69
+ const names = new Set();
70
+ const walk = (steps) => {
71
+ for (const step of steps) {
72
+ if (isPhase(step))
73
+ walk(step.steps);
74
+ else if (isGate(step))
75
+ names.add(gateName(step));
76
+ }
77
+ };
78
+ for (const c of components)
79
+ for (const phase of c.deploy)
80
+ walk(phase.steps);
81
+ return [...names].sort();
82
+ }
83
+ const byString = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
84
+ /** One attribute per key whose value differs between `before` and `after`, sorted by path. */
85
+ function differing(before, after, prefix) {
86
+ const out = [];
87
+ for (const key of [...new Set([...before.keys(), ...after.keys()])].sort(byString)) {
88
+ const was = before.get(key);
89
+ const now = after.get(key);
90
+ if (was === now)
91
+ continue;
92
+ out.push({ path: `${prefix}${key}`, ...(was !== undefined ? { before: was } : {}), ...(now !== undefined ? { after: now } : {}) });
93
+ }
94
+ return out;
95
+ }
96
+ /** What one target says a component deploys: its templates by path, and the target's parameters by name. */
97
+ function deployedInputs(release, env, component) {
98
+ const target = release.targets.find((t) => t.env === env);
99
+ if (!target)
100
+ return null;
101
+ return {
102
+ templates: new Map(target.templates.filter((t) => t.component === component).map((t) => [t.path, t.digest])),
103
+ params: new Map(target.params.map((p) => [p.name, JSON.stringify(p.value)])),
104
+ };
105
+ }
106
+ /**
107
+ * A component no capability plans, as a `chant` member: what the release
108
+ * deploys compared with what the environment runs now. See the module doc.
109
+ */
110
+ export function chantComponentPart(input) {
111
+ const { component, release, env, digest, current } = input;
112
+ const name = component.name;
113
+ const member = {
114
+ member: name,
115
+ lexicon: "chant",
116
+ planner: "chant",
117
+ status: "planned",
118
+ planDigest: componentPlanDigest({ environment: env, component, release: digest }),
119
+ holes: [],
120
+ };
121
+ const want = deployedInputs(release, env, name);
122
+ if (!want) {
123
+ member.holes.push({ address: name, type: RELEASE_COMPONENT_ENTRY_TYPE, reason: `release ${release.releaseDigest} has no target for "${env}"` });
124
+ return { member, entries: [] };
125
+ }
126
+ const entry = (action, attributes) => ({
127
+ member,
128
+ entries: [
129
+ {
130
+ member: name,
131
+ lexicon: "chant",
132
+ planner: "chant",
133
+ address: name,
134
+ type: RELEASE_COMPONENT_ENTRY_TYPE,
135
+ name,
136
+ action,
137
+ ...(action === "update" ? { disruption: "unknown" } : {}),
138
+ scope: env,
139
+ attributes,
140
+ },
141
+ ],
142
+ });
143
+ if (!current) {
144
+ return entry("create", [
145
+ { path: "artifact", after: digest },
146
+ ...differing(new Map(), want.templates, "template:"),
147
+ ...differing(new Map(), want.params, "param:"),
148
+ ]);
149
+ }
150
+ const named = current.record.releaseDigest;
151
+ if (named === undefined) {
152
+ member.holes.push({
153
+ address: name,
154
+ type: RELEASE_COMPONENT_ENTRY_TYPE,
155
+ reason: `the "${env}" deploy of ${name} (run ${current.record.runId}) names no release, so what it runs can't be compared with this release`,
156
+ });
157
+ return { member, entries: [] };
158
+ }
159
+ const have = current.release ? deployedInputs(current.release, env, name) : null;
160
+ if (!have) {
161
+ member.holes.push({
162
+ address: name,
163
+ type: RELEASE_COMPONENT_ENTRY_TYPE,
164
+ reason: current.release
165
+ ? `release ${named}, which the "${env}" deploy of ${name} names, has no target for "${env}"`
166
+ : `release ${named}, which the "${env}" deploy of ${name} names, can't be read from chant/lifecycle`,
167
+ });
168
+ return { member, entries: [] };
169
+ }
170
+ const attributes = [
171
+ ...differing(new Map([["", current.record.digest]]), new Map([["", digest]]), "artifact"),
172
+ ...differing(have.templates, want.templates, "template:"),
173
+ ...differing(have.params, want.params, "param:"),
174
+ ];
175
+ return attributes.length === 0 ? { member, entries: [] } : entry("update", attributes);
176
+ }
177
+ /**
178
+ * Plan the release's change set for `env`: one part per promoted component
179
+ * (or per member its planning capability names), composed into a document
180
+ * that names the release and the environment. Never throws for a component
181
+ * that fails to plan: it becomes a failed member.
182
+ */
183
+ export async function planReleaseChangeSet(input) {
184
+ const { release, env, registry } = input;
185
+ const components = [...input.components];
186
+ const byName = new Map(components.map((c) => [c.name, c]));
187
+ const outputs = { ...(input.seededOutputs ?? {}) };
188
+ const read = new Set(Object.keys(outputs));
189
+ const parts = [];
190
+ const { order } = resolveComponentGraph(components.map((c) => ({ ...c, dependsOn: (c.dependsOn ?? []).filter((d) => byName.has(d)) })));
191
+ for (const name of order) {
192
+ const component = byName.get(name);
193
+ const digest = input.digests.get(name) ?? "";
194
+ const plannable = capabilitySteps(component.deploy).filter((s) => registry.has(s.kind) && registry.resolve(s.kind).plan !== undefined);
195
+ if (plannable.length === 0) {
196
+ parts.push(chantComponentPart({ component, release, env, digest, current: input.current.get(name) }));
197
+ continue;
198
+ }
199
+ const ctx = deployContext({ env }, name);
200
+ try {
201
+ for (const dep of component.dependsOn ?? []) {
202
+ if (read.has(dep) || !byName.has(dep))
203
+ continue;
204
+ read.add(dep);
205
+ const found = await readComponentOutputs(byName.get(dep), registry, deployContext({ env }, dep), outputs);
206
+ if (found)
207
+ outputs[dep] = found;
208
+ }
209
+ for (const step of plannable) {
210
+ const { kind, ...rest } = step;
211
+ const planned = await registry.resolve(kind).plan(ctx, resolveStepInput(rest, {}, outputs));
212
+ parts.push(planned.changeSet ?? {
213
+ member: {
214
+ member: planned.member,
215
+ lexicon: "chant",
216
+ planner: "chant",
217
+ status: "planned",
218
+ planDigest: planned.planDigest,
219
+ holes: [{ address: planned.member, reason: `its ${kind} plan describes no changes, so what it changes is unknown` }],
220
+ },
221
+ entries: [],
222
+ });
223
+ }
224
+ }
225
+ catch (err) {
226
+ parts.push({
227
+ member: {
228
+ member: name,
229
+ lexicon: "chant",
230
+ planner: "chant",
231
+ status: "failed",
232
+ error: err instanceof Error ? err.message : String(err),
233
+ planDigest: null,
234
+ holes: [],
235
+ },
236
+ entries: [],
237
+ });
238
+ }
239
+ }
240
+ return composeChangeSet(parts, {
241
+ ...(input.chant !== undefined ? { chant: input.chant } : {}),
242
+ planned: { releaseDigest: release.releaseDigest, environment: env },
243
+ });
244
+ }
245
+ /** The members a release gate refuses: provisional ones, which no approval of the document covers (`change-set.mdx`). */
246
+ export function provisionalMembers(doc) {
247
+ return doc.members.filter((m) => m.provisional === true).map((m) => m.member);
248
+ }
249
+ /**
250
+ * The `verifyEmpty` a release gate decides with: the document stored under
251
+ * the digest, read back and checked against its digest by `read`, is the
252
+ * one planned for this release and environment, and it is empty.
253
+ */
254
+ export function emptyVerifier(read, planned) {
255
+ return async (digest) => {
256
+ const stored = await read(digest);
257
+ return (stored.status === "found" &&
258
+ stored.document.releaseDigest === planned.releaseDigest &&
259
+ stored.document.environment === planned.environment &&
260
+ isEmptyChangeSet(stored.document));
261
+ };
262
+ }
263
+ /** The `empty: true` resolution a promote writes for one release gate over an empty change set. */
264
+ export function emptyResolution(input) {
265
+ const { doc } = input;
266
+ if (doc.releaseDigest === undefined || doc.environment === undefined) {
267
+ throw new Error(`change set ${doc.digest} names no release and environment, so no release gate can pass on it`);
268
+ }
269
+ return {
270
+ op: RELEASE_GATE_OP,
271
+ gate: input.gate,
272
+ resolvedBy: input.actor,
273
+ timestamp: input.timestamp,
274
+ note: `the change set of release ${doc.releaseDigest} for "${doc.environment}" is empty`,
275
+ planDigest: doc.digest,
276
+ environment: doc.environment,
277
+ releaseDigest: doc.releaseDigest,
278
+ empty: true,
279
+ ...(input.gitSha ? { gitSha: input.gitSha } : {}),
280
+ ...(input.runId ? { runId: input.runId } : {}),
281
+ };
282
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * A promote under a release (#4026, ws-104 question 5): the deploy reads the
3
+ * templates the release recorded for the target environment, not the ones in
4
+ * the promoting checkout.
5
+ *
6
+ * Each template a promoted component's deploy names ({@link templateRefs}) has
7
+ * to be one the release's target records for that component. Its bytes are
8
+ * read from `_releases/templates/` on `chant/lifecycle` and checked against
9
+ * the target's digest, the way a promote checks the publish digest, and a
10
+ * mismatch refuses the promote before anything runs. The bytes are written
11
+ * under `.chant/release-templates/<digest>/` in the member's directory and the
12
+ * step reads them from there. The path is relative and fixed by the digest,
13
+ * so a gate approval bound to the promote's plan still matches on a re-run.
14
+ */
15
+ import type { DriverComponent } from "./driver.js";
16
+ import type { Release, ReleaseTarget } from "../lifecycle/release-store.js";
17
+ import type { ReleaseRecord } from "../lifecycle/release-ledger.js";
18
+ import type { BuildArchiveManifest } from "./verbs/build-archive.js";
19
+ /** Where a promote under a release writes the recorded templates, relative to the member's directory. */
20
+ export declare const RELEASE_TEMPLATES_DIR = ".chant/release-templates";
21
+ /** A template ready to write: where, and its bytes. */
22
+ export interface PinnedTemplate {
23
+ /** Relative to the member's directory. */
24
+ path: string;
25
+ content: string;
26
+ }
27
+ /** The release's target for `env`, or an error naming the environments it has. */
28
+ export declare function targetFor(release: Release, env: string): {
29
+ target: ReleaseTarget;
30
+ } | {
31
+ error: string;
32
+ };
33
+ /** Whether a release is of a project with no components (#4046): no artifact, and every template it records has `component: null`. */
34
+ export declare function isImplicitRelease(release: Release): boolean;
35
+ /**
36
+ * Point every template `components` read at the target's recorded bytes.
37
+ * Returns the rewritten compositions and the files to write, or the reasons
38
+ * the promote is refused: a template the target does not record, one whose
39
+ * bytes are missing, or one whose bytes do not hash to the target's digest.
40
+ */
41
+ export declare function pinReleaseTemplates(components: readonly DriverComponent[], release: Release, target: ReleaseTarget, readTemplate: (digest: string) => Promise<string | null>): Promise<{
42
+ components: DriverComponent[];
43
+ files: PinnedTemplate[];
44
+ } | {
45
+ errors: string[];
46
+ }>;
47
+ /**
48
+ * The files a release's target records, read back by digest and checked, for
49
+ * `chant release export` (#4046). A project with no components has no deploy
50
+ * step for a promote to point at the recorded bytes, so its deploy (an Op such
51
+ * as `chant run deploy`, or a CI job) reads the files this writes instead of
52
+ * building them again. Each path is the one the build wrote, relative to the
53
+ * member's directory; a template whose bytes are missing or don't hash to the
54
+ * target's digest is refused, as {@link pinReleaseTemplates} refuses one.
55
+ */
56
+ export declare function targetFiles(release: Release, target: ReleaseTarget, readTemplate: (digest: string) => Promise<string | null>): Promise<{
57
+ files: PinnedTemplate[];
58
+ } | {
59
+ errors: string[];
60
+ }>;
61
+ /** Write the pinned templates under `dir`, the member's directory. */
62
+ export declare function writePinnedTemplates(dir: string, files: readonly PinnedTemplate[]): void;
63
+ /**
64
+ * Remove the templates {@link writePinnedTemplates} wrote once the promote is
65
+ * done, and {@link RELEASE_TEMPLATES_DIR} with them when nothing else is in
66
+ * it, so a promote leaves the checkout as it found it. A re-run writes them
67
+ * again from the release.
68
+ */
69
+ export declare function removePinnedTemplates(dir: string, files: readonly PinnedTemplate[]): void;
70
+ /**
71
+ * Whether the artifact a promote deploys under a release is one the release
72
+ * built (#4045, the rule #4026 left open). The release records build digests
73
+ * (`artifactDigests`, the digest the archive step returned), and a deploy
74
+ * record carries the publish digest, which is another value for an image, so
75
+ * the two are compared through the build manifest the source deploy record
76
+ * names (`manifestDigest`), whose entries carry build digests at the same
77
+ * archive paths:
78
+ *
79
+ * - a source record that names this release in `releaseDigest` matches;
80
+ * - else, each of the release's artifacts for the component must be in that
81
+ * manifest at its path with the release's digest, and one that differs is
82
+ * a mismatch;
83
+ * - a record with no `manifestDigest`, a manifest that isn't stored, or an
84
+ * artifact path the manifest doesn't hold can't be compared.
85
+ *
86
+ * A mismatch is a warning, not a refusal. The environment promoted from was
87
+ * deployed by its own `run --components`, which builds again, and an image
88
+ * build is not reproducible, so its digest differs from the cut's for the
89
+ * same commit. Refusing would refuse every image promote until a deploy can
90
+ * run the release's own artifacts (#4043).
91
+ */
92
+ export declare function releaseArtifactMismatches(release: Release, sources: ReadonlyArray<{
93
+ component: string;
94
+ source: ReleaseRecord;
95
+ }>, readManifest: (manifestDigest: string) => Promise<BuildArchiveManifest | null>): Promise<string[]>;
96
+ //# sourceMappingURL=release-promote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-promote.d.ts","sourceRoot":"","sources":["../../src/components/release-promote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAuC,MAAM,UAAU,CAAC;AAErF,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,yGAAyG;AACzG,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAMtG;AAED,sIAAsI;AACtI,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAG3D;AAUD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GACvD,OAAO,CAAC;IAAE,UAAU,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAiD5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GACvD,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA2B7D;AAED,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI,CAMxF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI,CAQzF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,aAAa,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,EACpE,YAAY,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAC7E,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBnB"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * A promote under a release (#4026, ws-104 question 5): the deploy reads the
3
+ * templates the release recorded for the target environment, not the ones in
4
+ * the promoting checkout.
5
+ *
6
+ * Each template a promoted component's deploy names ({@link templateRefs}) has
7
+ * to be one the release's target records for that component. Its bytes are
8
+ * read from `_releases/templates/` on `chant/lifecycle` and checked against
9
+ * the target's digest, the way a promote checks the publish digest, and a
10
+ * mismatch refuses the promote before anything runs. The bytes are written
11
+ * under `.chant/release-templates/<digest>/` in the member's directory and the
12
+ * step reads them from there. The path is relative and fixed by the digest,
13
+ * so a gate approval bound to the promote's plan still matches on a re-run.
14
+ */
15
+ import { mkdirSync, readdirSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
16
+ import { basename, dirname, join } from "node:path";
17
+ import { contentDigest } from "../content-digest.js";
18
+ import { TEMPLATE_FIELDS, templateRefs } from "./release-compile.js";
19
+ /** Where a promote under a release writes the recorded templates, relative to the member's directory. */
20
+ export const RELEASE_TEMPLATES_DIR = ".chant/release-templates";
21
+ /** The release's target for `env`, or an error naming the environments it has. */
22
+ export function targetFor(release, env) {
23
+ const target = release.targets.find((t) => t.env === env);
24
+ if (target)
25
+ return { target };
26
+ return {
27
+ error: `release ${release.releaseDigest} has no target for "${env}"; it was compiled for ${release.targets.map((t) => t.env).join(", ") || "no environment"}`,
28
+ };
29
+ }
30
+ /** Whether a release is of a project with no components (#4046): no artifact, and every template it records has `component: null`. */
31
+ export function isImplicitRelease(release) {
32
+ const templates = release.targets.flatMap((t) => t.templates);
33
+ return release.artifactDigests.length === 0 && templates.length > 0 && templates.every((t) => t.component === null);
34
+ }
35
+ function isGate(step) {
36
+ return step.kind === "gate";
37
+ }
38
+ function isPhase(step) {
39
+ return typeof step.phase === "string" && Array.isArray(step.steps);
40
+ }
41
+ /**
42
+ * Point every template `components` read at the target's recorded bytes.
43
+ * Returns the rewritten compositions and the files to write, or the reasons
44
+ * the promote is refused: a template the target does not record, one whose
45
+ * bytes are missing, or one whose bytes do not hash to the target's digest.
46
+ */
47
+ export async function pinReleaseTemplates(components, release, target, readTemplate) {
48
+ const errors = [];
49
+ const files = [];
50
+ const out = [];
51
+ for (const component of components) {
52
+ const replace = new Map();
53
+ for (const ref of templateRefs(component)) {
54
+ if (replace.has(ref.value))
55
+ continue;
56
+ const recorded = target.templates.find((t) => t.component === component.name && t.path === ref.path);
57
+ if (!recorded) {
58
+ errors.push(`component "${component.name}" reads ${ref.field} "${ref.value}", which release ${release.releaseDigest} does not record for "${target.env}"; ` +
59
+ `this checkout's deploy is not the one the release was compiled from (commit ${release.commit.slice(0, 12)})`);
60
+ continue;
61
+ }
62
+ const content = await readTemplate(recorded.digest);
63
+ if (content === null) {
64
+ errors.push(`component "${component.name}": the bytes of template "${ref.path}" (${recorded.digest}) are not on the chant/lifecycle branch; fetch it and try again`);
65
+ continue;
66
+ }
67
+ const got = contentDigest(content);
68
+ if (got !== recorded.digest) {
69
+ errors.push(`component "${component.name}": template "${ref.path}" hashes to ${got}, but the release's target for "${target.env}" records ${recorded.digest}; refusing to deploy it`);
70
+ continue;
71
+ }
72
+ const path = join(RELEASE_TEMPLATES_DIR, recorded.digest.replace(/:/g, "_"), basename(ref.path));
73
+ files.push({ path, content });
74
+ replace.set(ref.value, path);
75
+ }
76
+ const rewrite = (phase) => ({
77
+ ...phase,
78
+ steps: phase.steps.map((step) => {
79
+ if (isPhase(step))
80
+ return rewrite(step);
81
+ if (isGate(step))
82
+ return step;
83
+ const next = { ...step };
84
+ for (const field of TEMPLATE_FIELDS) {
85
+ const v = next[field];
86
+ if (typeof v === "string" && replace.has(v))
87
+ next[field] = replace.get(v);
88
+ else if (Array.isArray(v))
89
+ next[field] = v.map((x) => (typeof x === "string" && replace.has(x) ? replace.get(x) : x));
90
+ }
91
+ return next;
92
+ }),
93
+ });
94
+ out.push({ ...component, deploy: component.deploy.map(rewrite) });
95
+ }
96
+ return errors.length > 0 ? { errors } : { components: out, files };
97
+ }
98
+ /**
99
+ * The files a release's target records, read back by digest and checked, for
100
+ * `chant release export` (#4046). A project with no components has no deploy
101
+ * step for a promote to point at the recorded bytes, so its deploy (an Op such
102
+ * as `chant run deploy`, or a CI job) reads the files this writes instead of
103
+ * building them again. Each path is the one the build wrote, relative to the
104
+ * member's directory; a template whose bytes are missing or don't hash to the
105
+ * target's digest is refused, as {@link pinReleaseTemplates} refuses one.
106
+ */
107
+ export async function targetFiles(release, target, readTemplate) {
108
+ const errors = [];
109
+ const files = [];
110
+ for (const t of target.templates) {
111
+ const who = t.component === null ? "" : `component "${t.component}": `;
112
+ if (t.path.startsWith("/") || t.path.split("/").includes("..")) {
113
+ errors.push(`${who}template "${t.path}" is not a path inside the member's directory; refusing to write it`);
114
+ continue;
115
+ }
116
+ const content = await readTemplate(t.digest);
117
+ if (content === null) {
118
+ errors.push(`${who}the bytes of template "${t.path}" (${t.digest}) are not on the chant/lifecycle branch; fetch it and try again`);
119
+ continue;
120
+ }
121
+ const got = contentDigest(content);
122
+ if (got !== t.digest) {
123
+ errors.push(`${who}template "${t.path}" hashes to ${got}, but release ${release.releaseDigest} records ${t.digest} for "${target.env}"; refusing to write it`);
124
+ continue;
125
+ }
126
+ const same = files.find((f) => f.path === t.path);
127
+ if (same) {
128
+ if (same.content !== content)
129
+ errors.push(`two components record different bytes at "${t.path}" for "${target.env}", so they can't both be written there`);
130
+ continue;
131
+ }
132
+ files.push({ path: t.path, content });
133
+ }
134
+ return errors.length > 0 ? { errors } : { files };
135
+ }
136
+ /** Write the pinned templates under `dir`, the member's directory. */
137
+ export function writePinnedTemplates(dir, files) {
138
+ for (const f of files) {
139
+ const full = join(dir, f.path);
140
+ mkdirSync(dirname(full), { recursive: true });
141
+ writeFileSync(full, f.content);
142
+ }
143
+ }
144
+ /**
145
+ * Remove the templates {@link writePinnedTemplates} wrote once the promote is
146
+ * done, and {@link RELEASE_TEMPLATES_DIR} with them when nothing else is in
147
+ * it, so a promote leaves the checkout as it found it. A re-run writes them
148
+ * again from the release.
149
+ */
150
+ export function removePinnedTemplates(dir, files) {
151
+ for (const f of files)
152
+ rmSync(dirname(join(dir, f.path)), { recursive: true, force: true });
153
+ const root = join(dir, RELEASE_TEMPLATES_DIR);
154
+ try {
155
+ if (readdirSync(root).length === 0)
156
+ rmdirSync(root);
157
+ }
158
+ catch {
159
+ // Already gone, or not ours to remove.
160
+ }
161
+ }
162
+ /**
163
+ * Whether the artifact a promote deploys under a release is one the release
164
+ * built (#4045, the rule #4026 left open). The release records build digests
165
+ * (`artifactDigests`, the digest the archive step returned), and a deploy
166
+ * record carries the publish digest, which is another value for an image, so
167
+ * the two are compared through the build manifest the source deploy record
168
+ * names (`manifestDigest`), whose entries carry build digests at the same
169
+ * archive paths:
170
+ *
171
+ * - a source record that names this release in `releaseDigest` matches;
172
+ * - else, each of the release's artifacts for the component must be in that
173
+ * manifest at its path with the release's digest, and one that differs is
174
+ * a mismatch;
175
+ * - a record with no `manifestDigest`, a manifest that isn't stored, or an
176
+ * artifact path the manifest doesn't hold can't be compared.
177
+ *
178
+ * A mismatch is a warning, not a refusal. The environment promoted from was
179
+ * deployed by its own `run --components`, which builds again, and an image
180
+ * build is not reproducible, so its digest differs from the cut's for the
181
+ * same commit. Refusing would refuse every image promote until a deploy can
182
+ * run the release's own artifacts (#4043).
183
+ */
184
+ export async function releaseArtifactMismatches(release, sources, readManifest) {
185
+ const out = [];
186
+ for (const { component, source } of sources) {
187
+ if (source.releaseDigest === release.releaseDigest)
188
+ continue;
189
+ const artifacts = release.artifactDigests.filter((a) => a.component === component);
190
+ if (artifacts.length === 0 || source.manifestDigest === undefined)
191
+ continue;
192
+ const manifest = await readManifest(source.manifestDigest);
193
+ if (!manifest)
194
+ continue;
195
+ for (const a of artifacts) {
196
+ const entry = manifest.contents.find((e) => e.path === a.path && e.kind === a.kind);
197
+ if (entry && entry.digest !== a.digest) {
198
+ out.push(`${component}: the ${source.env} deploy being promoted was built with ${a.path} at ${entry.digest}, ` +
199
+ `but release ${release.releaseDigest} built it at ${a.digest}, so the artifact deployed is not the release's own`);
200
+ }
201
+ }
202
+ }
203
+ return out;
204
+ }
@@ -79,6 +79,13 @@ export interface RunDoneEvent {
79
79
  type: "run-done";
80
80
  status: RunProgressStatus;
81
81
  }
82
+ /**
83
+ * @deprecated Read `RunEvent` (`../run-event.ts`, exported from
84
+ * `@intentius/chant`) instead: one contract for Op, component and pipeline
85
+ * runs, with the run id, commit and runtime on every event (#4019).
86
+ * `runEventOfProgress` maps each of these onto it. `--progress-json` keeps
87
+ * printing this shape until #4041 moves it to the run-event stream.
88
+ */
82
89
  export type RunProgressEvent = RunStartEvent | WaveStartEvent | ComponentStartEvent | PhaseStartEvent | StepEvent | PhaseDoneEvent | ComponentDoneEvent | WaveDoneEvent | RunDoneEvent;
83
90
  /** A sink that receives progress events as they occur. The driver only ever calls this — it never writes to a stream directly, so it stays testable without stdout. */
84
91
  export type RunProgressSink = (event: RunProgressEvent) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"run-progress.d.ts","sourceRoot":"","sources":["../../src/components/run-progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mPAAmP;AACnP,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1D,mMAAmM;AACnM,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;CACnB;AAED,2GAA2G;AAC3G,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2JAA2J;AAC3J,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+FAA+F;AAC/F,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,QAAQ,CAAC;IACpC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0LAA0L;AAC1L,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,2IAA2I;AAC3I,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,uHAAuH;AACvH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,4FAA4F;AAC5F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,cAAc,GACd,mBAAmB,GACnB,eAAe,GACf,SAAS,GACT,cAAc,GACd,kBAAkB,GAClB,aAAa,GACb,YAAY,CAAC;AAEjB,uKAAuK;AACvK,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,gBAAgB,EACrD,KAAK,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAA0C,GACnE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAEpB"}
1
+ {"version":3,"file":"run-progress.d.ts","sourceRoot":"","sources":["../../src/components/run-progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,mPAAmP;AACnP,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1D,mMAAmM;AACnM,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;CACnB;AAED,2GAA2G;AAC3G,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,2JAA2J;AAC3J,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+FAA+F;AAC/F,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG,QAAQ,CAAC;IACpC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0LAA0L;AAC1L,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,2IAA2I;AAC3I,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,uHAAuH;AACvH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,4FAA4F;AAC5F,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,cAAc,GACd,mBAAmB,GACnB,eAAe,GACf,SAAS,GACT,cAAc,GACd,kBAAkB,GAClB,aAAa,GACb,YAAY,CAAC;AAEjB,uKAAuK;AACvK,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAEhE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,gBAAgB,EACrD,KAAK,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAA0C,GACnE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAEpB"}
@@ -18,7 +18,7 @@
18
18
  * plans as `undefined`. Cross-component wiring (`stackOutput()`,
19
19
  * `@<component>.publish.*`) resolves.
20
20
  */
21
- import { type DriverComponent } from "./driver.js";
21
+ import { type DriverComponent, type DriverPhase, type DriverStep } from "./driver.js";
22
22
  import type { CapabilityRegistry, DeployContext } from "./capability.js";
23
23
  import type { WaveMember } from "../gated-waves.js";
24
24
  import type { ChangeSetPart } from "../change-set.js";
@@ -37,6 +37,8 @@ export type WaveComponentPlan = {
37
37
  component: string;
38
38
  error: string;
39
39
  };
40
+ /** Every capability step in a composition, nested phases included, gates left out. */
41
+ export declare function capabilitySteps(phases: readonly DriverPhase[]): DriverStep[];
40
42
  /** Plan one component against the outputs earlier waves produced. Never throws: a failure comes back as `error`. */
41
43
  export declare function planWaveComponent(component: DriverComponent, registry: CapabilityRegistry, ctx: DeployContext, componentOutputs: Record<string, Record<string, unknown>>): Promise<WaveComponentPlan>;
42
44
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"wave-plan.d.ts","sourceRoot":"","sources":["../../src/components/wave-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAoB,KAAK,eAAe,EAAqC,MAAM,UAAU,CAAC;AAErG,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GACpG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA2BzC,oHAAoH;AACpH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,OAAO,CAAC,iBAAiB,CAAC,CAgC5B;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAU9C"}
1
+ {"version":3,"file":"wave-plan.d.ts","sourceRoot":"","sources":["../../src/components/wave-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAoB,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAErG,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAA;CAAE,GACpG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAUzC,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,UAAU,EAAE,CAc5E;AAED,oHAAoH;AACpH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,OAAO,CAAC,iBAAiB,CAAC,CAgC5B;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAU9C"}
@@ -28,7 +28,7 @@ function emptyPart(member) {
28
28
  };
29
29
  }
30
30
  /** Every capability step in a composition, nested phases included, gates left out. */
31
- function capabilitySteps(phases) {
31
+ export function capabilitySteps(phases) {
32
32
  const out = [];
33
33
  const walk = (steps) => {
34
34
  for (const step of steps) {