@intentius/chant 0.124.28 → 0.124.30

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 (449) hide show
  1. package/dist/build-params.d.ts +34 -1
  2. package/dist/build-params.d.ts.map +1 -1
  3. package/dist/build-params.js +31 -1
  4. package/dist/change-set-graph.d.ts +8 -1
  5. package/dist/change-set-graph.d.ts.map +1 -1
  6. package/dist/change-set-graph.js +4 -2
  7. package/dist/change-set.d.ts +10 -0
  8. package/dist/change-set.d.ts.map +1 -1
  9. package/dist/change-set.js +4 -3
  10. package/dist/cli/build-params-cli.d.ts +7 -1
  11. package/dist/cli/build-params-cli.d.ts.map +1 -1
  12. package/dist/cli/build-params-cli.js +17 -8
  13. package/dist/cli/commands/build.d.ts.map +1 -1
  14. package/dist/cli/commands/build.js +6 -3
  15. package/dist/cli/handlers/approve.d.ts.map +1 -1
  16. package/dist/cli/handlers/approve.js +45 -0
  17. package/dist/cli/handlers/build.d.ts.map +1 -1
  18. package/dist/cli/handlers/build.js +18 -4
  19. package/dist/cli/handlers/fan-out.d.ts +9 -0
  20. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  21. package/dist/cli/handlers/fan-out.js +67 -8
  22. package/dist/cli/handlers/lifecycle-gc.d.ts +19 -0
  23. package/dist/cli/handlers/lifecycle-gc.d.ts.map +1 -0
  24. package/dist/cli/handlers/lifecycle-gc.js +143 -0
  25. package/dist/cli/handlers/pr.d.ts +11 -3
  26. package/dist/cli/handlers/pr.d.ts.map +1 -1
  27. package/dist/cli/handlers/pr.js +134 -26
  28. package/dist/cli/handlers/promote.d.ts +7 -0
  29. package/dist/cli/handlers/promote.d.ts.map +1 -1
  30. package/dist/cli/handlers/promote.js +210 -33
  31. package/dist/cli/handlers/release.d.ts +62 -5
  32. package/dist/cli/handlers/release.d.ts.map +1 -1
  33. package/dist/cli/handlers/release.js +414 -28
  34. package/dist/cli/handlers/run.d.ts +11 -1
  35. package/dist/cli/handlers/run.d.ts.map +1 -1
  36. package/dist/cli/handlers/run.js +67 -6
  37. package/dist/cli/main.d.ts.map +1 -1
  38. package/dist/cli/main.js +91 -10
  39. package/dist/cli/parse-args.d.ts.map +1 -1
  40. package/dist/cli/parse-args.js +73 -2
  41. package/dist/cli/registry.d.ts +32 -4
  42. package/dist/cli/registry.d.ts.map +1 -1
  43. package/dist/cli/run-events.d.ts +3 -2
  44. package/dist/cli/run-events.d.ts.map +1 -1
  45. package/dist/cli/run-events.js +5 -3
  46. package/dist/components/auto-release.d.ts +2 -0
  47. package/dist/components/auto-release.d.ts.map +1 -1
  48. package/dist/components/auto-release.js +1 -0
  49. package/dist/components/capability.d.ts +9 -0
  50. package/dist/components/capability.d.ts.map +1 -1
  51. package/dist/components/driver.d.ts +8 -0
  52. package/dist/components/driver.d.ts.map +1 -1
  53. package/dist/components/driver.js +35 -0
  54. package/dist/components/fan-out-inputs.d.ts +69 -0
  55. package/dist/components/fan-out-inputs.d.ts.map +1 -0
  56. package/dist/components/fan-out-inputs.js +169 -0
  57. package/dist/components/fan-out-record.d.ts +13 -0
  58. package/dist/components/fan-out-record.d.ts.map +1 -1
  59. package/dist/components/fan-out-record.js +16 -0
  60. package/dist/components/fan-out-run.d.ts.map +1 -1
  61. package/dist/components/fan-out-run.js +50 -0
  62. package/dist/components/fan-out.d.ts +4 -0
  63. package/dist/components/fan-out.d.ts.map +1 -1
  64. package/dist/components/pr-pipeline.d.ts +49 -0
  65. package/dist/components/pr-pipeline.d.ts.map +1 -1
  66. package/dist/components/pr-pipeline.js +38 -4
  67. package/dist/components/pr-run.d.ts +20 -2
  68. package/dist/components/pr-run.d.ts.map +1 -1
  69. package/dist/components/pr-run.js +26 -13
  70. package/dist/components/promote.d.ts +23 -0
  71. package/dist/components/promote.d.ts.map +1 -1
  72. package/dist/components/promote.js +60 -2
  73. package/dist/components/release-compile.d.ts +9 -0
  74. package/dist/components/release-compile.d.ts.map +1 -1
  75. package/dist/components/release-compile.js +9 -3
  76. package/dist/components/release-gate.d.ts +11 -1
  77. package/dist/components/release-gate.d.ts.map +1 -1
  78. package/dist/components/release-gate.js +10 -4
  79. package/dist/components/wave-plan.d.ts +16 -0
  80. package/dist/components/wave-plan.d.ts.map +1 -1
  81. package/dist/components/wave-plan.js +36 -2
  82. package/dist/config.d.ts +38 -0
  83. package/dist/config.d.ts.map +1 -1
  84. package/dist/config.js +2 -0
  85. package/dist/flag-params.d.ts +54 -0
  86. package/dist/flag-params.d.ts.map +1 -0
  87. package/dist/flag-params.js +130 -0
  88. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts +120 -0
  89. package/dist/lifecycle/__fixtures__/publish-fakes.d.ts.map +1 -0
  90. package/dist/lifecycle/__fixtures__/publish-fakes.js +304 -0
  91. package/dist/lifecycle/change-set-store.d.ts +2 -1
  92. package/dist/lifecycle/change-set-store.d.ts.map +1 -1
  93. package/dist/lifecycle/change-set-store.js +2 -1
  94. package/dist/lifecycle/delivery-metrics.d.ts +139 -0
  95. package/dist/lifecycle/delivery-metrics.d.ts.map +1 -0
  96. package/dist/lifecycle/delivery-metrics.js +145 -0
  97. package/dist/lifecycle/deploy-outcome.d.ts +81 -0
  98. package/dist/lifecycle/deploy-outcome.d.ts.map +1 -0
  99. package/dist/lifecycle/deploy-outcome.js +101 -0
  100. package/dist/lifecycle/gate-change-set.d.ts +10 -1
  101. package/dist/lifecycle/gate-change-set.d.ts.map +1 -1
  102. package/dist/lifecycle/gate-change-set.js +35 -3
  103. package/dist/lifecycle/gate-ledger.d.ts +2 -3
  104. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  105. package/dist/lifecycle/git.d.ts +30 -1
  106. package/dist/lifecycle/git.d.ts.map +1 -1
  107. package/dist/lifecycle/git.js +31 -5
  108. package/dist/lifecycle/index.d.ts +4 -0
  109. package/dist/lifecycle/index.d.ts.map +1 -1
  110. package/dist/lifecycle/index.js +4 -0
  111. package/dist/lifecycle/mixed-environment.d.ts +95 -0
  112. package/dist/lifecycle/mixed-environment.d.ts.map +1 -0
  113. package/dist/lifecycle/mixed-environment.js +154 -0
  114. package/dist/lifecycle/publish-attachments.d.ts +79 -0
  115. package/dist/lifecycle/publish-attachments.d.ts.map +1 -0
  116. package/dist/lifecycle/publish-attachments.js +179 -0
  117. package/dist/lifecycle/publish-credentials.d.ts +37 -0
  118. package/dist/lifecycle/publish-credentials.d.ts.map +1 -0
  119. package/dist/lifecycle/publish-credentials.js +69 -0
  120. package/dist/lifecycle/publish-declaration.d.ts +97 -0
  121. package/dist/lifecycle/publish-declaration.d.ts.map +1 -0
  122. package/dist/lifecycle/publish-declaration.js +83 -0
  123. package/dist/lifecycle/publish-forge.d.ts +53 -0
  124. package/dist/lifecycle/publish-forge.d.ts.map +1 -0
  125. package/dist/lifecycle/publish-forge.js +298 -0
  126. package/dist/lifecycle/publish-npm.d.ts +61 -0
  127. package/dist/lifecycle/publish-npm.d.ts.map +1 -0
  128. package/dist/lifecycle/publish-npm.js +242 -0
  129. package/dist/lifecycle/publish-oci.d.ts +64 -0
  130. package/dist/lifecycle/publish-oci.d.ts.map +1 -0
  131. package/dist/lifecycle/publish-oci.js +383 -0
  132. package/dist/lifecycle/publish-record.d.ts +66 -0
  133. package/dist/lifecycle/publish-record.d.ts.map +1 -0
  134. package/dist/lifecycle/publish-record.js +84 -0
  135. package/dist/lifecycle/publish-targets.d.ts +45 -0
  136. package/dist/lifecycle/publish-targets.d.ts.map +1 -0
  137. package/dist/lifecycle/publish-targets.js +85 -0
  138. package/dist/lifecycle/release-cut.d.ts +48 -1
  139. package/dist/lifecycle/release-cut.d.ts.map +1 -1
  140. package/dist/lifecycle/release-cut.js +116 -23
  141. package/dist/lifecycle/release-join.d.ts +95 -0
  142. package/dist/lifecycle/release-join.d.ts.map +1 -0
  143. package/dist/lifecycle/release-join.js +139 -0
  144. package/dist/lifecycle/release-ledger.d.ts +8 -3
  145. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  146. package/dist/lifecycle/release-ledger.js +2 -0
  147. package/dist/lifecycle/release-publish.d.ts +312 -0
  148. package/dist/lifecycle/release-publish.d.ts.map +1 -0
  149. package/dist/lifecycle/release-publish.js +335 -0
  150. package/dist/lifecycle/release-revocation.d.ts +80 -0
  151. package/dist/lifecycle/release-revocation.d.ts.map +1 -0
  152. package/dist/lifecycle/release-revocation.js +123 -0
  153. package/dist/lifecycle/release-store.d.ts +12 -2
  154. package/dist/lifecycle/release-store.d.ts.map +1 -1
  155. package/dist/lifecycle/release-store.js +4 -2
  156. package/dist/lifecycle/release-verify.d.ts +61 -0
  157. package/dist/lifecycle/release-verify.d.ts.map +1 -0
  158. package/dist/lifecycle/release-verify.js +92 -0
  159. package/dist/lifecycle/release-workstation.d.ts +91 -0
  160. package/dist/lifecycle/release-workstation.d.ts.map +1 -0
  161. package/dist/lifecycle/release-workstation.js +180 -0
  162. package/dist/lifecycle/retention-policy.d.ts +45 -0
  163. package/dist/lifecycle/retention-policy.d.ts.map +1 -0
  164. package/dist/lifecycle/retention-policy.js +43 -0
  165. package/dist/lifecycle/retention.d.ts +185 -0
  166. package/dist/lifecycle/retention.d.ts.map +1 -0
  167. package/dist/lifecycle/retention.js +400 -0
  168. package/dist/lifecycle/run-ledger.d.ts +1 -1
  169. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  170. package/dist/lifecycle/run-ledger.js +9 -0
  171. package/dist/op/activities/activity-contracts.d.ts +1 -0
  172. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  173. package/dist/op/activities/activity-contracts.js +1 -0
  174. package/dist/op/activities/shell.d.ts +6 -0
  175. package/dist/op/activities/shell.d.ts.map +1 -1
  176. package/dist/op/activities/shell.js +1 -1
  177. package/dist/op/local-executor.d.ts +23 -1
  178. package/dist/op/local-executor.d.ts.map +1 -1
  179. package/dist/op/local-executor.js +9 -3
  180. package/dist/op/runtime.d.ts +27 -0
  181. package/dist/op/runtime.d.ts.map +1 -1
  182. package/dist/op/runtime.js +20 -0
  183. package/dist/plan-summary.d.ts.map +1 -1
  184. package/dist/plan-summary.js +8 -2
  185. package/dist/pr-forge.d.ts +23 -0
  186. package/dist/pr-forge.d.ts.map +1 -1
  187. package/dist/pr-forge.js +44 -0
  188. package/dist/pr-loop.d.ts +17 -0
  189. package/dist/pr-loop.d.ts.map +1 -1
  190. package/dist/pr-loop.js +30 -4
  191. package/dist/pr-report-url.d.ts +82 -0
  192. package/dist/pr-report-url.d.ts.map +1 -0
  193. package/dist/pr-report-url.js +174 -0
  194. package/dist/provenance.d.ts +2 -2
  195. package/dist/provenance.d.ts.map +1 -1
  196. package/dist/run-event-store.d.ts +29 -2
  197. package/dist/run-event-store.d.ts.map +1 -1
  198. package/dist/run-event-store.js +50 -3
  199. package/dist/run-event-stream.d.ts +4 -3
  200. package/dist/run-event-stream.d.ts.map +1 -1
  201. package/dist/run-event-stream.js +7 -3
  202. package/dist/run-event.d.ts +34 -1
  203. package/dist/run-event.d.ts.map +1 -1
  204. package/dist/run-event.js +4 -0
  205. package/dist/wave-runtime.mjs +260 -229
  206. package/dist/workspace/__fixtures__/flag-workspace.d.ts +31 -0
  207. package/dist/workspace/__fixtures__/flag-workspace.d.ts.map +1 -0
  208. package/dist/workspace/__fixtures__/flag-workspace.js +114 -0
  209. package/dist/workspace/change-set.schema.json +5 -1
  210. package/dist/workspace/check.schema.json +4 -2
  211. package/dist/workspace/checks/records.d.ts +9 -1
  212. package/dist/workspace/checks/records.d.ts.map +1 -1
  213. package/dist/workspace/checks/records.js +35 -1
  214. package/dist/workspace/checks.d.ts +1 -0
  215. package/dist/workspace/checks.d.ts.map +1 -1
  216. package/dist/workspace/checks.js +2 -1
  217. package/dist/workspace/ci-green-forge.d.ts +2 -0
  218. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  219. package/dist/workspace/ci-green.d.ts +10 -0
  220. package/dist/workspace/ci-green.d.ts.map +1 -1
  221. package/dist/workspace/ci-green.js +14 -5
  222. package/dist/workspace/ci-run.d.ts +222 -0
  223. package/dist/workspace/ci-run.d.ts.map +1 -0
  224. package/dist/workspace/ci-run.js +464 -0
  225. package/dist/workspace/ci-serve.d.ts +214 -0
  226. package/dist/workspace/ci-serve.d.ts.map +1 -0
  227. package/dist/workspace/ci-serve.js +412 -0
  228. package/dist/workspace/declaration.d.ts +16 -0
  229. package/dist/workspace/declaration.d.ts.map +1 -1
  230. package/dist/workspace/declaration.js +26 -0
  231. package/dist/workspace/declaration.schema.json +64 -0
  232. package/dist/workspace/declared-kinds.d.ts +16 -0
  233. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  234. package/dist/workspace/declared-kinds.js +25 -0
  235. package/dist/workspace/delivery-metrics.d.ts +91 -0
  236. package/dist/workspace/delivery-metrics.d.ts.map +1 -0
  237. package/dist/workspace/delivery-metrics.js +217 -0
  238. package/dist/workspace/delivery-metrics.schema.json +519 -0
  239. package/dist/workspace/flags-read.d.ts +37 -0
  240. package/dist/workspace/flags-read.d.ts.map +1 -0
  241. package/dist/workspace/flags-read.js +103 -0
  242. package/dist/workspace/flags.d.ts +100 -0
  243. package/dist/workspace/flags.d.ts.map +1 -0
  244. package/dist/workspace/flags.js +98 -0
  245. package/dist/workspace/graph-cli.js +1 -1
  246. package/dist/workspace/intent-cli.d.ts +11 -2
  247. package/dist/workspace/intent-cli.d.ts.map +1 -1
  248. package/dist/workspace/intent-cli.js +54 -5
  249. package/dist/workspace/intent-trace.d.ts +219 -0
  250. package/dist/workspace/intent-trace.d.ts.map +1 -0
  251. package/dist/workspace/intent-trace.js +314 -0
  252. package/dist/workspace/intent.d.ts +30 -6
  253. package/dist/workspace/intent.d.ts.map +1 -1
  254. package/dist/workspace/intent.js +141 -21
  255. package/dist/workspace/intent.schema.json +702 -6
  256. package/dist/workspace/overlap.d.ts +146 -0
  257. package/dist/workspace/overlap.d.ts.map +1 -0
  258. package/dist/workspace/overlap.js +276 -0
  259. package/dist/workspace/pr-report.schema.json +5 -0
  260. package/dist/workspace/reason-codes.d.ts +2 -0
  261. package/dist/workspace/reason-codes.d.ts.map +1 -1
  262. package/dist/workspace/reason-codes.js +3 -0
  263. package/dist/workspace/records.d.ts +15 -2
  264. package/dist/workspace/records.d.ts.map +1 -1
  265. package/dist/workspace/records.js +32 -0
  266. package/dist/workspace/records.schema.json +21 -2
  267. package/dist/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  268. package/dist/workspace/reference-kinds/flag/flag.schema.json +53 -0
  269. package/dist/workspace/releases.d.ts +9 -0
  270. package/dist/workspace/releases.d.ts.map +1 -1
  271. package/dist/workspace/releases.js +9 -0
  272. package/dist/workspace/releases.schema.json +123 -1
  273. package/dist/workspace/run-event.schema.json +24 -6
  274. package/dist/workspace/status-gates.d.ts +8 -0
  275. package/dist/workspace/status-gates.d.ts.map +1 -1
  276. package/dist/workspace/status-stewards.d.ts +2 -0
  277. package/dist/workspace/status-stewards.d.ts.map +1 -1
  278. package/dist/workspace/status-stewards.js +1 -0
  279. package/dist/workspace/status.d.ts +78 -0
  280. package/dist/workspace/status.d.ts.map +1 -1
  281. package/dist/workspace/status.js +170 -3
  282. package/dist/workspace/status.schema.json +210 -2
  283. package/dist/workspace/wip.d.ts.map +1 -1
  284. package/dist/workspace/wip.js +11 -3
  285. package/package.json +1 -1
  286. package/src/build-params.test.ts +46 -0
  287. package/src/build-params.ts +55 -1
  288. package/src/change-set-graph.ts +10 -2
  289. package/src/change-set.ts +14 -3
  290. package/src/cli/build-params-cli.ts +22 -9
  291. package/src/cli/commands/build.ts +6 -3
  292. package/src/cli/handlers/approve-release.test.ts +5 -1
  293. package/src/cli/handlers/approve-revoked.test.ts +155 -0
  294. package/src/cli/handlers/approve.ts +47 -0
  295. package/src/cli/handlers/build.test.ts +30 -0
  296. package/src/cli/handlers/build.ts +20 -4
  297. package/src/cli/handlers/fan-out.test.ts +262 -1
  298. package/src/cli/handlers/fan-out.ts +72 -8
  299. package/src/cli/handlers/intent-trace.e2e.test.ts +201 -0
  300. package/src/cli/handlers/lifecycle-gc.test.ts +126 -0
  301. package/src/cli/handlers/lifecycle-gc.ts +146 -0
  302. package/src/cli/handlers/pr.test.ts +148 -1
  303. package/src/cli/handlers/pr.ts +144 -28
  304. package/src/cli/handlers/promote.test.ts +280 -2
  305. package/src/cli/handlers/promote.ts +210 -34
  306. package/src/cli/handlers/release-implicit.e2e.test.ts +12 -4
  307. package/src/cli/handlers/release-join.e2e.test.ts +185 -0
  308. package/src/cli/handlers/release-publish-targets.e2e.test.ts +295 -0
  309. package/src/cli/handlers/release-verify.e2e.test.ts +117 -0
  310. package/src/cli/handlers/release-workstation-ci.e2e.test.ts +135 -0
  311. package/src/cli/handlers/release.e2e.test.ts +146 -32
  312. package/src/cli/handlers/release.ts +415 -28
  313. package/src/cli/handlers/run-auto-release.test.ts +9 -0
  314. package/src/cli/handlers/run-release.test.ts +55 -0
  315. package/src/cli/handlers/run.ts +69 -5
  316. package/src/cli/main.test.ts +1 -0
  317. package/src/cli/main.ts +91 -10
  318. package/src/cli/parse-args.ts +54 -2
  319. package/src/cli/registry.ts +32 -4
  320. package/src/cli/run-events.ts +5 -2
  321. package/src/components/auto-release.test.ts +9 -0
  322. package/src/components/auto-release.ts +3 -0
  323. package/src/components/capability.ts +9 -0
  324. package/src/components/driver.test.ts +24 -0
  325. package/src/components/driver.ts +36 -0
  326. package/src/components/fan-out-inputs.test.ts +85 -0
  327. package/src/components/fan-out-inputs.ts +192 -0
  328. package/src/components/fan-out-record.test.ts +10 -0
  329. package/src/components/fan-out-record.ts +19 -0
  330. package/src/components/fan-out-run.ts +48 -0
  331. package/src/components/fan-out.ts +4 -0
  332. package/src/components/pr-pipeline.ts +67 -4
  333. package/src/components/pr-run.test.ts +127 -0
  334. package/src/components/pr-run.ts +32 -12
  335. package/src/components/promote.ts +68 -2
  336. package/src/components/release-compile.ts +17 -3
  337. package/src/components/release-gate.ts +18 -4
  338. package/src/components/wave-plan.ts +45 -2
  339. package/src/config.ts +8 -0
  340. package/src/flag-params.test.ts +144 -0
  341. package/src/flag-params.ts +134 -0
  342. package/src/lifecycle/__fixtures__/publish-fakes.ts +351 -0
  343. package/src/lifecycle/change-set-store.ts +2 -1
  344. package/src/lifecycle/delivery-metrics.ts +263 -0
  345. package/src/lifecycle/deploy-outcome.ts +147 -0
  346. package/src/lifecycle/gate-change-set.ts +37 -6
  347. package/src/lifecycle/gate-ledger.ts +2 -2
  348. package/src/lifecycle/git.ts +61 -8
  349. package/src/lifecycle/index.ts +4 -0
  350. package/src/lifecycle/mixed-environment.test.ts +97 -0
  351. package/src/lifecycle/mixed-environment.ts +204 -0
  352. package/src/lifecycle/publish-attachments.ts +196 -0
  353. package/src/lifecycle/publish-credentials.ts +84 -0
  354. package/src/lifecycle/publish-declaration.ts +95 -0
  355. package/src/lifecycle/publish-forge.ts +325 -0
  356. package/src/lifecycle/publish-npm.ts +259 -0
  357. package/src/lifecycle/publish-oci.ts +396 -0
  358. package/src/lifecycle/publish-record.ts +113 -0
  359. package/src/lifecycle/publish-resume.test.ts +168 -0
  360. package/src/lifecycle/publish-targets.test.ts +494 -0
  361. package/src/lifecycle/publish-targets.ts +100 -0
  362. package/src/lifecycle/release-cut.test.ts +74 -2
  363. package/src/lifecycle/release-cut.ts +158 -22
  364. package/src/lifecycle/release-flag.test.ts +112 -0
  365. package/src/lifecycle/release-join.test.ts +68 -0
  366. package/src/lifecycle/release-join.ts +182 -0
  367. package/src/lifecycle/release-ledger.ts +9 -3
  368. package/src/lifecycle/release-publish.test.ts +225 -0
  369. package/src/lifecycle/release-publish.ts +568 -0
  370. package/src/lifecycle/release-revocation.ts +147 -0
  371. package/src/lifecycle/release-store.ts +15 -4
  372. package/src/lifecycle/release-verify.test.ts +110 -0
  373. package/src/lifecycle/release-verify.ts +120 -0
  374. package/src/lifecycle/release-workstation.test.ts +204 -0
  375. package/src/lifecycle/release-workstation.ts +216 -0
  376. package/src/lifecycle/retention-growth.e2e.test.ts +279 -0
  377. package/src/lifecycle/retention-policy.ts +63 -0
  378. package/src/lifecycle/retention.test.ts +363 -0
  379. package/src/lifecycle/retention.ts +508 -0
  380. package/src/lifecycle/run-ledger.ts +7 -1
  381. package/src/op/activities/activity-contracts.ts +1 -0
  382. package/src/op/activities/shell.ts +7 -1
  383. package/src/op/local-executor.ts +27 -4
  384. package/src/op/runtime.ts +42 -0
  385. package/src/plan-summary.test.ts +20 -0
  386. package/src/plan-summary.ts +8 -1
  387. package/src/pr-forge.test.ts +25 -0
  388. package/src/pr-forge.ts +62 -0
  389. package/src/pr-loop.test.ts +13 -1
  390. package/src/pr-loop.ts +41 -4
  391. package/src/pr-report-url.test.ts +131 -0
  392. package/src/pr-report-url.ts +209 -0
  393. package/src/provenance.ts +2 -2
  394. package/src/run-event-store.ts +63 -3
  395. package/src/run-event-stream.ts +8 -4
  396. package/src/run-event.ts +38 -1
  397. package/src/workspace/__fixtures__/flag-workspace.ts +132 -0
  398. package/src/workspace/__fixtures__/older-records/change-set-984534ea9.json +100 -0
  399. package/src/workspace/__fixtures__/older-records/older-records.json +326 -0
  400. package/src/workspace/change-set.schema.json +5 -1
  401. package/src/workspace/check.schema.json +4 -2
  402. package/src/workspace/checks/records.ts +35 -1
  403. package/src/workspace/checks.ts +2 -1
  404. package/src/workspace/ci-green-forge.ts +2 -0
  405. package/src/workspace/ci-green.ts +20 -5
  406. package/src/workspace/ci-run.test.ts +416 -0
  407. package/src/workspace/ci-run.ts +571 -0
  408. package/src/workspace/ci-serve.test.ts +268 -0
  409. package/src/workspace/ci-serve.ts +521 -0
  410. package/src/workspace/declaration.schema.json +64 -0
  411. package/src/workspace/declaration.test.ts +28 -0
  412. package/src/workspace/declaration.ts +38 -0
  413. package/src/workspace/declared-kinds.ts +40 -1
  414. package/src/workspace/delivery-metrics.schema.json +519 -0
  415. package/src/workspace/delivery-metrics.test.ts +236 -0
  416. package/src/workspace/delivery-metrics.ts +286 -0
  417. package/src/workspace/flags-read.ts +121 -0
  418. package/src/workspace/flags.test.ts +141 -0
  419. package/src/workspace/flags.ts +157 -0
  420. package/src/workspace/graph-cli.ts +1 -1
  421. package/src/workspace/intent-cli.ts +46 -5
  422. package/src/workspace/intent-trace.test.ts +173 -0
  423. package/src/workspace/intent-trace.ts +484 -0
  424. package/src/workspace/intent.schema.json +702 -6
  425. package/src/workspace/intent.ts +148 -25
  426. package/src/workspace/older-records.test.ts +412 -0
  427. package/src/workspace/overlap.test.ts +165 -0
  428. package/src/workspace/overlap.ts +340 -0
  429. package/src/workspace/pr-report.schema.json +5 -0
  430. package/src/workspace/read-contract.e2e.test.ts +2 -1
  431. package/src/workspace/reason-codes.test.ts +5 -0
  432. package/src/workspace/reason-codes.ts +3 -0
  433. package/src/workspace/record-assets.test.ts +2 -1
  434. package/src/workspace/records-contract.e2e.test.ts +2 -1
  435. package/src/workspace/records.schema.json +21 -2
  436. package/src/workspace/records.ts +36 -2
  437. package/src/workspace/reference-kinds/flag/flag.kind.mjs +32 -0
  438. package/src/workspace/reference-kinds/flag/flag.schema.json +53 -0
  439. package/src/workspace/releases.schema.json +123 -1
  440. package/src/workspace/releases.ts +11 -0
  441. package/src/workspace/run-event.schema.json +24 -6
  442. package/src/workspace/status-contract.test.ts +29 -0
  443. package/src/workspace/status-gates.ts +8 -0
  444. package/src/workspace/status-mixed.test.ts +152 -0
  445. package/src/workspace/status-revoked.test.ts +153 -0
  446. package/src/workspace/status-stewards.ts +3 -0
  447. package/src/workspace/status.schema.json +210 -2
  448. package/src/workspace/status.ts +254 -3
  449. package/src/workspace/wip.ts +11 -2
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from "fs";
2
2
  import { resolve } from "path";
3
- import { resolveBuildParams, type BuildParamsConfig } from "../build-params";
3
+ import { resolveBuildParams, type BuildParamFlags, type BuildParamsConfig } from "../build-params";
4
4
  import type { BuildParamProvenance } from "../provenance";
5
5
  import { formatError, formatInfo } from "./format";
6
6
 
@@ -40,6 +40,10 @@ export interface CliBuildParamsArgs {
40
40
  paramsFile?: string;
41
41
  /** `--verbose` — list every resolved parameter one per line instead of the one-line count (#1424). */
42
42
  verbose?: boolean;
43
+ /** The workspace flags backing parameters in this build's environment (#4024), from `../flag-params.ts`. */
44
+ flags?: BuildParamFlags;
45
+ /** `false` to resolve without printing the summary line, for a caller that checks more before it prints ({@link echoBuildParams}). */
46
+ echo?: boolean;
43
47
  }
44
48
 
45
49
  export interface CliBuildParamsResolution {
@@ -94,6 +98,7 @@ export function resolveCliBuildParams(
94
98
  cli: args.cli,
95
99
  fromFile,
96
100
  env: process.env,
101
+ ...(args.flags ? { flags: args.flags } : {}),
97
102
  });
98
103
  for (const message of resolution.errors) {
99
104
  errors.push(formatError({ message }));
@@ -103,21 +108,25 @@ export function resolveCliBuildParams(
103
108
  return { success: false, provenance: [], errors };
104
109
  }
105
110
 
111
+ if (args.echo !== false) echoBuildParams(resolution.provenance, args.verbose);
112
+ return { success: true, provenance: resolution.provenance, errors: [] };
113
+ }
114
+
115
+ /** Print a successful resolution: the one-line summary, or every value under `--verbose` or `CHANT_PARAM_ECHO=all` (#1424). */
116
+ export function echoBuildParams(provenance: readonly BuildParamProvenance[], verboseFlag?: boolean): void {
106
117
  // #1424 — one line by default. A project with two dozen declared
107
118
  // parameters printed two dozen grey lines on every build, ahead of the
108
119
  // warnings the reader actually needed. The count by source still answers
109
120
  // "did my override reach the build" (the failure mode
110
121
  // warnIfParamsCannotReachProject exists for); --verbose names every value.
111
- const verbose = args.verbose === true || process.env.CHANT_PARAM_ECHO === "all";
122
+ const verbose = verboseFlag === true || process.env.CHANT_PARAM_ECHO === "all";
112
123
  if (verbose) {
113
- for (const p of resolution.provenance) {
124
+ for (const p of provenance) {
114
125
  console.error(formatInfo(`[param] ${p.name} = ${JSON.stringify(p.value)} (${p.source})`));
115
126
  }
116
- } else if (resolution.provenance.length > 0) {
117
- console.error(formatInfo(summarizeBuildParams(resolution.provenance)));
127
+ } else if (provenance.length > 0) {
128
+ console.error(formatInfo(summarizeBuildParams(provenance)));
118
129
  }
119
-
120
- return { success: true, provenance: resolution.provenance, errors: [] };
121
130
  }
122
131
 
123
132
  /**
@@ -127,8 +136,12 @@ export function resolveCliBuildParams(
127
136
  */
128
137
  export function summarizeBuildParams(provenance: readonly { source: string }[]): string {
129
138
  const counts = new Map<string, number>();
130
- for (const p of provenance) counts.set(p.source, (counts.get(p.source) ?? 0) + 1);
131
- const order = ["cli", "params-file", "env", "default"];
139
+ // Every flag source (`flag:<name>`, #4024) counts as one, "from flags".
140
+ for (const p of provenance) {
141
+ const source = p.source.startsWith("flag:") ? "flags" : p.source;
142
+ counts.set(source, (counts.get(source) ?? 0) + 1);
143
+ }
144
+ const order = ["cli", "params-file", "env", "flags", "default"];
132
145
  const rank = (s: string) => (order.includes(s) ? order.indexOf(s) : order.length);
133
146
  const parts = [...counts.keys()]
134
147
  .sort((a, b) => rank(a) - rank(b))
@@ -12,7 +12,7 @@ import { resolveTelemetryAttribution } from "../../telemetry-attribution";
12
12
  import { loadOkfBundle } from "../../okf-read";
13
13
  import { unknownEnvError } from "../../env";
14
14
  import type { OwnershipMarker } from "../../ownership";
15
- import { resolveCliBuildParams } from "../build-params-cli";
15
+ import { resolveFlaggedBuildParams } from "../../flag-params";
16
16
  import type { Serializer, SerializerResult } from "../../serializer";
17
17
  import type { LexiconPlugin } from "../../lexicon";
18
18
  import { runPostSynthChecks, type PostSynthDiagnostic } from "../../lint/post-synth";
@@ -297,11 +297,14 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
297
297
  // project's own `params.ts` does before migrating to this mechanism). Also
298
298
  // logs a one-line count on success, or every resolved value (`[param] name =
299
299
  // value (source)`) under --verbose (#1424).
300
- const paramsResolution = resolveCliBuildParams(config.buildParams, {
300
+ // #4024: in a workspace member, a build for an environment also reads the
301
+ // flag records that back its parameters, and refuses an override of one
302
+ // where the environment has a gate (../../flag-params.ts).
303
+ const paramsResolution = await resolveFlaggedBuildParams(configDir, config.buildParams, {
301
304
  cli: options.params,
302
305
  paramsFile: options.paramsFile,
303
306
  verbose: options.verbose,
304
- });
307
+ }, options.env);
305
308
  if (!paramsResolution.success) {
306
309
  errors.push(...paramsResolution.errors);
307
310
  return { success: false, resourceCount: 0, fileCount: 0, errors, warnings };
@@ -11,6 +11,7 @@ import { writeFileSync } from "node:fs";
11
11
  import { join } from "node:path";
12
12
  import { appendPendingGate, readGateLedger } from "../../lifecycle/gate-ledger";
13
13
  import { resetGateOrigin } from "../../lifecycle/gate-origin";
14
+ import { makeRelease, persistRelease } from "../../lifecycle/release-store";
14
15
 
15
16
  vi.mock("../../op/discover", () => ({ discoverOps: async () => ({ errors: [], ops: new Map() }) }));
16
17
 
@@ -20,7 +21,9 @@ function git(args: string[], cwd: string): void {
20
21
  spawnSync("git", args, { cwd, encoding: "utf-8" });
21
22
  }
22
23
 
23
- const RELEASE = `jcs1-sha256:${"a".repeat(64)}`;
24
+ /** The release the gate binds. #4033: approve reads it to check its commit isn't revoked, so it is stored. */
25
+ const STORED = makeRelease({ member: null, commit: "1".repeat(40), artifactDigests: [], targets: [{ env: "prod", templates: [], params: [] }] });
26
+ const RELEASE = STORED.releaseDigest;
24
27
  const DOC = `jcs1-sha256:${"d".repeat(64)}`;
25
28
 
26
29
  async function repoWithReleaseGate(dir: string): Promise<void> {
@@ -30,6 +33,7 @@ async function repoWithReleaseGate(dir: string): Promise<void> {
30
33
  writeFileSync(join(dir, "README.md"), "x\n");
31
34
  git(["add", "."], dir);
32
35
  git(["commit", "-q", "-m", "init"], dir);
36
+ await persistRelease(STORED, [], { cwd: dir });
33
37
  await appendPendingGate(
34
38
  {
35
39
  op: "release",
@@ -0,0 +1,155 @@
1
+ /**
2
+ * #4033 (ws-105): when a commit is revoked, the release cut from it is
3
+ * revoked, and its pending release gate refuses approval. Against temp repos;
4
+ * nothing is pushed.
5
+ */
6
+
7
+ import { afterEach, describe, expect, test, vi } from "vitest";
8
+ import { withTestDir } from "@intentius/chant-test-utils";
9
+ import { spawnSync } from "node:child_process";
10
+ import { writeFileSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ import { appendPendingGate, readGateLedger } from "../../lifecycle/gate-ledger";
13
+ import { resetGateOrigin } from "../../lifecycle/gate-origin";
14
+ import { appendCut, makeRelease, persistRelease, type Release } from "../../lifecycle/release-store";
15
+
16
+ vi.mock("../../op/discover", () => ({ discoverOps: async () => ({ errors: [], ops: new Map() }) }));
17
+
18
+ const { recordGateApproval } = await import("./approve");
19
+
20
+ function git(cwd: string, ...args: string[]): string {
21
+ const r = spawnSync("git", args, { cwd, encoding: "utf-8" });
22
+ if (r.status !== 0) throw new Error(`git ${args.join(" ")}: ${r.stderr}`);
23
+ return r.stdout.trim();
24
+ }
25
+
26
+ const DOC = `jcs1-sha256:${"d".repeat(64)}`;
27
+ const GREEN = { branch: "main", phases: { test: ["test"] }, require: ["test"] };
28
+
29
+ function declaration(dir: string, green: Record<string, unknown>): void {
30
+ writeFileSync(
31
+ join(dir, "chant.workspace.json"),
32
+ JSON.stringify({ name: "acme", schema: 1, members: [{ name: "root", dir: ".", kind: "other", because: "the release fixture" }], ci: { green } }, null, 2),
33
+ );
34
+ }
35
+
36
+ /** A green commit, a release cut from it as v1.0.0, and a release gate pending for it in prod. */
37
+ async function releaseWaitingAtGate(dir: string): Promise<{ sha: string; release: Release }> {
38
+ git(dir, "init", "-q", "-b", "main");
39
+ git(dir, "config", "user.email", "t@chant.dev");
40
+ git(dir, "config", "user.name", "T");
41
+ declaration(dir, GREEN);
42
+ git(dir, "add", ".");
43
+ git(dir, "commit", "-q", "-m", "init");
44
+ const sha = git(dir, "rev-parse", "HEAD");
45
+ git(dir, "tag", "-a", "-m", "ci: green", `ci/green/${sha}`, sha);
46
+ const release = makeRelease({
47
+ member: null,
48
+ commit: sha,
49
+ artifactDigests: [],
50
+ targets: [{ env: "prod", templates: [{ component: "api", path: "t.json", digest: `sha256:${"c".repeat(64)}` }], params: [] }],
51
+ });
52
+ await persistRelease(release, [], { cwd: dir });
53
+ await appendCut({ releaseDigest: release.releaseDigest, label: "v1.0.0", actor: "alice", timestamp: "2026-10-16T10:00:00.000Z", runOrigin: null }, { cwd: dir });
54
+ await appendPendingGate(
55
+ {
56
+ op: "release",
57
+ gate: "prod-release",
58
+ timestamp: "2026-10-16T11:00:00.000Z",
59
+ expiresAt: "2999-01-01T00:00:00.000Z",
60
+ planDigest: DOC,
61
+ environment: "prod",
62
+ releaseDigest: release.releaseDigest,
63
+ gitSha: sha,
64
+ },
65
+ { cwd: dir },
66
+ );
67
+ return { sha, release };
68
+ }
69
+
70
+ /** ci tick's revoked tag for a run from chant runs (#4044): the run's id is null and the Op run is named in opRun. */
71
+ function revoke(dir: string, sha: string): void {
72
+ const record = {
73
+ schema: 1,
74
+ tag: "revoked",
75
+ commit: sha,
76
+ branch: "main",
77
+ at: "2026-10-16T12:00:00.000Z",
78
+ source: "runs",
79
+ phase: "test",
80
+ run: { name: "smoke", id: null, conclusion: "failure", url: null, opRun: { id: "r-12", env: "staging", signer: "runner:ci", statement: null } },
81
+ };
82
+ git(dir, "tag", "-a", "-m", `ci: phase test failed in smoke (failure)\n\n${JSON.stringify(record, null, 2)}\n`, `ci/revoked/${sha}`, sha);
83
+ }
84
+
85
+ describe("chant approve on the gate of a revoked release (#4033)", () => {
86
+ const cwd = process.cwd();
87
+ afterEach(() => {
88
+ process.chdir(cwd);
89
+ resetGateOrigin();
90
+ vi.restoreAllMocks();
91
+ });
92
+
93
+ test("revoke a commit, and its release's pending gate refuses approval with release-revoked and the fix line", async () => {
94
+ const errors: string[] = [];
95
+ vi.spyOn(console, "error").mockImplementation((...m: unknown[]) => { errors.push(m.join(" ")); });
96
+ await withTestDir(async (dir) => {
97
+ const { sha } = await releaseWaitingAtGate(dir);
98
+ process.chdir(dir);
99
+ revoke(dir, sha);
100
+ const outcome = await recordGateApproval("release", "prod-release", { origin: "cli", actor: "alice", cwd: dir, environment: "prod" });
101
+ expect(outcome.ok).toBe(false);
102
+ const said = errors.join("\n");
103
+ expect(said).toContain(`release v1.0.0 was cut from commit ${sha.slice(0, 12)}, which ci/revoked/${sha} revokes (phase test failed in smoke (Op run r-12 in staging))`);
104
+ expect(said).toContain("[release-revoked]");
105
+ expect(said).toContain("chant approve release prod-release --expire");
106
+ expect((await readGateLedger("release", { cwd: dir })).resolutions).toEqual([]);
107
+
108
+ // Naming the plan outright doesn't get round it.
109
+ const named = await recordGateApproval("release", "prod-release", { origin: "cli", actor: "alice", cwd: dir, environment: "prod", plan: DOC });
110
+ expect(named.ok).toBe(false);
111
+ expect((await readGateLedger("release", { cwd: dir })).resolutions).toEqual([]);
112
+ });
113
+ });
114
+
115
+ test("before the commit is revoked, the same gate takes the approval", async () => {
116
+ vi.spyOn(console, "error").mockImplementation(() => {});
117
+ await withTestDir(async (dir) => {
118
+ const { release } = await releaseWaitingAtGate(dir);
119
+ process.chdir(dir);
120
+ const outcome = await recordGateApproval("release", "prod-release", { origin: "cli", actor: "alice", cwd: dir, environment: "prod" });
121
+ expect(outcome.ok).toBe(true);
122
+ expect((await readGateLedger("release", { cwd: dir })).resolutions).toEqual([expect.objectContaining({ releaseDigest: release.releaseDigest })]);
123
+ });
124
+ });
125
+
126
+ test("with ci.green.signedSince, a hand-pushed revoked tag is ignored and revokes nothing", async () => {
127
+ vi.spyOn(console, "error").mockImplementation(() => {});
128
+ await withTestDir(async (dir) => {
129
+ const { sha } = await releaseWaitingAtGate(dir);
130
+ // The release's own commit is the pivot, so a tag on it needs a statement; this one has none.
131
+ declaration(dir, { ...GREEN, signedSince: sha });
132
+ git(dir, "commit", "-q", "-am", "require signed ci tags");
133
+ revoke(dir, sha);
134
+ process.chdir(dir);
135
+ const outcome = await recordGateApproval("release", "prod-release", { origin: "cli", actor: "alice", cwd: dir, environment: "prod" });
136
+ expect(outcome.ok).toBe(true);
137
+ });
138
+ });
139
+
140
+ test("a gate whose release can't be read refuses, since whether it is revoked is unknown", async () => {
141
+ const errors: string[] = [];
142
+ vi.spyOn(console, "error").mockImplementation((...m: unknown[]) => { errors.push(m.join(" ")); });
143
+ await withTestDir(async (dir) => {
144
+ await releaseWaitingAtGate(dir);
145
+ await appendPendingGate(
146
+ { op: "release", gate: "prod-release", timestamp: "2026-10-16T13:00:00.000Z", expiresAt: "2999-01-01T00:00:00.000Z", planDigest: DOC, environment: "prod", releaseDigest: `jcs1-sha256:${"e".repeat(64)}` },
147
+ { cwd: dir },
148
+ );
149
+ process.chdir(dir);
150
+ const outcome = await recordGateApproval("release", "prod-release", { origin: "cli", actor: "alice", cwd: dir, environment: "prod" });
151
+ expect(outcome.ok).toBe(false);
152
+ expect(errors.join("\n")).toContain("[release-unreadable]");
153
+ });
154
+ });
155
+ });
@@ -255,6 +255,46 @@ export type GateApprovalOutcome =
255
255
  | { ok: true; record: GateResolutionRecord; pushed: boolean }
256
256
  | { ok: false };
257
257
 
258
+ /**
259
+ * Refuse the approval of a release gate whose release is revoked (#4033,
260
+ * ws-105): its commit carries a `ci/revoked/<sha>` tag that counts, read from
261
+ * local tags as `release cut` reads them. Prints the refusal and returns true
262
+ * when it refuses. A release file that can't be read, or tags that can't be
263
+ * judged, refuse too, since whether the release is revoked is then unknown.
264
+ */
265
+ async function refuseRevokedRelease(opName: string, gate: string, releaseDigest: string, cwd: string): Promise<boolean> {
266
+ const { readRelease, readCuts, labelsByDigest } = await import("../../lifecycle/release-store");
267
+ const { readRevokedCommits, revocationOf, revokedRefusal } = await import("../../lifecycle/release-revocation");
268
+ const release = await readRelease(releaseDigest, { cwd }).catch(() => null);
269
+ if (!release) {
270
+ console.error(formatError({
271
+ message: `Gate "${gate}" on "${opName}" binds release ${releaseDigest}, which can't be read from ${LIFECYCLE_BRANCH}, so whether it is revoked is unknown [release-unreadable]`,
272
+ hint: `Fetch the ledger branch (git fetch origin ${LIFECYCLE_BRANCH}:${LIFECYCLE_BRANCH}) and approve again from the member's directory.`,
273
+ }));
274
+ return true;
275
+ }
276
+ let revoked: Awaited<ReturnType<typeof readRevokedCommits>>;
277
+ try {
278
+ revoked = await readRevokedCommits(cwd);
279
+ } catch (err) {
280
+ console.error(formatError({
281
+ message: `Gate "${gate}" on "${opName}" binds release ${releaseDigest}, and the ci tags can't be judged: ${err instanceof Error ? err.message : String(err)} [declaration-invalid]`,
282
+ hint: "Fix ci.green in chant.workspace.json at base; chant workspace check names the problem.",
283
+ }));
284
+ return true;
285
+ }
286
+ const r = revocationOf(release, revoked);
287
+ if (!r) return false;
288
+ const label = labelsByDigest((await readCuts({ cwd }).catch(() => ({ cuts: [] }))).cuts).get(releaseDigest) ?? null;
289
+ console.error(formatError(revokedRefusal(
290
+ { releaseDigest, label },
291
+ r,
292
+ `Clear the pending gate with \`chant approve ${opName} ${gate} --expire\`, then promote a release cut from a green commit: ` +
293
+ "`chant ci last-green` names the newest, and `chant release list` marks the revoked releases.",
294
+ )));
295
+ return true;
296
+ }
297
+
258
298
  /**
259
299
  * The ledger write behind `chant approve` — extracted so `chant run approve`
260
300
  * (#2121) records the identical fact before waking the runtime that hosts the
@@ -400,6 +440,13 @@ export async function recordGateApproval(
400
440
  // approval of another plan names none, and no release gate counts it.
401
441
  const releaseDigest =
402
442
  standing?.releaseDigest !== undefined && samePlanDigest(planDigest, standing.planDigest) ? standing.releaseDigest : undefined;
443
+ // #4033 (ws-105): a release gate whose release was cut from a revoked
444
+ // commit is superseded. Its promote refuses the release, so an approval of
445
+ // it would count for nothing; refuse it here, whatever plan is named.
446
+ if (standing?.releaseDigest !== undefined) {
447
+ const refused = await refuseRevokedRelease(opName, gate, standing.releaseDigest, opts.cwd ?? process.cwd());
448
+ if (refused) return { ok: false };
449
+ }
403
450
 
404
451
  // chant#2384 — the gate's whole value is that its two halves have different
405
452
  // authors. At a shell they do: a person runs, reads the plan, and approves.
@@ -133,6 +133,36 @@ describe("runBuild --components --generate (chant #1108 build-time parameters)",
133
133
  vi.restoreAllMocks();
134
134
  });
135
135
 
136
+ test("--pr-loop with --events-json and --report-url asks the generated jobs for both (#4007)", async () => {
137
+ generateComponentsPipelineMock.mockResolvedValue({ success: true, yaml: "stages: []", stages: [], jobs: [] });
138
+ vi.spyOn(console, "log").mockImplementation(() => {});
139
+
140
+ const exit = await runBuild({
141
+ args: makeArgs({ generate: "github", prLoop: true, eventsJson: true, reportUrl: "s3://reports/acme" }),
142
+ plugins: [],
143
+ serializers: [],
144
+ });
145
+
146
+ expect(exit).toBe(0);
147
+ expect(generateComponentsPipelineMock).toHaveBeenCalledWith(".", "github", { env: undefined, prLoop: { events: true, reportUrl: "s3://reports/acme" } }, undefined, []);
148
+ vi.restoreAllMocks();
149
+ });
150
+
151
+ test("--pr-build and --pr-build-command become the prLoop build options (#4088)", async () => {
152
+ generateComponentsPipelineMock.mockResolvedValue({ success: true, yaml: "jobs: {}", stages: [], jobs: [] });
153
+ vi.spyOn(console, "log").mockImplementation(() => {});
154
+
155
+ const exit = await runBuild({
156
+ args: makeArgs({ generate: "github", prLoop: true, prBuild: true, prBuildCommand: "npm run build" }),
157
+ plugins: [],
158
+ serializers: [],
159
+ });
160
+
161
+ expect(exit).toBe(0);
162
+ expect(generateComponentsPipelineMock).toHaveBeenCalledWith(".", "github", { env: undefined, prLoop: { build: true, buildCommand: "npm run build" } }, undefined, []);
163
+ vi.restoreAllMocks();
164
+ });
165
+
136
166
  test("chant.config.ts's declared buildParams resolve, log, and are forwarded to generateComponentsPipeline", async () => {
137
167
  loadChantConfigUpwardMock.mockResolvedValue({
138
168
  config: { buildParams: { tier: { type: "string", default: "light" } } },
@@ -8,6 +8,24 @@ import { loadChantConfigUpward, type ChantConfig } from "../../config";
8
8
  import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
9
9
  import { findWorkspaceRoot } from "../../project-root";
10
10
  import { resolvePromotionSource } from "../../components/promote-order";
11
+ import type { PrLoopPipelineOptions } from "../../components/pr-pipeline";
12
+
13
+ /**
14
+ * The `prLoop` generator option from `--pr-loop`'s flags (#3183): the gate
15
+ * and the branch, and with `--events-json` and `--report-url` (#4007) the
16
+ * flags the generated jobs pass to pr-plan and pr-apply. `--pr-build` and
17
+ * `--pr-build-command` (#4088) add the build and lint steps before both.
18
+ */
19
+ function prLoopOption(args: CommandContext["args"]): PrLoopPipelineOptions {
20
+ return {
21
+ ...(args.gate ? { gate: args.gate } : {}),
22
+ ...(args.branch ? { branch: args.branch } : {}),
23
+ ...(args.eventsJson ? { events: true } : {}),
24
+ ...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
25
+ ...(args.prBuild ? { build: true } : {}),
26
+ ...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
27
+ };
28
+ }
11
29
 
12
30
  /**
13
31
  * `chant build --components --generate <lexicon>` — generate mode (#563,
@@ -86,7 +104,7 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
86
104
  params: args.param,
87
105
  paramsFile: args.paramsFile,
88
106
  ...(args.waveGate ? { waveGate: { gate: args.waveGate, ...(args.canary?.length ? { canary: args.canary } : {}), ...(args.base ? { base: args.base } : {}) } } : {}),
89
- ...(args.prLoop ? { prLoop: { ...(args.gate ? { gate: args.gate } : {}), ...(args.branch ? { branch: args.branch } : {}) } } : {}),
107
+ ...(args.prLoop ? { prLoop: prLoopOption(args) } : {}),
90
108
  ...(args.image ? { image: args.image } : {}),
91
109
  ...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
92
110
  });
@@ -116,9 +134,7 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
116
134
  ? { gatedWaves: { gate: args.waveGate, ...(args.canary?.length ? { canary: args.canary } : {}), ...(args.base ? { base: args.base } : {}) } }
117
135
  : {}),
118
136
  // #3183: a plan job per pull request and an apply job per merge.
119
- ...(args.prLoop
120
- ? { prLoop: { ...(args.gate ? { gate: args.gate } : {}), ...(args.branch ? { branch: args.branch } : {}) } }
121
- : {}),
137
+ ...(args.prLoop ? { prLoop: prLoopOption(args) } : {}),
122
138
  // #4002: the job image and the lines that install what it lacks, chant itself included.
123
139
  ...(args.image ? { image: args.image } : {}),
124
140
  ...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),