@intentius/chant 0.124.27 → 0.124.29

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 (681) 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/build-params.d.ts +34 -1
  20. package/dist/build-params.d.ts.map +1 -1
  21. package/dist/build-params.js +31 -1
  22. package/dist/change-set-graph.d.ts +63 -0
  23. package/dist/change-set-graph.d.ts.map +1 -0
  24. package/dist/change-set-graph.js +130 -0
  25. package/dist/change-set.d.ts +62 -3
  26. package/dist/change-set.d.ts.map +1 -1
  27. package/dist/change-set.js +36 -4
  28. package/dist/chant-version.d.ts +9 -0
  29. package/dist/chant-version.d.ts.map +1 -0
  30. package/dist/chant-version.js +16 -0
  31. package/dist/cli/build-params-cli.d.ts +7 -1
  32. package/dist/cli/build-params-cli.d.ts.map +1 -1
  33. package/dist/cli/build-params-cli.js +17 -8
  34. package/dist/cli/commands/build.d.ts +8 -0
  35. package/dist/cli/commands/build.d.ts.map +1 -1
  36. package/dist/cli/commands/build.js +15 -11
  37. package/dist/cli/commands/check-lexicon-docs.d.ts.map +1 -1
  38. package/dist/cli/commands/check-lexicon-docs.js +30 -2
  39. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  40. package/dist/cli/commands/check-lexicon.js +13 -2
  41. package/dist/cli/commands/init-lexicon/templates/docs.d.ts +4 -1
  42. package/dist/cli/commands/init-lexicon/templates/docs.d.ts.map +1 -1
  43. package/dist/cli/commands/init-lexicon/templates/docs.js +6 -6
  44. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  45. package/dist/cli/commands/init-lexicon.js +17 -8
  46. package/dist/cli/handlers/approve.d.ts.map +1 -1
  47. package/dist/cli/handlers/approve.js +64 -4
  48. package/dist/cli/handlers/build.d.ts.map +1 -1
  49. package/dist/cli/handlers/build.js +43 -4
  50. package/dist/cli/handlers/change-set.d.ts +10 -0
  51. package/dist/cli/handlers/change-set.d.ts.map +1 -1
  52. package/dist/cli/handlers/change-set.js +51 -1
  53. package/dist/cli/handlers/fan-out.d.ts +10 -1
  54. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  55. package/dist/cli/handlers/fan-out.js +54 -6
  56. package/dist/cli/handlers/lifecycle-gc.d.ts +19 -0
  57. package/dist/cli/handlers/lifecycle-gc.d.ts.map +1 -0
  58. package/dist/cli/handlers/lifecycle-gc.js +143 -0
  59. package/dist/cli/handlers/pr.d.ts +16 -2
  60. package/dist/cli/handlers/pr.d.ts.map +1 -1
  61. package/dist/cli/handlers/pr.js +269 -37
  62. package/dist/cli/handlers/promote.d.ts +7 -0
  63. package/dist/cli/handlers/promote.d.ts.map +1 -1
  64. package/dist/cli/handlers/promote.js +440 -28
  65. package/dist/cli/handlers/release.d.ts +91 -0
  66. package/dist/cli/handlers/release.d.ts.map +1 -0
  67. package/dist/cli/handlers/release.js +589 -0
  68. package/dist/cli/handlers/run.d.ts +38 -2
  69. package/dist/cli/handlers/run.d.ts.map +1 -1
  70. package/dist/cli/handlers/run.js +234 -16
  71. package/dist/cli/main.d.ts.map +1 -1
  72. package/dist/cli/main.js +143 -17
  73. package/dist/cli/mcp/workspace-tools.js +1 -1
  74. package/dist/cli/parse-args.d.ts.map +1 -1
  75. package/dist/cli/parse-args.js +73 -5
  76. package/dist/cli/registry.d.ts +43 -5
  77. package/dist/cli/registry.d.ts.map +1 -1
  78. package/dist/cli/run-events.d.ts +30 -0
  79. package/dist/cli/run-events.d.ts.map +1 -0
  80. package/dist/cli/run-events.js +49 -0
  81. package/dist/cli/version.d.ts +3 -5
  82. package/dist/cli/version.d.ts.map +1 -1
  83. package/dist/cli/version.js +3 -13
  84. package/dist/codegen/docs-in-site.d.ts +71 -0
  85. package/dist/codegen/docs-in-site.d.ts.map +1 -0
  86. package/dist/codegen/docs-in-site.js +177 -0
  87. package/dist/codegen/docs-types.d.ts +14 -1
  88. package/dist/codegen/docs-types.d.ts.map +1 -1
  89. package/dist/codegen/docs.d.ts +18 -1
  90. package/dist/codegen/docs.d.ts.map +1 -1
  91. package/dist/codegen/docs.js +40 -7
  92. package/dist/codegen/rehype-base-url.mjs +15 -9
  93. package/dist/components/auto-release.d.ts +6 -1
  94. package/dist/components/auto-release.d.ts.map +1 -1
  95. package/dist/components/auto-release.js +3 -0
  96. package/dist/components/capability.d.ts +9 -0
  97. package/dist/components/capability.d.ts.map +1 -1
  98. package/dist/components/cli-support.d.ts +6 -0
  99. package/dist/components/cli-support.d.ts.map +1 -1
  100. package/dist/components/cli-support.js +10 -9
  101. package/dist/components/driver.d.ts +50 -9
  102. package/dist/components/driver.d.ts.map +1 -1
  103. package/dist/components/driver.js +116 -54
  104. package/dist/components/fan-out-inputs.d.ts +69 -0
  105. package/dist/components/fan-out-inputs.d.ts.map +1 -0
  106. package/dist/components/fan-out-inputs.js +169 -0
  107. package/dist/components/fan-out-record.d.ts +13 -0
  108. package/dist/components/fan-out-record.d.ts.map +1 -1
  109. package/dist/components/fan-out-record.js +16 -0
  110. package/dist/components/fan-out-run.d.ts +7 -0
  111. package/dist/components/fan-out-run.d.ts.map +1 -1
  112. package/dist/components/fan-out-run.js +85 -26
  113. package/dist/components/fan-out.d.ts +4 -0
  114. package/dist/components/fan-out.d.ts.map +1 -1
  115. package/dist/components/pr-pipeline.d.ts +25 -0
  116. package/dist/components/pr-pipeline.d.ts.map +1 -1
  117. package/dist/components/pr-pipeline.js +22 -4
  118. package/dist/components/pr-run.d.ts +11 -0
  119. package/dist/components/pr-run.d.ts.map +1 -1
  120. package/dist/components/pr-run.js +20 -1
  121. package/dist/components/promote-order.d.ts +38 -0
  122. package/dist/components/promote-order.d.ts.map +1 -0
  123. package/dist/components/promote-order.js +62 -0
  124. package/dist/components/promote.d.ts +38 -2
  125. package/dist/components/promote.d.ts.map +1 -1
  126. package/dist/components/promote.js +77 -2
  127. package/dist/components/release-compile.d.ts +142 -0
  128. package/dist/components/release-compile.d.ts.map +1 -0
  129. package/dist/components/release-compile.js +382 -0
  130. package/dist/components/release-gate.d.ts +135 -0
  131. package/dist/components/release-gate.d.ts.map +1 -0
  132. package/dist/components/release-gate.js +288 -0
  133. package/dist/components/release-promote.d.ts +96 -0
  134. package/dist/components/release-promote.d.ts.map +1 -0
  135. package/dist/components/release-promote.js +204 -0
  136. package/dist/components/run-progress.d.ts +7 -0
  137. package/dist/components/run-progress.d.ts.map +1 -1
  138. package/dist/components/wave-plan.d.ts +8 -1
  139. package/dist/components/wave-plan.d.ts.map +1 -1
  140. package/dist/components/wave-plan.js +11 -3
  141. package/dist/config.d.ts +45 -0
  142. package/dist/config.d.ts.map +1 -1
  143. package/dist/config.js +3 -0
  144. package/dist/flag-params.d.ts +54 -0
  145. package/dist/flag-params.d.ts.map +1 -0
  146. package/dist/flag-params.js +130 -0
  147. package/dist/index.d.ts +1 -0
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +2 -0
  150. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts +120 -0
  151. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -0
  152. package/dist/lifecycle/__fixtures__/publish-fakes.js +304 -0
  153. package/dist/lifecycle/change-set-store.d.ts +68 -0
  154. package/dist/lifecycle/change-set-store.d.ts.map +1 -0
  155. package/dist/lifecycle/change-set-store.js +97 -0
  156. package/dist/lifecycle/commit-sha.d.ts +13 -0
  157. package/dist/lifecycle/commit-sha.d.ts.map +1 -0
  158. package/dist/lifecycle/commit-sha.js +21 -0
  159. package/dist/lifecycle/delivery-metrics.d.ts +139 -0
  160. package/dist/lifecycle/delivery-metrics.d.ts.map +1 -0
  161. package/dist/lifecycle/delivery-metrics.js +145 -0
  162. package/dist/lifecycle/deploy-outcome.d.ts +81 -0
  163. package/dist/lifecycle/deploy-outcome.d.ts.map +1 -0
  164. package/dist/lifecycle/deploy-outcome.js +101 -0
  165. package/dist/lifecycle/gate-change-set.d.ts +78 -0
  166. package/dist/lifecycle/gate-change-set.d.ts.map +1 -0
  167. package/dist/lifecycle/gate-change-set.js +138 -0
  168. package/dist/lifecycle/gate-ledger.d.ts +51 -4
  169. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  170. package/dist/lifecycle/gate-ledger.js +18 -0
  171. package/dist/lifecycle/git.d.ts +30 -1
  172. package/dist/lifecycle/git.d.ts.map +1 -1
  173. package/dist/lifecycle/git.js +31 -5
  174. package/dist/lifecycle/index.d.ts +4 -0
  175. package/dist/lifecycle/index.d.ts.map +1 -1
  176. package/dist/lifecycle/index.js +4 -0
  177. package/dist/lifecycle/mixed-environment.d.ts +95 -0
  178. package/dist/lifecycle/mixed-environment.d.ts.map +1 -0
  179. package/dist/lifecycle/mixed-environment.js +154 -0
  180. package/dist/lifecycle/publish-attachments.d.ts +79 -0
  181. package/dist/lifecycle/publish-attachments.d.ts.map +1 -0
  182. package/dist/lifecycle/publish-attachments.js +179 -0
  183. package/dist/lifecycle/publish-credentials.d.ts +37 -0
  184. package/dist/lifecycle/publish-credentials.d.ts.map +1 -0
  185. package/dist/lifecycle/publish-credentials.js +69 -0
  186. package/dist/lifecycle/publish-declaration.d.ts +97 -0
  187. package/dist/lifecycle/publish-declaration.d.ts.map +1 -0
  188. package/dist/lifecycle/publish-declaration.js +83 -0
  189. package/dist/lifecycle/publish-forge.d.ts +53 -0
  190. package/dist/lifecycle/publish-forge.d.ts.map +1 -0
  191. package/dist/lifecycle/publish-forge.js +298 -0
  192. package/dist/lifecycle/publish-npm.d.ts +61 -0
  193. package/dist/lifecycle/publish-npm.d.ts.map +1 -0
  194. package/dist/lifecycle/publish-npm.js +242 -0
  195. package/dist/lifecycle/publish-oci.d.ts +64 -0
  196. package/dist/lifecycle/publish-oci.d.ts.map +1 -0
  197. package/dist/lifecycle/publish-oci.js +383 -0
  198. package/dist/lifecycle/publish-record.d.ts +66 -0
  199. package/dist/lifecycle/publish-record.d.ts.map +1 -0
  200. package/dist/lifecycle/publish-record.js +84 -0
  201. package/dist/lifecycle/publish-targets.d.ts +45 -0
  202. package/dist/lifecycle/publish-targets.d.ts.map +1 -0
  203. package/dist/lifecycle/publish-targets.js +85 -0
  204. package/dist/lifecycle/release-cut.d.ts +154 -0
  205. package/dist/lifecycle/release-cut.d.ts.map +1 -0
  206. package/dist/lifecycle/release-cut.js +366 -0
  207. package/dist/lifecycle/release-join.d.ts +95 -0
  208. package/dist/lifecycle/release-join.d.ts.map +1 -0
  209. package/dist/lifecycle/release-join.js +139 -0
  210. package/dist/lifecycle/release-ledger.d.ts +54 -0
  211. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  212. package/dist/lifecycle/release-ledger.js +53 -20
  213. package/dist/lifecycle/release-publish.d.ts +312 -0
  214. package/dist/lifecycle/release-publish.d.ts.map +1 -0
  215. package/dist/lifecycle/release-publish.js +335 -0
  216. package/dist/lifecycle/release-revocation.d.ts +80 -0
  217. package/dist/lifecycle/release-revocation.d.ts.map +1 -0
  218. package/dist/lifecycle/release-revocation.js +123 -0
  219. package/dist/lifecycle/release-store.d.ts +200 -0
  220. package/dist/lifecycle/release-store.d.ts.map +1 -0
  221. package/dist/lifecycle/release-store.js +320 -0
  222. package/dist/lifecycle/release-verify.d.ts +61 -0
  223. package/dist/lifecycle/release-verify.d.ts.map +1 -0
  224. package/dist/lifecycle/release-verify.js +92 -0
  225. package/dist/lifecycle/release-workstation.d.ts +91 -0
  226. package/dist/lifecycle/release-workstation.d.ts.map +1 -0
  227. package/dist/lifecycle/release-workstation.js +180 -0
  228. package/dist/lifecycle/retention-policy.d.ts +45 -0
  229. package/dist/lifecycle/retention-policy.d.ts.map +1 -0
  230. package/dist/lifecycle/retention-policy.js +43 -0
  231. package/dist/lifecycle/retention.d.ts +185 -0
  232. package/dist/lifecycle/retention.d.ts.map +1 -0
  233. package/dist/lifecycle/retention.js +400 -0
  234. package/dist/lifecycle/run-ledger.d.ts +4 -0
  235. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  236. package/dist/lifecycle/run-ledger.js +2 -0
  237. package/dist/op/activities/change-coverage.d.ts.map +1 -1
  238. package/dist/op/activities/change-coverage.js +4 -2
  239. package/dist/op/activities/source-release.d.ts.map +1 -1
  240. package/dist/op/activities/source-release.js +7 -3
  241. package/dist/op/activities/source-rollback.d.ts.map +1 -1
  242. package/dist/op/activities/source-rollback.js +7 -3
  243. package/dist/op/gate-name.d.ts +11 -2
  244. package/dist/op/gate-name.d.ts.map +1 -1
  245. package/dist/op/gate-name.js +12 -3
  246. package/dist/op/gate-run-locator.d.ts +22 -0
  247. package/dist/op/gate-run-locator.d.ts.map +1 -1
  248. package/dist/op/gate-run-locator.js +31 -0
  249. package/dist/op/gate.d.ts +27 -3
  250. package/dist/op/gate.d.ts.map +1 -1
  251. package/dist/op/gate.js +57 -3
  252. package/dist/op/local-executor.d.ts +36 -1
  253. package/dist/op/local-executor.d.ts.map +1 -1
  254. package/dist/op/local-executor.js +158 -52
  255. package/dist/op/op-waves-run.d.ts.map +1 -1
  256. package/dist/op/op-waves-run.js +4 -0
  257. package/dist/op/run-live.d.ts +2 -0
  258. package/dist/op/run-live.d.ts.map +1 -1
  259. package/dist/op/run-live.js +1 -1
  260. package/dist/op/runtime.d.ts +46 -0
  261. package/dist/op/runtime.d.ts.map +1 -1
  262. package/dist/op/runtimes/local.d.ts.map +1 -1
  263. package/dist/op/runtimes/local.js +8 -0
  264. package/dist/plan-summary.d.ts.map +1 -1
  265. package/dist/plan-summary.js +8 -2
  266. package/dist/point-decision.d.ts +2 -0
  267. package/dist/point-decision.d.ts.map +1 -1
  268. package/dist/point-decision.js +9 -2
  269. package/dist/pr-loop.d.ts +7 -0
  270. package/dist/pr-loop.d.ts.map +1 -1
  271. package/dist/pr-loop.js +23 -4
  272. package/dist/pr-report-url.d.ts +82 -0
  273. package/dist/pr-report-url.d.ts.map +1 -0
  274. package/dist/pr-report-url.js +174 -0
  275. package/dist/provenance.d.ts +2 -2
  276. package/dist/provenance.d.ts.map +1 -1
  277. package/dist/run-event-store.d.ts +104 -0
  278. package/dist/run-event-store.d.ts.map +1 -0
  279. package/dist/run-event-store.js +251 -0
  280. package/dist/run-event-stream.d.ts +133 -0
  281. package/dist/run-event-stream.d.ts.map +1 -0
  282. package/dist/run-event-stream.js +242 -0
  283. package/dist/run-event.d.ts +285 -0
  284. package/dist/run-event.d.ts.map +1 -0
  285. package/dist/run-event.js +209 -0
  286. package/dist/wave-runtime.mjs +262 -226
  287. package/dist/workspace/__fixtures__/flag-workspace.d.ts +31 -0
  288. package/dist/workspace/__fixtures__/flag-workspace.d.ts.map +1 -0
  289. package/dist/workspace/__fixtures__/flag-workspace.js +114 -0
  290. package/dist/workspace/__fixtures__/run-event-check.d.ts +19 -0
  291. package/dist/workspace/__fixtures__/run-event-check.d.ts.map +1 -0
  292. package/dist/workspace/__fixtures__/run-event-check.js +59 -0
  293. package/dist/workspace/change-set-show.d.ts +56 -0
  294. package/dist/workspace/change-set-show.d.ts.map +1 -0
  295. package/dist/workspace/change-set-show.js +54 -0
  296. package/dist/workspace/change-set-show.schema.json +102 -0
  297. package/dist/workspace/change-set.schema.json +32 -1
  298. package/dist/workspace/changes-cli.d.ts.map +1 -1
  299. package/dist/workspace/changes-cli.js +10 -1
  300. package/dist/workspace/changes.d.ts +37 -0
  301. package/dist/workspace/changes.d.ts.map +1 -1
  302. package/dist/workspace/changes.js +49 -2
  303. package/dist/workspace/changes.schema.json +135 -0
  304. package/dist/workspace/check.schema.json +4 -2
  305. package/dist/workspace/checks/records.d.ts +9 -1
  306. package/dist/workspace/checks/records.d.ts.map +1 -1
  307. package/dist/workspace/checks/records.js +35 -1
  308. package/dist/workspace/checks.d.ts +1 -0
  309. package/dist/workspace/checks.d.ts.map +1 -1
  310. package/dist/workspace/checks.js +2 -1
  311. package/dist/workspace/ci-green-cli.d.ts +19 -4
  312. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  313. package/dist/workspace/ci-green-cli.js +75 -12
  314. package/dist/workspace/ci-green-forge.d.ts +20 -3
  315. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  316. package/dist/workspace/ci-green-forge.js +6 -4
  317. package/dist/workspace/ci-green-workflow.d.ts +11 -0
  318. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  319. package/dist/workspace/ci-green-workflow.js +6 -0
  320. package/dist/workspace/ci-green.d.ts +281 -13
  321. package/dist/workspace/ci-green.d.ts.map +1 -1
  322. package/dist/workspace/ci-green.js +456 -38
  323. package/dist/workspace/ci-last-green.schema.json +32 -2
  324. package/dist/workspace/ci-list.schema.json +525 -0
  325. package/dist/workspace/commit-links.d.ts +85 -0
  326. package/dist/workspace/commit-links.d.ts.map +1 -0
  327. package/dist/workspace/commit-links.js +163 -0
  328. package/dist/workspace/declaration.d.ts +35 -0
  329. package/dist/workspace/declaration.d.ts.map +1 -1
  330. package/dist/workspace/declaration.js +27 -1
  331. package/dist/workspace/declaration.schema.json +76 -0
  332. package/dist/workspace/declared-kinds.d.ts +16 -0
  333. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  334. package/dist/workspace/declared-kinds.js +25 -0
  335. package/dist/workspace/delivery-metrics.d.ts +91 -0
  336. package/dist/workspace/delivery-metrics.d.ts.map +1 -0
  337. package/dist/workspace/delivery-metrics.js +217 -0
  338. package/dist/workspace/delivery-metrics.schema.json +519 -0
  339. package/dist/workspace/flags-read.d.ts +37 -0
  340. package/dist/workspace/flags-read.d.ts.map +1 -0
  341. package/dist/workspace/flags-read.js +103 -0
  342. package/dist/workspace/flags.d.ts +100 -0
  343. package/dist/workspace/flags.d.ts.map +1 -0
  344. package/dist/workspace/flags.js +98 -0
  345. package/dist/workspace/graph-cli.js +1 -1
  346. package/dist/workspace/identity-gate-rule.d.ts +37 -0
  347. package/dist/workspace/identity-gate-rule.d.ts.map +1 -1
  348. package/dist/workspace/identity-gate-rule.js +72 -7
  349. package/dist/workspace/identity.d.ts +12 -0
  350. package/dist/workspace/identity.d.ts.map +1 -1
  351. package/dist/workspace/identity.js +13 -1
  352. package/dist/workspace/intent-cli.d.ts +11 -2
  353. package/dist/workspace/intent-cli.d.ts.map +1 -1
  354. package/dist/workspace/intent-cli.js +54 -5
  355. package/dist/workspace/intent-trace.d.ts +219 -0
  356. package/dist/workspace/intent-trace.d.ts.map +1 -0
  357. package/dist/workspace/intent-trace.js +314 -0
  358. package/dist/workspace/intent.d.ts +36 -7
  359. package/dist/workspace/intent.d.ts.map +1 -1
  360. package/dist/workspace/intent.js +192 -22
  361. package/dist/workspace/intent.schema.json +702 -6
  362. package/dist/workspace/ls.d.ts +4 -0
  363. package/dist/workspace/ls.d.ts.map +1 -1
  364. package/dist/workspace/ls.js +2 -0
  365. package/dist/workspace/ls.schema.json +3 -1
  366. package/dist/workspace/member-pipeline.d.ts +6 -0
  367. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  368. package/dist/workspace/member-pipeline.js +6 -0
  369. package/dist/workspace/overlap.d.ts +146 -0
  370. package/dist/workspace/overlap.d.ts.map +1 -0
  371. package/dist/workspace/overlap.js +276 -0
  372. package/dist/workspace/promotion-order.d.ts +41 -0
  373. package/dist/workspace/promotion-order.d.ts.map +1 -0
  374. package/dist/workspace/promotion-order.js +95 -0
  375. package/dist/workspace/reason-codes.d.ts +4 -0
  376. package/dist/workspace/reason-codes.d.ts.map +1 -1
  377. package/dist/workspace/reason-codes.js +7 -1
  378. package/dist/workspace/records.d.ts +15 -2
  379. package/dist/workspace/records.d.ts.map +1 -1
  380. package/dist/workspace/records.js +32 -0
  381. package/dist/workspace/records.schema.json +21 -2
  382. package/dist/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  383. package/dist/workspace/reference-kinds/flag/flag.schema.json +53 -0
  384. package/dist/workspace/releases.d.ts +81 -0
  385. package/dist/workspace/releases.d.ts.map +1 -0
  386. package/dist/workspace/releases.js +103 -0
  387. package/dist/workspace/releases.schema.json +513 -0
  388. package/dist/workspace/run-event.schema.json +295 -0
  389. package/dist/workspace/status-gates.d.ts +34 -1
  390. package/dist/workspace/status-gates.d.ts.map +1 -1
  391. package/dist/workspace/status-gates.js +31 -2
  392. package/dist/workspace/status-stewards.d.ts +4 -0
  393. package/dist/workspace/status-stewards.d.ts.map +1 -1
  394. package/dist/workspace/status-stewards.js +2 -0
  395. package/dist/workspace/status.d.ts +117 -0
  396. package/dist/workspace/status.d.ts.map +1 -1
  397. package/dist/workspace/status.js +218 -4
  398. package/dist/workspace/status.schema.json +268 -2
  399. package/dist/workspace/trust/ci-tag-statement.d.ts +102 -0
  400. package/dist/workspace/trust/ci-tag-statement.d.ts.map +1 -0
  401. package/dist/workspace/trust/ci-tag-statement.js +123 -0
  402. package/dist/workspace/trust/op-run-statement.d.ts +91 -0
  403. package/dist/workspace/trust/op-run-statement.d.ts.map +1 -0
  404. package/dist/workspace/trust/op-run-statement.js +143 -0
  405. package/dist/workspace/trust/rotation.d.ts +18 -2
  406. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  407. package/dist/workspace/trust/rotation.js +65 -16
  408. package/dist/workspace/trust/seal.d.ts +11 -0
  409. package/dist/workspace/trust/seal.d.ts.map +1 -1
  410. package/dist/workspace/trust/seal.js +9 -0
  411. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  412. package/dist/workspace/trust/ssh-commit.js +10 -10
  413. package/dist/workspace/wip.d.ts.map +1 -1
  414. package/dist/workspace/wip.js +11 -3
  415. package/package.json +1 -1
  416. package/src/__golden__/wave-loop/fan-out-gated.json +8 -0
  417. package/src/__golden__/wave-loop/fan-out-no-members.json +4 -0
  418. package/src/__golden__/wave-loop/fan-out-only.json +6 -0
  419. package/src/__golden__/wave-loop/op-by-apply-hold.json +2 -0
  420. package/src/__golden__/wave-loop/op-cost-member.json +3 -0
  421. package/src/__golden__/wave-loop/op-held-on-before-apply.json +1 -0
  422. package/src/__golden__/wave-loop/op-held-on.json +2 -0
  423. package/src/__golden__/wave-loop/op-hooks-held.json +2 -0
  424. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +2 -0
  425. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +3 -0
  426. package/src/__golden__/wave-loop/op-hooks-share.json +3 -0
  427. package/src/__golden__/wave-loop/op-per-run.json +7 -0
  428. package/src/__golden__/wave-loop/op-pr-review.json +7 -0
  429. package/src/__golden__/wave-loop/op-sealed.json +3 -0
  430. package/src/__golden__/wave-loop/op-spend.json +3 -0
  431. package/src/__golden__/wave-loop/op-wave-commands.json +7 -0
  432. package/src/__golden__/wave-loop/op-wide-waiting.json +4 -0
  433. package/src/build-params.test.ts +46 -0
  434. package/src/build-params.ts +55 -1
  435. package/src/change-set-graph.test.ts +72 -0
  436. package/src/change-set-graph.ts +141 -0
  437. package/src/change-set.ts +87 -6
  438. package/src/chant-version.ts +16 -0
  439. package/src/cli/build-params-cli.ts +22 -9
  440. package/src/cli/commands/build.ts +25 -11
  441. package/src/cli/commands/check-lexicon-docs.test.ts +51 -0
  442. package/src/cli/commands/check-lexicon-docs.ts +39 -2
  443. package/src/cli/commands/check-lexicon.ts +14 -2
  444. package/src/cli/commands/init-lexicon/templates/docs.ts +7 -6
  445. package/src/cli/commands/init-lexicon.test.ts +25 -0
  446. package/src/cli/commands/init-lexicon.ts +18 -8
  447. package/src/cli/handlers/approve-release.test.ts +84 -0
  448. package/src/cli/handlers/approve-revoked.test.ts +155 -0
  449. package/src/cli/handlers/approve.ts +65 -2
  450. package/src/cli/handlers/build.test.ts +67 -0
  451. package/src/cli/handlers/build.ts +46 -4
  452. package/src/cli/handlers/change-set.ts +49 -1
  453. package/src/cli/handlers/fan-out.test.ts +228 -1
  454. package/src/cli/handlers/fan-out.ts +53 -6
  455. package/src/cli/handlers/intent-trace.e2e.test.ts +201 -0
  456. package/src/cli/handlers/lifecycle-gc.test.ts +126 -0
  457. package/src/cli/handlers/lifecycle-gc.ts +146 -0
  458. package/src/cli/handlers/operator.test.ts +37 -0
  459. package/src/cli/handlers/pr.test.ts +341 -0
  460. package/src/cli/handlers/pr.ts +292 -47
  461. package/src/cli/handlers/promote.test.ts +669 -7
  462. package/src/cli/handlers/promote.ts +464 -29
  463. package/src/cli/handlers/release-implicit.e2e.test.ts +161 -0
  464. package/src/cli/handlers/release-join.e2e.test.ts +185 -0
  465. package/src/cli/handlers/release-publish-targets.e2e.test.ts +295 -0
  466. package/src/cli/handlers/release-verify.e2e.test.ts +117 -0
  467. package/src/cli/handlers/release-workstation-ci.e2e.test.ts +135 -0
  468. package/src/cli/handlers/release.e2e.test.ts +199 -0
  469. package/src/cli/handlers/release.ts +593 -0
  470. package/src/cli/handlers/run-auto-release.test.ts +80 -0
  471. package/src/cli/handlers/run-events-cmd.test.ts +92 -0
  472. package/src/cli/handlers/run-release.test.ts +55 -0
  473. package/src/cli/handlers/run.test.ts +30 -0
  474. package/src/cli/handlers/run.ts +243 -18
  475. package/src/cli/main.test.ts +8 -0
  476. package/src/cli/main.ts +143 -17
  477. package/src/cli/mcp/never-over-mcp.test.ts +2 -0
  478. package/src/cli/mcp/workspace-tools.ts +1 -1
  479. package/src/cli/parse-args.ts +56 -5
  480. package/src/cli/registry.ts +43 -5
  481. package/src/cli/run-events.ts +57 -0
  482. package/src/cli/version.ts +3 -13
  483. package/src/codegen/docs-in-site.test.ts +166 -0
  484. package/src/codegen/docs-in-site.ts +182 -0
  485. package/src/codegen/docs-site/AgentPrompt.astro +26 -1
  486. package/src/codegen/docs-types.ts +14 -1
  487. package/src/codegen/docs.ts +60 -7
  488. package/src/codegen/rehype-base-url.d.mts +3 -1
  489. package/src/codegen/rehype-base-url.mjs +15 -9
  490. package/src/codegen/rehype-base-url.test.ts +34 -0
  491. package/src/components/auto-release.test.ts +30 -0
  492. package/src/components/auto-release.ts +9 -1
  493. package/src/components/capability.ts +9 -0
  494. package/src/components/cli-support.test.ts +82 -0
  495. package/src/components/cli-support.ts +16 -9
  496. package/src/components/driver.test.ts +24 -0
  497. package/src/components/driver.ts +165 -56
  498. package/src/components/fan-out-inputs.test.ts +85 -0
  499. package/src/components/fan-out-inputs.ts +192 -0
  500. package/src/components/fan-out-record.test.ts +10 -0
  501. package/src/components/fan-out-record.ts +19 -0
  502. package/src/components/fan-out-run.ts +104 -35
  503. package/src/components/fan-out.ts +4 -0
  504. package/src/components/pr-pipeline.ts +35 -4
  505. package/src/components/pr-run.ts +30 -1
  506. package/src/components/promote-order.test.ts +90 -0
  507. package/src/components/promote-order.ts +75 -0
  508. package/src/components/promote.test.ts +10 -1
  509. package/src/components/promote.ts +94 -3
  510. package/src/components/release-compile.test.ts +147 -0
  511. package/src/components/release-compile.ts +459 -0
  512. package/src/components/release-gate.test.ts +215 -0
  513. package/src/components/release-gate.ts +355 -0
  514. package/src/components/release-promote.test.ts +159 -0
  515. package/src/components/release-promote.ts +232 -0
  516. package/src/components/run-progress.ts +7 -0
  517. package/src/components/wave-plan.ts +16 -3
  518. package/src/config.ts +15 -1
  519. package/src/flag-params.test.ts +144 -0
  520. package/src/flag-params.ts +134 -0
  521. package/src/index.ts +2 -0
  522. package/src/lifecycle/__fixtures__/publish-fakes.ts +351 -0
  523. package/src/lifecycle/change-set-store.test.ts +217 -0
  524. package/src/lifecycle/change-set-store.ts +113 -0
  525. package/src/lifecycle/commit-sha.ts +23 -0
  526. package/src/lifecycle/delivery-metrics.ts +263 -0
  527. package/src/lifecycle/deploy-outcome.ts +147 -0
  528. package/src/lifecycle/gate-change-set.e2e.test.ts +122 -0
  529. package/src/lifecycle/gate-change-set.ts +164 -0
  530. package/src/lifecycle/gate-ledger.test.ts +33 -0
  531. package/src/lifecycle/gate-ledger.ts +68 -3
  532. package/src/lifecycle/git.ts +61 -8
  533. package/src/lifecycle/index.ts +4 -0
  534. package/src/lifecycle/mixed-environment.test.ts +97 -0
  535. package/src/lifecycle/mixed-environment.ts +204 -0
  536. package/src/lifecycle/publish-attachments.ts +196 -0
  537. package/src/lifecycle/publish-credentials.ts +84 -0
  538. package/src/lifecycle/publish-declaration.ts +95 -0
  539. package/src/lifecycle/publish-forge.ts +325 -0
  540. package/src/lifecycle/publish-npm.ts +259 -0
  541. package/src/lifecycle/publish-oci.ts +396 -0
  542. package/src/lifecycle/publish-record.ts +113 -0
  543. package/src/lifecycle/publish-resume.test.ts +168 -0
  544. package/src/lifecycle/publish-targets.test.ts +494 -0
  545. package/src/lifecycle/publish-targets.ts +100 -0
  546. package/src/lifecycle/release-cut-signed.test.ts +180 -0
  547. package/src/lifecycle/release-cut.test.ts +483 -0
  548. package/src/lifecycle/release-cut.ts +503 -0
  549. package/src/lifecycle/release-flag.test.ts +112 -0
  550. package/src/lifecycle/release-join.test.ts +68 -0
  551. package/src/lifecycle/release-join.ts +182 -0
  552. package/src/lifecycle/release-ledger.test.ts +14 -0
  553. package/src/lifecycle/release-ledger.ts +85 -17
  554. package/src/lifecycle/release-publish.test.ts +225 -0
  555. package/src/lifecycle/release-publish.ts +568 -0
  556. package/src/lifecycle/release-revocation.ts +147 -0
  557. package/src/lifecycle/release-store.ts +434 -0
  558. package/src/lifecycle/release-verify.test.ts +110 -0
  559. package/src/lifecycle/release-verify.ts +120 -0
  560. package/src/lifecycle/release-workstation.test.ts +204 -0
  561. package/src/lifecycle/release-workstation.ts +216 -0
  562. package/src/lifecycle/retention-growth.e2e.test.ts +279 -0
  563. package/src/lifecycle/retention-policy.ts +63 -0
  564. package/src/lifecycle/retention.test.ts +363 -0
  565. package/src/lifecycle/retention.ts +508 -0
  566. package/src/lifecycle/run-ledger.test.ts +10 -0
  567. package/src/lifecycle/run-ledger.ts +6 -0
  568. package/src/op/activities/change-coverage.ts +4 -1
  569. package/src/op/activities/source-release.ts +8 -3
  570. package/src/op/activities/source-rollback.ts +8 -4
  571. package/src/op/commit-run-gate-deploy-join.test.ts +117 -0
  572. package/src/op/gate-name.ts +13 -3
  573. package/src/op/gate-release.test.ts +126 -0
  574. package/src/op/gate-run-locator.test.ts +110 -0
  575. package/src/op/gate-run-locator.ts +35 -0
  576. package/src/op/gate.ts +88 -6
  577. package/src/op/local-executor.ts +207 -52
  578. package/src/op/op-waves-run.ts +4 -0
  579. package/src/op/run-events.test.ts +166 -0
  580. package/src/op/run-live.ts +1 -1
  581. package/src/op/runtime.ts +39 -0
  582. package/src/op/runtimes/local.test.ts +16 -0
  583. package/src/op/runtimes/local.ts +9 -0
  584. package/src/plan-summary.test.ts +20 -0
  585. package/src/plan-summary.ts +8 -1
  586. package/src/point-decision.ts +12 -2
  587. package/src/pr-loop.ts +25 -4
  588. package/src/pr-report-url.test.ts +131 -0
  589. package/src/pr-report-url.ts +209 -0
  590. package/src/provenance.ts +2 -2
  591. package/src/run-event-store.test.ts +144 -0
  592. package/src/run-event-store.ts +273 -0
  593. package/src/run-event-stream.test.ts +175 -0
  594. package/src/run-event-stream.ts +309 -0
  595. package/src/run-event.test.ts +277 -0
  596. package/src/run-event.ts +471 -0
  597. package/src/wave-loop-golden.test.ts +9 -0
  598. package/src/workspace/__fixtures__/flag-workspace.ts +132 -0
  599. package/src/workspace/__fixtures__/older-records/change-set-984534ea9.json +100 -0
  600. package/src/workspace/__fixtures__/older-records/older-records.json +326 -0
  601. package/src/workspace/__fixtures__/run-event-check.ts +58 -0
  602. package/src/workspace/ancestry-index.test.ts +93 -0
  603. package/src/workspace/change-set-show.schema.json +102 -0
  604. package/src/workspace/change-set-show.ts +72 -0
  605. package/src/workspace/change-set.schema.json +32 -1
  606. package/src/workspace/changes-cli.ts +10 -1
  607. package/src/workspace/changes.schema.json +135 -0
  608. package/src/workspace/changes.test.ts +1 -1
  609. package/src/workspace/changes.ts +84 -2
  610. package/src/workspace/check.schema.json +4 -2
  611. package/src/workspace/checks/records.ts +35 -1
  612. package/src/workspace/checks.ts +2 -1
  613. package/src/workspace/ci-green-cli.ts +75 -13
  614. package/src/workspace/ci-green-forge.ts +24 -4
  615. package/src/workspace/ci-green-runs.test.ts +242 -0
  616. package/src/workspace/ci-green-signed.test.ts +302 -0
  617. package/src/workspace/ci-green-workflow.test.ts +16 -0
  618. package/src/workspace/ci-green-workflow.ts +12 -0
  619. package/src/workspace/ci-green.test.ts +131 -2
  620. package/src/workspace/ci-green.ts +635 -42
  621. package/src/workspace/ci-last-green.schema.json +32 -2
  622. package/src/workspace/ci-list.schema.json +525 -0
  623. package/src/workspace/commit-links.test.ts +279 -0
  624. package/src/workspace/commit-links.ts +183 -0
  625. package/src/workspace/declaration.schema.json +76 -0
  626. package/src/workspace/declaration.test.ts +28 -0
  627. package/src/workspace/declaration.ts +60 -2
  628. package/src/workspace/declared-kinds.ts +40 -1
  629. package/src/workspace/delivery-metrics.schema.json +519 -0
  630. package/src/workspace/delivery-metrics.test.ts +236 -0
  631. package/src/workspace/delivery-metrics.ts +286 -0
  632. package/src/workspace/flags-read.ts +121 -0
  633. package/src/workspace/flags.test.ts +141 -0
  634. package/src/workspace/flags.ts +157 -0
  635. package/src/workspace/graph-cli.ts +1 -1
  636. package/src/workspace/identity-gate-rule.ts +91 -7
  637. package/src/workspace/identity.ts +14 -1
  638. package/src/workspace/intent-cli.ts +46 -5
  639. package/src/workspace/intent-trace.test.ts +173 -0
  640. package/src/workspace/intent-trace.ts +484 -0
  641. package/src/workspace/intent.schema.json +702 -6
  642. package/src/workspace/intent.ts +196 -26
  643. package/src/workspace/ls.schema.json +3 -1
  644. package/src/workspace/ls.ts +6 -0
  645. package/src/workspace/member-pipeline.test.ts +17 -0
  646. package/src/workspace/member-pipeline.ts +9 -0
  647. package/src/workspace/older-records.test.ts +412 -0
  648. package/src/workspace/overlap.test.ts +165 -0
  649. package/src/workspace/overlap.ts +340 -0
  650. package/src/workspace/promotion-order.ts +97 -0
  651. package/src/workspace/read-contract.e2e.test.ts +5 -1
  652. package/src/workspace/reason-codes.test.ts +7 -1
  653. package/src/workspace/reason-codes.ts +7 -1
  654. package/src/workspace/record-assets.test.ts +2 -1
  655. package/src/workspace/records-contract.e2e.test.ts +2 -1
  656. package/src/workspace/records.schema.json +21 -2
  657. package/src/workspace/records.ts +36 -2
  658. package/src/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  659. package/src/workspace/reference-kinds/flag/flag.schema.json +53 -0
  660. package/src/workspace/releases.schema.json +513 -0
  661. package/src/workspace/releases.test.ts +108 -0
  662. package/src/workspace/releases.ts +133 -0
  663. package/src/workspace/run-event.schema.json +295 -0
  664. package/src/workspace/status-contract.test.ts +81 -1
  665. package/src/workspace/status-gates.ts +64 -1
  666. package/src/workspace/status-mixed.test.ts +152 -0
  667. package/src/workspace/status-revoked.test.ts +153 -0
  668. package/src/workspace/status-stewards.ts +6 -0
  669. package/src/workspace/status.schema.json +268 -2
  670. package/src/workspace/status.ts +334 -4
  671. package/src/workspace/trust/ci-tag-statement.ts +151 -0
  672. package/src/workspace/trust/op-run-statement.ts +148 -0
  673. package/src/workspace/trust/rotation.ts +61 -14
  674. package/src/workspace/trust/seal.ts +10 -0
  675. package/src/workspace/trust/ssh-commit.ts +10 -9
  676. package/src/workspace/wip.ts +11 -2
  677. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +0 -14
  678. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +0 -16
  679. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +0 -8
  680. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +0 -15
  681. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +0 -10
@@ -0,0 +1,232 @@
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
+
16
+ import { mkdirSync, readdirSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
17
+ import { basename, dirname, join } from "node:path";
18
+ import { contentDigest } from "../content-digest";
19
+ import type { DriverComponent, DriverGate, DriverPhase, DriverStep } from "./driver";
20
+ import { TEMPLATE_FIELDS, templateRefs } from "./release-compile";
21
+ import type { Release, ReleaseTarget } from "../lifecycle/release-store";
22
+ import type { ReleaseRecord } from "../lifecycle/release-ledger";
23
+ import type { BuildArchiveManifest } from "./verbs/build-archive";
24
+
25
+ /** Where a promote under a release writes the recorded templates, relative to the member's directory. */
26
+ export const RELEASE_TEMPLATES_DIR = ".chant/release-templates";
27
+
28
+ /** A template ready to write: where, and its bytes. */
29
+ export interface PinnedTemplate {
30
+ /** Relative to the member's directory. */
31
+ path: string;
32
+ content: string;
33
+ }
34
+
35
+ /** The release's target for `env`, or an error naming the environments it has. */
36
+ export function targetFor(release: Release, env: string): { target: ReleaseTarget } | { error: string } {
37
+ const target = release.targets.find((t) => t.env === env);
38
+ if (target) return { target };
39
+ return {
40
+ error: `release ${release.releaseDigest} has no target for "${env}"; it was compiled for ${release.targets.map((t) => t.env).join(", ") || "no environment"}`,
41
+ };
42
+ }
43
+
44
+ /** Whether a release is of a project with no components (#4046): no artifact, and every template it records has `component: null`. */
45
+ export function isImplicitRelease(release: Release): boolean {
46
+ const templates = release.targets.flatMap((t) => t.templates);
47
+ return release.artifactDigests.length === 0 && templates.length > 0 && templates.every((t) => t.component === null);
48
+ }
49
+
50
+ function isGate(step: DriverStep | DriverGate | DriverPhase): step is DriverGate {
51
+ return (step as { kind?: unknown }).kind === "gate";
52
+ }
53
+
54
+ function isPhase(step: DriverStep | DriverGate | DriverPhase): step is DriverPhase {
55
+ return typeof (step as { phase?: unknown }).phase === "string" && Array.isArray((step as DriverPhase).steps);
56
+ }
57
+
58
+ /**
59
+ * Point every template `components` read at the target's recorded bytes.
60
+ * Returns the rewritten compositions and the files to write, or the reasons
61
+ * the promote is refused: a template the target does not record, one whose
62
+ * bytes are missing, or one whose bytes do not hash to the target's digest.
63
+ */
64
+ export async function pinReleaseTemplates(
65
+ components: readonly DriverComponent[],
66
+ release: Release,
67
+ target: ReleaseTarget,
68
+ readTemplate: (digest: string) => Promise<string | null>,
69
+ ): Promise<{ components: DriverComponent[]; files: PinnedTemplate[] } | { errors: string[] }> {
70
+ const errors: string[] = [];
71
+ const files: PinnedTemplate[] = [];
72
+ const out: DriverComponent[] = [];
73
+ for (const component of components) {
74
+ const replace = new Map<string, string>();
75
+ for (const ref of templateRefs(component)) {
76
+ if (replace.has(ref.value)) continue;
77
+ const recorded = target.templates.find((t) => t.component === component.name && t.path === ref.path);
78
+ if (!recorded) {
79
+ errors.push(
80
+ `component "${component.name}" reads ${ref.field} "${ref.value}", which release ${release.releaseDigest} does not record for "${target.env}"; ` +
81
+ `this checkout's deploy is not the one the release was compiled from (commit ${release.commit.slice(0, 12)})`,
82
+ );
83
+ continue;
84
+ }
85
+ const content = await readTemplate(recorded.digest);
86
+ if (content === null) {
87
+ 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`);
88
+ continue;
89
+ }
90
+ const got = contentDigest(content);
91
+ if (got !== recorded.digest) {
92
+ errors.push(
93
+ `component "${component.name}": template "${ref.path}" hashes to ${got}, but the release's target for "${target.env}" records ${recorded.digest}; refusing to deploy it`,
94
+ );
95
+ continue;
96
+ }
97
+ const path = join(RELEASE_TEMPLATES_DIR, recorded.digest.replace(/:/g, "_"), basename(ref.path));
98
+ files.push({ path, content });
99
+ replace.set(ref.value, path);
100
+ }
101
+ const rewrite = (phase: DriverPhase): DriverPhase => ({
102
+ ...phase,
103
+ steps: phase.steps.map((step) => {
104
+ if (isPhase(step)) return rewrite(step);
105
+ if (isGate(step)) return step;
106
+ const next: DriverStep = { ...step };
107
+ for (const field of TEMPLATE_FIELDS) {
108
+ const v = next[field];
109
+ if (typeof v === "string" && replace.has(v)) next[field] = replace.get(v);
110
+ else if (Array.isArray(v)) next[field] = v.map((x) => (typeof x === "string" && replace.has(x) ? replace.get(x) : x));
111
+ }
112
+ return next;
113
+ }),
114
+ });
115
+ out.push({ ...component, deploy: component.deploy.map(rewrite) });
116
+ }
117
+ return errors.length > 0 ? { errors } : { components: out, files };
118
+ }
119
+
120
+ /**
121
+ * The files a release's target records, read back by digest and checked, for
122
+ * `chant release export` (#4046). A project with no components has no deploy
123
+ * step for a promote to point at the recorded bytes, so its deploy (an Op such
124
+ * as `chant run deploy`, or a CI job) reads the files this writes instead of
125
+ * building them again. Each path is the one the build wrote, relative to the
126
+ * member's directory; a template whose bytes are missing or don't hash to the
127
+ * target's digest is refused, as {@link pinReleaseTemplates} refuses one.
128
+ */
129
+ export async function targetFiles(
130
+ release: Release,
131
+ target: ReleaseTarget,
132
+ readTemplate: (digest: string) => Promise<string | null>,
133
+ ): Promise<{ files: PinnedTemplate[] } | { errors: string[] }> {
134
+ const errors: string[] = [];
135
+ const files: PinnedTemplate[] = [];
136
+ for (const t of target.templates) {
137
+ const who = t.component === null ? "" : `component "${t.component}": `;
138
+ if (t.path.startsWith("/") || t.path.split("/").includes("..")) {
139
+ errors.push(`${who}template "${t.path}" is not a path inside the member's directory; refusing to write it`);
140
+ continue;
141
+ }
142
+ const content = await readTemplate(t.digest);
143
+ if (content === null) {
144
+ errors.push(`${who}the bytes of template "${t.path}" (${t.digest}) are not on the chant/lifecycle branch; fetch it and try again`);
145
+ continue;
146
+ }
147
+ const got = contentDigest(content);
148
+ if (got !== t.digest) {
149
+ errors.push(`${who}template "${t.path}" hashes to ${got}, but release ${release.releaseDigest} records ${t.digest} for "${target.env}"; refusing to write it`);
150
+ continue;
151
+ }
152
+ const same = files.find((f) => f.path === t.path);
153
+ if (same) {
154
+ if (same.content !== content) errors.push(`two components record different bytes at "${t.path}" for "${target.env}", so they can't both be written there`);
155
+ continue;
156
+ }
157
+ files.push({ path: t.path, content });
158
+ }
159
+ return errors.length > 0 ? { errors } : { files };
160
+ }
161
+
162
+ /** Write the pinned templates under `dir`, the member's directory. */
163
+ export function writePinnedTemplates(dir: string, files: readonly PinnedTemplate[]): void {
164
+ for (const f of files) {
165
+ const full = join(dir, f.path);
166
+ mkdirSync(dirname(full), { recursive: true });
167
+ writeFileSync(full, f.content);
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Remove the templates {@link writePinnedTemplates} wrote once the promote is
173
+ * done, and {@link RELEASE_TEMPLATES_DIR} with them when nothing else is in
174
+ * it, so a promote leaves the checkout as it found it. A re-run writes them
175
+ * again from the release.
176
+ */
177
+ export function removePinnedTemplates(dir: string, files: readonly PinnedTemplate[]): void {
178
+ for (const f of files) rmSync(dirname(join(dir, f.path)), { recursive: true, force: true });
179
+ const root = join(dir, RELEASE_TEMPLATES_DIR);
180
+ try {
181
+ if (readdirSync(root).length === 0) rmdirSync(root);
182
+ } catch {
183
+ // Already gone, or not ours to remove.
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Whether the artifact a promote deploys under a release is one the release
189
+ * built (#4045, the rule #4026 left open). The release records build digests
190
+ * (`artifactDigests`, the digest the archive step returned), and a deploy
191
+ * record carries the publish digest, which is another value for an image, so
192
+ * the two are compared through the build manifest the source deploy record
193
+ * names (`manifestDigest`), whose entries carry build digests at the same
194
+ * archive paths:
195
+ *
196
+ * - a source record that names this release in `releaseDigest` matches;
197
+ * - else, each of the release's artifacts for the component must be in that
198
+ * manifest at its path with the release's digest, and one that differs is
199
+ * a mismatch;
200
+ * - a record with no `manifestDigest`, a manifest that isn't stored, or an
201
+ * artifact path the manifest doesn't hold can't be compared.
202
+ *
203
+ * A mismatch is a warning, not a refusal. The environment promoted from was
204
+ * deployed by its own `run --components`, which builds again, and an image
205
+ * build is not reproducible, so its digest differs from the cut's for the
206
+ * same commit. Refusing would refuse every image promote until a deploy can
207
+ * run the release's own artifacts (#4043).
208
+ */
209
+ export async function releaseArtifactMismatches(
210
+ release: Release,
211
+ sources: ReadonlyArray<{ component: string; source: ReleaseRecord }>,
212
+ readManifest: (manifestDigest: string) => Promise<BuildArchiveManifest | null>,
213
+ ): Promise<string[]> {
214
+ const out: string[] = [];
215
+ for (const { component, source } of sources) {
216
+ if (source.releaseDigest === release.releaseDigest) continue;
217
+ const artifacts = release.artifactDigests.filter((a) => a.component === component);
218
+ if (artifacts.length === 0 || source.manifestDigest === undefined) continue;
219
+ const manifest = await readManifest(source.manifestDigest);
220
+ if (!manifest) continue;
221
+ for (const a of artifacts) {
222
+ const entry = manifest.contents.find((e) => e.path === a.path && e.kind === a.kind);
223
+ if (entry && entry.digest !== a.digest) {
224
+ out.push(
225
+ `${component}: the ${source.env} deploy being promoted was built with ${a.path} at ${entry.digest}, ` +
226
+ `but release ${release.releaseDigest} built it at ${a.digest}, so the artifact deployed is not the release's own`,
227
+ );
228
+ }
229
+ }
230
+ }
231
+ return out;
232
+ }
@@ -90,6 +90,13 @@ export interface RunDoneEvent {
90
90
  status: RunProgressStatus;
91
91
  }
92
92
 
93
+ /**
94
+ * @deprecated Read `RunEvent` (`../run-event.ts`, exported from
95
+ * `@intentius/chant`) instead: one contract for Op, component and pipeline
96
+ * runs, with the run id, commit and runtime on every event (#4019).
97
+ * `runEventOfProgress` maps each of these onto it. `--progress-json` keeps
98
+ * printing this shape until #4041 moves it to the run-event stream.
99
+ */
93
100
  export type RunProgressEvent =
94
101
  | RunStartEvent
95
102
  | WaveStartEvent
@@ -19,7 +19,7 @@
19
19
  * `@<component>.publish.*`) resolves.
20
20
  */
21
21
 
22
- import { resolveStepInput, type DriverComponent, type DriverPhase, type DriverStep } from "./driver";
22
+ import { resolveStepInput, unresolvedWiringSources, type DriverComponent, type DriverPhase, type DriverStep } from "./driver";
23
23
  import { componentPlanDigest } from "./gate-plan";
24
24
  import type { CapabilityRegistry, DeployContext } from "./capability";
25
25
  import type { WaveMember } from "../gated-waves";
@@ -44,7 +44,7 @@ function emptyPart(member: WaveMember): ChangeSetPart {
44
44
  }
45
45
 
46
46
  /** Every capability step in a composition, nested phases included, gates left out. */
47
- function capabilitySteps(phases: readonly DriverPhase[]): DriverStep[] {
47
+ export function capabilitySteps(phases: readonly DriverPhase[]): DriverStep[] {
48
48
  const out: DriverStep[] = [];
49
49
  const walk = (steps: DriverPhase["steps"]): void => {
50
50
  for (const step of steps) {
@@ -60,6 +60,19 @@ function capabilitySteps(phases: readonly DriverPhase[]): DriverStep[] {
60
60
  return out;
61
61
  }
62
62
 
63
+ /**
64
+ * The context a step is planned with: `ctx`, plus the components whose
65
+ * outputs the step reads and could not read yet (`unresolvedInputs`, #4084).
66
+ */
67
+ export function planContext(
68
+ ctx: DeployContext,
69
+ stepInput: Record<string, unknown>,
70
+ componentOutputs: Record<string, Record<string, unknown>>,
71
+ ): DeployContext {
72
+ const unresolved = unresolvedWiringSources(stepInput, componentOutputs);
73
+ return unresolved.length > 0 ? { ...ctx, unresolvedInputs: unresolved } : ctx;
74
+ }
75
+
63
76
  /** Plan one component against the outputs earlier waves produced. Never throws: a failure comes back as `error`. */
64
77
  export async function planWaveComponent(
65
78
  component: DriverComponent,
@@ -76,7 +89,7 @@ export async function planWaveComponent(
76
89
  if (!capability.plan) continue;
77
90
  const { kind: _kind, ...rest } = step;
78
91
  const input = resolveStepInput(rest, {}, componentOutputs);
79
- const planned = await capability.plan(ctx, input as never);
92
+ const planned = await capability.plan(planContext(ctx, rest, componentOutputs), input as never);
80
93
  const member = { member: planned.member, planDigest: planned.planDigest };
81
94
  members.push(member);
82
95
  parts.push(planned.changeSet ?? emptyPart(member));
package/src/config.ts CHANGED
@@ -12,6 +12,7 @@ import { findProjectConfig } from "./project-root";
12
12
  import { evaluateProjectConfig } from "./config-sandbox";
13
13
  import { lexiconNames, pathLexiconRoot, registerLexiconDeclarations, type LexiconDeclaration } from "./lexicon-module";
14
14
  import { decideConfigSchema, type DecideConfig } from "./op/decide-config";
15
+ import { PublishDeclarationSchema, type PublishDeclaration } from "./lifecycle/publish-declaration";
15
16
 
16
17
  /**
17
18
  * One project-declared environment (chant #1166). Historically always a bare
@@ -22,8 +23,13 @@ import { decideConfigSchema, type DecideConfig } from "./op/decide-config";
22
23
  * silently querying real AWS. See {@link environmentName}, {@link
23
24
  * environmentNames}, {@link environmentEndpoint} below, and
24
25
  * `./live-endpoint.ts`'s `applyLiveEndpoint`, the CLI-side consumer.
26
+ *
27
+ * The array's order is the member's promotion order (#4030, see
28
+ * `./workspace/promotion-order.ts`), and `canary: true` marks a step as the
29
+ * canary step of that order. The canary is declared and surfaced; chant does
30
+ * not yet act on it.
25
31
  */
26
- export type EnvironmentDeclaration = string | { name: string; endpoint?: string };
32
+ export type EnvironmentDeclaration = string | { name: string; endpoint?: string; canary?: boolean };
27
33
 
28
34
  /**
29
35
  * `ownership.env`: a literal environment identity, or a reference to a
@@ -124,6 +130,7 @@ const EnvironmentEntrySchema = z.union([
124
130
  z.object({
125
131
  name: z.string().min(1),
126
132
  endpoint: z.string().min(1).optional(),
133
+ canary: z.boolean().optional(),
127
134
  }),
128
135
  ]);
129
136
 
@@ -163,6 +170,7 @@ export const ChantConfigSchema = z.object({
163
170
  ).optional(),
164
171
  release: z.object({
165
172
  autoRecord: z.boolean().optional(),
173
+ publish: z.array(PublishDeclarationSchema).optional(),
166
174
  }).optional(),
167
175
  // Strict: a misspelt key here would leave Ops on the local runtime with
168
176
  // nothing said (#2523).
@@ -376,6 +384,12 @@ export interface ChantConfig {
376
384
  release?: {
377
385
  /** Set false to disable auto-emitting a release record after a successful component deploy project-wide. The `--no-release-record` CLI flag overrides this per-invocation. */
378
386
  autoRecord?: boolean;
387
+ /**
388
+ * Where `chant release publish` publishes a cut release (#4047): npm
389
+ * packages, an image in an OCI registry, release assets on a forge. Run in
390
+ * the order given. See ./lifecycle/publish-declaration.ts.
391
+ */
392
+ publish?: PublishDeclaration[];
379
393
  };
380
394
 
381
395
  /** Defaults for `chant run` and its subcommands (#2523). */
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Build-time parameters from workspace flags (#4024): what a build for an
3
+ * environment resolves in a member with flags, and the precedence rule that a
4
+ * flag-backed parameter can't be overridden where the environment has a gate.
5
+ * On the fixture in `workspace/__fixtures__/flag-workspace.ts`, where member
6
+ * `shop`'s component declares a gate and member `blog`'s does not.
7
+ */
8
+
9
+ import { writeFileSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
12
+ import { buildCommand } from "./cli/commands/build";
13
+ import type { Serializer } from "./serializer";
14
+ import type { BuildParamsConfig } from "./build-params";
15
+ import { loadBuildParamFlags, resolveFlaggedBuildParams } from "./flag-params";
16
+ import { cleanScratch, scratchDir } from "./workspace/__fixtures__/contract-repo";
17
+ import { flagWorkspace } from "./workspace/__fixtures__/flag-workspace";
18
+
19
+ const SHOP: BuildParamsConfig = { newCheckout: { type: "boolean", default: false }, tier: { type: "string", default: "small" } };
20
+ const BLOG: BuildParamsConfig = { banner: { type: "boolean", default: false } };
21
+
22
+ let root: string;
23
+ beforeAll(() => {
24
+ root = flagWorkspace();
25
+ });
26
+ afterAll(cleanScratch);
27
+
28
+ const quiet = { echo: false } as const;
29
+
30
+ describe("loadBuildParamFlags", () => {
31
+ test("outside a workspace, and without an environment, there are no flags", async () => {
32
+ const plain = scratchDir("chant-flags-plain-");
33
+ expect(await loadBuildParamFlags(plain, "prod")).toEqual({ flags: undefined, errors: [] });
34
+ expect(await loadBuildParamFlags(join(root, "shop"), undefined)).toEqual({ flags: undefined, errors: [] });
35
+ });
36
+
37
+ test("in a member, each flag-backed parameter with the flag's value for the environment", async () => {
38
+ expect(await loadBuildParamFlags(join(root, "shop"), "dev")).toEqual({
39
+ flags: { env: "dev", byParam: { newCheckout: { flag: "new-checkout", value: true } } },
40
+ errors: [],
41
+ });
42
+ });
43
+
44
+ test("a flag kind that can't be read stops the build rather than building without its flags", async () => {
45
+ const dir = flagWorkspace({ "flags/flag.schema.json": "{ not json" });
46
+ const loaded = await loadBuildParamFlags(join(dir, "shop"), "prod");
47
+ expect(loaded.flags).toBeUndefined();
48
+ expect(loaded.errors[0]).toMatch(/the workspace's flag records can't be read/);
49
+ });
50
+ });
51
+
52
+ describe("resolveFlaggedBuildParams", () => {
53
+ test("records the flag as the parameter's source, per environment", async () => {
54
+ const prod = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, quiet, "prod");
55
+ expect(prod).toEqual({
56
+ success: true,
57
+ errors: [],
58
+ provenance: [
59
+ { name: "newCheckout", value: false, source: "flag:new-checkout" },
60
+ { name: "tier", value: "small", source: "default" },
61
+ ],
62
+ });
63
+ const dev = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, quiet, "dev");
64
+ expect(dev.provenance[0]).toEqual({ name: "newCheckout", value: true, source: "flag:new-checkout" });
65
+ // staging: the record gives no value, so the declared default applies.
66
+ expect((await resolveFlaggedBuildParams(join(root, "shop"), SHOP, quiet, "staging")).provenance[0]).toEqual({ name: "newCheckout", value: false, source: "default" });
67
+ });
68
+
69
+ test("--param can't override a flag in an environment with a gate: the build refuses", async () => {
70
+ const refused = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, { ...quiet, cli: { newCheckout: "true" } }, "prod");
71
+ expect(refused.success).toBe(false);
72
+ expect(refused.provenance).toEqual([]);
73
+ expect(refused.errors).toHaveLength(1);
74
+ expect(refused.errors[0]).toMatch(/build parameter "newCheckout" is backed by the flag "new-checkout", and "prod" has a gate, so --param can't set it/);
75
+ expect(refused.errors[0]).toMatch(/gates: prod-release/);
76
+ });
77
+
78
+ test("--params-file can't either, and a parameter no flag backs still can", async () => {
79
+ const file = join(scratchDir("chant-flags-file-"), "params.json");
80
+ writeFileSync(file, JSON.stringify({ newCheckout: true }));
81
+ const refused = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, { ...quiet, paramsFile: file }, "prod");
82
+ expect(refused.success).toBe(false);
83
+ expect(refused.errors[0]).toMatch(/so --params-file can't set it/);
84
+ const tier = await resolveFlaggedBuildParams(join(root, "shop"), SHOP, { ...quiet, cli: { tier: "large" } }, "prod");
85
+ expect(tier.success).toBe(true);
86
+ expect(tier.provenance).toContainEqual({ name: "tier", value: "large", source: "cli" });
87
+ });
88
+
89
+ test("where no component declares a gate, --param still overrides the flag", async () => {
90
+ const r = await resolveFlaggedBuildParams(join(root, "blog"), BLOG, { ...quiet, cli: { banner: "false" } }, "prod");
91
+ expect(r.success).toBe(true);
92
+ expect(r.provenance).toEqual([{ name: "banner", value: false, source: "cli" }]);
93
+ });
94
+
95
+ test("components that can't be read refuse an override, since the gate can't be ruled out", async () => {
96
+ const dir = flagWorkspace({ "shop/broken.component.ts": "export const = ;\n" });
97
+ const r = await resolveFlaggedBuildParams(join(dir, "shop"), SHOP, { ...quiet, cli: { newCheckout: "true" } }, "prod");
98
+ expect(r.success).toBe(false);
99
+ expect(r.errors[0]).toMatch(/whether "prod" has a gate can't be told/);
100
+ });
101
+ });
102
+
103
+ describe("chant build --env in a member with flags", () => {
104
+ const runtime = join(import.meta.dirname, "runtime");
105
+ const paramsModule = join(import.meta.dirname, "params");
106
+ const serializer: Serializer = {
107
+ name: "aws",
108
+ rulePrefix: "TEST",
109
+ serialize: (entities) => JSON.stringify([...entities.values()].map((e) => (e as unknown as { props: unknown }).props)),
110
+ };
111
+ const shopFiles = {
112
+ "shop/chant.config.ts": `export default { environments: ["dev", "staging", "prod"], buildParams: { newCheckout: { type: "boolean", default: false } } };\n`,
113
+ "shop/main.ts":
114
+ `import { createResource } from ${JSON.stringify(runtime)};\n` +
115
+ `import { params } from ${JSON.stringify(paramsModule)};\n` +
116
+ `const Bucket = createResource("Test::Bucket", "aws", { arn: "Arn" });\n` +
117
+ `export const bucket = new Bucket({ checkout: params.newCheckout ? "new" : "old" });\n`,
118
+ };
119
+
120
+ test("records the flag on BuildResult.buildParams and builds with its value", async () => {
121
+ const dir = flagWorkspace(shopFiles);
122
+ const spy = vi.spyOn(console, "error").mockImplementation(() => {});
123
+ try {
124
+ const result = await buildCommand({ path: join(dir, "shop"), format: "json", serializers: [serializer], env: "dev" });
125
+ expect(result.errors).toEqual([]);
126
+ expect(result.buildParams).toEqual([{ name: "newCheckout", value: true, source: "flag:new-checkout" }]);
127
+ expect(spy.mock.calls.map((c) => String(c[0])).some((l) => l.includes("1 build parameter resolved (1 from flags)"))).toBe(true);
128
+ } finally {
129
+ spy.mockRestore();
130
+ }
131
+ });
132
+
133
+ test("refuses --param for a flag-backed parameter in an environment with a gate", async () => {
134
+ const dir = flagWorkspace(shopFiles);
135
+ const spy = vi.spyOn(console, "error").mockImplementation(() => {});
136
+ try {
137
+ const result = await buildCommand({ path: join(dir, "shop"), format: "json", serializers: [serializer], env: "prod", params: { newCheckout: "true" } });
138
+ expect(result.success).toBe(false);
139
+ expect(result.errors.join("\n")).toMatch(/"newCheckout" is backed by the flag "new-checkout", and "prod" has a gate, so --param can't set it/);
140
+ } finally {
141
+ spy.mockRestore();
142
+ }
143
+ });
144
+ });
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Build-time parameters from workspace flags (#4024, decided in #4016).
3
+ *
4
+ * A member of a workspace may have flag records: records of a kind with a
5
+ * `flag` block, each naming the member, one of its declared build
6
+ * parameters and a value per environment (`workspace/flags.ts`). A build
7
+ * for an environment (`chant build --env <env>`, `chant run --components
8
+ * --env <env>`, and each environment a release cut compiles) reads them, and
9
+ * a flag-backed parameter takes the flag's value for that environment,
10
+ * recorded as `source: "flag:<name>"` on `BuildResult.buildParams` and on the
11
+ * release target's `params`.
12
+ *
13
+ * The precedence rule: where the environment has a gate, `--param`,
14
+ * `--params-file` and the parameter's env var can't set a flag-backed
15
+ * parameter, and the build refuses. An environment has a gate when a
16
+ * component enabled in it declares a gate step, the same test `components
17
+ * promote --release` uses to bind a release gate. The test runs only when one
18
+ * of those sources did set a flag-backed parameter, since it imports the
19
+ * member's components; a project with no components has no gate.
20
+ *
21
+ * Level 0 pays one upward `existsSync` walk here and nothing more. Workspace
22
+ * code is imported only once a declaration is found (#2525 rule 5, pinned by
23
+ * #2526's goldens).
24
+ */
25
+
26
+ import { findWorkspaceRoot } from "./project-root";
27
+ import { flagGateRefusal, type BuildParamFlags, type BuildParamsConfig } from "./build-params";
28
+ import type { BuildParamProvenance } from "./provenance";
29
+ import { echoBuildParams, resolveCliBuildParams, type CliBuildParamsArgs, type CliBuildParamsResolution } from "./cli/build-params-cli";
30
+ import { formatError } from "./cli/format";
31
+
32
+ /** The flags backing parameters of the member at `projectDir` in `env`, or why they can't be read. `flags` is undefined outside a workspace, without an environment, or when no flag names the member. */
33
+ export async function loadBuildParamFlags(projectDir: string, env: string | undefined): Promise<{ flags: BuildParamFlags | undefined; errors: string[] }> {
34
+ if (!env) return { flags: undefined, errors: [] };
35
+ const found = findWorkspaceRoot(projectDir);
36
+ if (!found) return { flags: undefined, errors: [] };
37
+ const { memberFlagBindings } = await import("./workspace/flags-read");
38
+ try {
39
+ const bindings = await memberFlagBindings(found.dir, projectDir, env);
40
+ if (!bindings) return { flags: undefined, errors: [] };
41
+ if (bindings.errors.length > 0) return { flags: undefined, errors: bindings.errors };
42
+ if (Object.keys(bindings.byParam).length === 0) return { flags: undefined, errors: [] };
43
+ return { flags: { env, byParam: bindings.byParam }, errors: [] };
44
+ } catch (err) {
45
+ const { WorkspaceReadError } = await import("./workspace/declaration");
46
+ const { RecordReadError } = await import("./workspace/records");
47
+ if (err instanceof WorkspaceReadError || err instanceof RecordReadError) {
48
+ return { flags: undefined, errors: [`the workspace's flag records can't be read, so this build can't tell which parameters they set: ${err.message}`] };
49
+ }
50
+ throw err;
51
+ }
52
+ }
53
+
54
+ /** The parameters a flag backs that `--param`, `--params-file` or an env var set instead. */
55
+ export function overriddenFlagParams(provenance: readonly BuildParamProvenance[], flags: BuildParamFlags | undefined): BuildParamProvenance[] {
56
+ if (!flags) return [];
57
+ return provenance.filter((p) => flags.byParam[p.name] !== undefined && (p.source === "cli" || p.source === "params-file" || p.source === "env"));
58
+ }
59
+
60
+ /**
61
+ * The gates the member's components declare in the environment the process
62
+ * builds for (`CHANT_ENV`), with the parameters as resolved, or why the
63
+ * components can't be read. Only components enabled under those parameters
64
+ * count.
65
+ */
66
+ export async function environmentGates(projectDir: string, provenance: BuildParamProvenance[]): Promise<{ gates: string[] } | { error: string }> {
67
+ const { discoverComponents } = await import("./components/discover");
68
+ const { withoutDisabled } = await import("./components/cli-support");
69
+ const { gateNamesOf } = await import("./components/release-gate");
70
+ try {
71
+ const discovered = await discoverComponents(projectDir, { buildParams: provenance });
72
+ if (discovered.errors.length > 0) return { error: discovered.errors.map((e) => e.message).join("; ") };
73
+ const all = [...discovered.components.values()].map((d) => d.component);
74
+ const plain = all.map((c) => ({ name: c.name, dependsOn: c.dependsOn, deploy: c.deploy as never }));
75
+ return { gates: gateNamesOf(withoutDisabled(all, plain)) };
76
+ } catch (err) {
77
+ return { error: err instanceof Error ? err.message : String(err) };
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Resolve the build parameters of the project at `projectDir` for `env`,
83
+ * with the workspace's flags, as `resolveCliBuildParams` does without them.
84
+ * Refuses when a flag record can't be read, and when `--param`,
85
+ * `--params-file` or an env var sets a flag-backed parameter in an
86
+ * environment with a gate. Prints the summary line only on success.
87
+ */
88
+ export async function resolveFlaggedBuildParams(
89
+ projectDir: string,
90
+ buildParamsConfig: BuildParamsConfig | undefined,
91
+ args: CliBuildParamsArgs,
92
+ env: string | undefined,
93
+ ): Promise<CliBuildParamsResolution> {
94
+ const loaded = await loadBuildParamFlags(projectDir, env);
95
+ if (loaded.errors.length > 0) {
96
+ return { success: false, provenance: [], errors: loaded.errors.map((message) => formatError({ message })) };
97
+ }
98
+ const { flags } = loaded;
99
+ const resolution = resolveCliBuildParams(buildParamsConfig, { ...args, ...(flags ? { flags } : {}), echo: false });
100
+ if (!resolution.success || !flags) {
101
+ if (resolution.success && args.echo !== false) echoBuildParams(resolution.provenance, args.verbose);
102
+ return resolution;
103
+ }
104
+ const overridden = overriddenFlagParams(resolution.provenance, flags);
105
+ if (overridden.length > 0) {
106
+ const found = await environmentGates(projectDir, resolution.provenance);
107
+ if ("error" in found) {
108
+ return {
109
+ success: false,
110
+ provenance: [],
111
+ errors: [
112
+ formatError({
113
+ message:
114
+ `${overridden.map((p) => `"${p.name}"`).join(", ")} ${overridden.length === 1 ? "is" : "are"} backed by a flag and set by ${[...new Set(overridden.map((p) => p.source))].join(", ")}, ` +
115
+ `and whether "${flags.env}" has a gate can't be told, because its components can't be read: ${found.error}`,
116
+ }),
117
+ ],
118
+ };
119
+ }
120
+ if (found.gates.length > 0) {
121
+ const around = (p: BuildParamProvenance): string =>
122
+ p.source === "cli" ? "--param" : p.source === "params-file" ? "--params-file" : `the env var ${buildParamsConfig?.[p.name]?.env ?? "(unknown)"}`;
123
+ return {
124
+ success: false,
125
+ provenance: [],
126
+ errors: overridden.map((p) =>
127
+ formatError({ message: `${flagGateRefusal(p.name, flags.byParam[p.name].flag, flags.env, around(p))} (gates: ${found.gates.join(", ")})` }),
128
+ ),
129
+ };
130
+ }
131
+ }
132
+ if (args.echo !== false) echoBuildParams(resolution.provenance, args.verbose);
133
+ return resolution;
134
+ }
package/src/index.ts CHANGED
@@ -153,6 +153,8 @@ export type { SymbolDeclaration, SymbolResolver } from "./workspace/symbols";
153
153
  export * from "./lsp/lexicon-providers";
154
154
  export * from "./mcp/types";
155
155
  export * from "./lifecycle/index";
156
+ // The run-event contract (#4019): the types and the one writer of a run's stream.
157
+ export * from "./run-event";
156
158
  // Op builders — use explicit exports to avoid collision with the core `build` function
157
159
  export { Op, phase, activity, gate, kubectlApply, helmInstall, waitForStack,
158
160
  gitlabPipeline, lifecycleSnapshot, shell, teardown, OpResource } from "./op/index";