@intentius/chant 0.124.46 → 0.124.49

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 (726) hide show
  1. package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  2. package/dist/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  3. package/dist/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  4. package/dist/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  5. package/dist/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  6. package/dist/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  7. package/dist/__golden__/wave-loop/op-cost-member.json +13 -0
  8. package/dist/__golden__/wave-loop/op-denied-source.json +16 -0
  9. package/dist/__golden__/wave-loop/op-denied.json +16 -0
  10. package/dist/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  11. package/dist/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  12. package/dist/__golden__/wave-loop/op-discover-rest.json +26 -0
  13. package/dist/__golden__/wave-loop/op-discover-wide.json +26 -0
  14. package/dist/__golden__/wave-loop/op-held-on-again.json +16 -0
  15. package/dist/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  16. package/dist/__golden__/wave-loop/op-held-on.json +16 -0
  17. package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  18. package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  19. package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  20. package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  21. package/dist/__golden__/wave-loop/op-hooks-held.json +13 -0
  22. package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  23. package/dist/__golden__/wave-loop/op-hooks-pass.json +13 -0
  24. package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  25. package/dist/__golden__/wave-loop/op-hooks-share.json +33 -0
  26. package/dist/__golden__/wave-loop/op-outcome-held.json +10 -0
  27. package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  28. package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  29. package/dist/__golden__/wave-loop/op-outcome-replan.json +10 -0
  30. package/dist/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  31. package/dist/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  32. package/dist/__golden__/wave-loop/op-overridden.json +16 -0
  33. package/dist/__golden__/wave-loop/op-per-run.json +20 -0
  34. package/dist/__golden__/wave-loop/op-point.json +13 -0
  35. package/dist/__golden__/wave-loop/op-pr-review.json +10 -0
  36. package/dist/__golden__/wave-loop/op-sealed.json +10 -0
  37. package/dist/__golden__/wave-loop/op-spend-change-only.json +10 -0
  38. package/dist/__golden__/wave-loop/op-spend.json +10 -0
  39. package/dist/__golden__/wave-loop/op-wave-commands.json +55 -0
  40. package/dist/__golden__/wave-loop/op-wide-refused.json +26 -0
  41. package/dist/__golden__/wave-loop/op-wide-waiting.json +29 -0
  42. package/dist/__golden__/wave-loop/op-wide.json +39 -0
  43. package/dist/action-pins.d.ts +61 -0
  44. package/dist/action-pins.d.ts.map +1 -0
  45. package/dist/action-pins.js +77 -0
  46. package/dist/cli/commands/carve.d.ts +3 -0
  47. package/dist/cli/commands/carve.d.ts.map +1 -1
  48. package/dist/cli/commands/carve.js +36 -7
  49. package/dist/cli/commands/import-report.d.ts +26 -0
  50. package/dist/cli/commands/import-report.d.ts.map +1 -0
  51. package/dist/cli/commands/import-report.js +65 -0
  52. package/dist/cli/commands/import.d.ts +11 -1
  53. package/dist/cli/commands/import.d.ts.map +1 -1
  54. package/dist/cli/commands/import.js +22 -3
  55. package/dist/cli/commands/migrate.d.ts +13 -1
  56. package/dist/cli/commands/migrate.d.ts.map +1 -1
  57. package/dist/cli/commands/migrate.js +134 -10
  58. package/dist/cli/handlers/approve.d.ts.map +1 -1
  59. package/dist/cli/handlers/approve.js +41 -14
  60. package/dist/cli/handlers/build.d.ts.map +1 -1
  61. package/dist/cli/handlers/build.js +6 -1
  62. package/dist/cli/handlers/graph-reader.d.ts +26 -0
  63. package/dist/cli/handlers/graph-reader.d.ts.map +1 -0
  64. package/dist/cli/handlers/graph-reader.js +41 -0
  65. package/dist/cli/handlers/graph.d.ts.map +1 -1
  66. package/dist/cli/handlers/graph.js +14 -0
  67. package/dist/cli/handlers/ledger.d.ts +3 -0
  68. package/dist/cli/handlers/ledger.d.ts.map +1 -0
  69. package/dist/cli/handlers/ledger.js +55 -0
  70. package/dist/cli/handlers/migrate.d.ts.map +1 -1
  71. package/dist/cli/handlers/migrate.js +18 -11
  72. package/dist/cli/handlers/misc.d.ts.map +1 -1
  73. package/dist/cli/handlers/misc.js +12 -1
  74. package/dist/cli/handlers/pr-env.js +2 -2
  75. package/dist/cli/handlers/pr.d.ts +15 -1
  76. package/dist/cli/handlers/pr.d.ts.map +1 -1
  77. package/dist/cli/handlers/pr.js +183 -40
  78. package/dist/cli/handlers/query.d.ts +7 -2
  79. package/dist/cli/handlers/query.d.ts.map +1 -1
  80. package/dist/cli/handlers/query.js +16 -4
  81. package/dist/cli/handlers/release.d.ts.map +1 -1
  82. package/dist/cli/handlers/release.js +6 -3
  83. package/dist/cli/handlers/search.d.ts +2 -4
  84. package/dist/cli/handlers/search.d.ts.map +1 -1
  85. package/dist/cli/handlers/search.js +13 -39
  86. package/dist/cli/main.d.ts.map +1 -1
  87. package/dist/cli/main.js +87 -14
  88. package/dist/cli/parse-args.d.ts.map +1 -1
  89. package/dist/cli/parse-args.js +47 -2
  90. package/dist/cli/registry.d.ts +22 -4
  91. package/dist/cli/registry.d.ts.map +1 -1
  92. package/dist/components/builders.d.ts +5 -1
  93. package/dist/components/builders.d.ts.map +1 -1
  94. package/dist/components/builders.js +5 -0
  95. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  96. package/dist/components/capability-plugin-loader.js +16 -1
  97. package/dist/components/capability-plugin.d.ts +14 -0
  98. package/dist/components/capability-plugin.d.ts.map +1 -1
  99. package/dist/components/pr-hooks.d.ts +21 -1
  100. package/dist/components/pr-hooks.d.ts.map +1 -1
  101. package/dist/components/pr-hooks.js +72 -4
  102. package/dist/components/pr-pipeline.d.ts +45 -10
  103. package/dist/components/pr-pipeline.d.ts.map +1 -1
  104. package/dist/components/pr-pipeline.js +47 -14
  105. package/dist/components/pr-policy.d.ts +36 -0
  106. package/dist/components/pr-policy.d.ts.map +1 -1
  107. package/dist/components/pr-policy.js +36 -0
  108. package/dist/components/pr-run.d.ts +3 -0
  109. package/dist/components/pr-run.d.ts.map +1 -1
  110. package/dist/components/pr-run.js +1 -0
  111. package/dist/components/starter-plugin.d.ts +1 -0
  112. package/dist/components/starter-plugin.d.ts.map +1 -1
  113. package/dist/components/starter-plugin.js +5 -1
  114. package/dist/components/verbs/index.d.ts +2 -0
  115. package/dist/components/verbs/index.d.ts.map +1 -1
  116. package/dist/components/verbs/index.js +2 -0
  117. package/dist/components/verbs/publish-artifact.d.ts +65 -0
  118. package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
  119. package/dist/components/verbs/publish-artifact.js +74 -0
  120. package/dist/components/verbs/publish-image.d.ts +129 -0
  121. package/dist/components/verbs/publish-image.d.ts.map +1 -0
  122. package/dist/components/verbs/publish-image.js +145 -0
  123. package/dist/config-environments.d.ts +20 -0
  124. package/dist/config-environments.d.ts.map +1 -1
  125. package/dist/config-environments.js +12 -0
  126. package/dist/config.d.ts +25 -1
  127. package/dist/config.d.ts.map +1 -1
  128. package/dist/config.js +10 -2
  129. package/dist/gate-decision.d.ts +20 -2
  130. package/dist/gate-decision.d.ts.map +1 -1
  131. package/dist/gate-decision.js +30 -3
  132. package/dist/graph-ir.d.ts +25 -0
  133. package/dist/graph-ir.d.ts.map +1 -1
  134. package/dist/graph-walk.d.ts +66 -0
  135. package/dist/graph-walk.d.ts.map +1 -0
  136. package/dist/graph-walk.js +70 -0
  137. package/dist/import/parser.d.ts +19 -0
  138. package/dist/import/parser.d.ts.map +1 -1
  139. package/dist/lexicon.d.ts +94 -6
  140. package/dist/lexicon.d.ts.map +1 -1
  141. package/dist/lifecycle/gate-ledger.d.ts +11 -0
  142. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  143. package/dist/lifecycle/git.d.ts +2 -5
  144. package/dist/lifecycle/git.d.ts.map +1 -1
  145. package/dist/lifecycle/ledger-read.d.ts +65 -0
  146. package/dist/lifecycle/ledger-read.d.ts.map +1 -0
  147. package/dist/lifecycle/ledger-read.js +160 -0
  148. package/dist/lifecycle/release-workstation.d.ts +7 -0
  149. package/dist/lifecycle/release-workstation.d.ts.map +1 -1
  150. package/dist/lifecycle/release-workstation.js +25 -0
  151. package/dist/lifecycle/run-ledger.d.ts +4 -3
  152. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  153. package/dist/lifecycle/run-ledger.js +1 -0
  154. package/dist/lint/discover.js +3 -1
  155. package/dist/lint/post-synth.d.ts +127 -1
  156. package/dist/lint/post-synth.d.ts.map +1 -1
  157. package/dist/lint/post-synth.js +84 -2
  158. package/dist/lint/rules/op/index.d.ts +1 -0
  159. package/dist/lint/rules/op/index.d.ts.map +1 -1
  160. package/dist/lint/rules/op/index.js +2 -0
  161. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
  162. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
  163. package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
  164. package/dist/op/activities/activity-contracts.d.ts +9 -6
  165. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  166. package/dist/op/activities/activity-contracts.js +5 -2
  167. package/dist/op/activities/index.d.ts +2 -2
  168. package/dist/op/activities/index.d.ts.map +1 -1
  169. package/dist/op/activities/index.js +1 -1
  170. package/dist/op/activities/review-agent.d.ts +90 -4
  171. package/dist/op/activities/review-agent.d.ts.map +1 -1
  172. package/dist/op/activities/review-agent.js +217 -19
  173. package/dist/op/activities/work-evidence.d.ts +8 -1
  174. package/dist/op/activities/work-evidence.d.ts.map +1 -1
  175. package/dist/op/activities/work-evidence.js +1 -0
  176. package/dist/op/builders.d.ts +9 -5
  177. package/dist/op/builders.d.ts.map +1 -1
  178. package/dist/op/builders.js +9 -5
  179. package/dist/op/composites/apply-op.d.ts +29 -2
  180. package/dist/op/composites/apply-op.d.ts.map +1 -1
  181. package/dist/op/composites/apply-op.js +20 -1
  182. package/dist/op/gate-approval-base.d.ts +25 -0
  183. package/dist/op/gate-approval-base.d.ts.map +1 -0
  184. package/dist/op/gate-approval-base.js +71 -0
  185. package/dist/op/gate-approval.d.ts +18 -9
  186. package/dist/op/gate-approval.d.ts.map +1 -1
  187. package/dist/op/gate-approval.js +13 -31
  188. package/dist/op/gate-name.d.ts +13 -0
  189. package/dist/op/gate-name.d.ts.map +1 -1
  190. package/dist/op/gate-name.js +14 -1
  191. package/dist/op/gate-quorum.d.ts +100 -3
  192. package/dist/op/gate-quorum.d.ts.map +1 -1
  193. package/dist/op/gate-quorum.js +108 -6
  194. package/dist/op/gate-review.d.ts +9 -0
  195. package/dist/op/gate-review.d.ts.map +1 -1
  196. package/dist/op/gate-review.js +13 -0
  197. package/dist/op/gate.d.ts +47 -5
  198. package/dist/op/gate.d.ts.map +1 -1
  199. package/dist/op/gate.js +25 -4
  200. package/dist/op/index.d.ts +3 -3
  201. package/dist/op/index.d.ts.map +1 -1
  202. package/dist/op/index.js +1 -1
  203. package/dist/op/local-executor.d.ts +45 -3
  204. package/dist/op/local-executor.d.ts.map +1 -1
  205. package/dist/op/local-executor.js +68 -7
  206. package/dist/op/op-waves-run.d.ts +26 -1
  207. package/dist/op/op-waves-run.d.ts.map +1 -1
  208. package/dist/op/op-waves-run.js +259 -13
  209. package/dist/op/op-waves.d.ts +72 -5
  210. package/dist/op/op-waves.d.ts.map +1 -1
  211. package/dist/op/op-waves.js +110 -15
  212. package/dist/op/runtime.d.ts +11 -0
  213. package/dist/op/runtime.d.ts.map +1 -1
  214. package/dist/op/schedule-overdue.d.ts +16 -0
  215. package/dist/op/schedule-overdue.d.ts.map +1 -1
  216. package/dist/op/schedule-overdue.js +36 -0
  217. package/dist/op/stage-hooks.d.ts +9 -2
  218. package/dist/op/stage-hooks.d.ts.map +1 -1
  219. package/dist/op/stage-hooks.js +7 -5
  220. package/dist/op/workspace-run-env.d.ts +22 -0
  221. package/dist/op/workspace-run-env.d.ts.map +1 -0
  222. package/dist/op/workspace-run-env.js +21 -0
  223. package/dist/pr-forge.d.ts +24 -0
  224. package/dist/pr-forge.d.ts.map +1 -1
  225. package/dist/pr-forge.js +47 -0
  226. package/dist/pr-loop.d.ts +10 -0
  227. package/dist/pr-loop.d.ts.map +1 -1
  228. package/dist/pr-loop.js +4 -0
  229. package/dist/pr-migrations.d.ts +62 -0
  230. package/dist/pr-migrations.d.ts.map +1 -0
  231. package/dist/pr-migrations.js +50 -0
  232. package/dist/pr-post.d.ts +42 -0
  233. package/dist/pr-post.d.ts.map +1 -1
  234. package/dist/pr-post.js +68 -2
  235. package/dist/read-filter.d.ts +65 -0
  236. package/dist/read-filter.d.ts.map +1 -0
  237. package/dist/read-filter.js +179 -0
  238. package/dist/run-event.d.ts +1 -1
  239. package/dist/run-event.d.ts.map +1 -1
  240. package/dist/terraform/carve.d.ts +24 -3
  241. package/dist/terraform/carve.d.ts.map +1 -1
  242. package/dist/terraform/carve.js +32 -14
  243. package/dist/terraform/cuts.d.ts +97 -0
  244. package/dist/terraform/cuts.d.ts.map +1 -0
  245. package/dist/terraform/cuts.js +138 -0
  246. package/dist/terraform/folds.d.ts +26 -0
  247. package/dist/terraform/folds.d.ts.map +1 -0
  248. package/dist/terraform/folds.js +38 -0
  249. package/dist/terraform/graph.d.ts.map +1 -1
  250. package/dist/terraform/graph.js +10 -0
  251. package/dist/terraform/reach.d.ts +140 -0
  252. package/dist/terraform/reach.d.ts.map +1 -0
  253. package/dist/terraform/reach.js +170 -0
  254. package/dist/terraform/score.d.ts +14 -0
  255. package/dist/terraform/score.d.ts.map +1 -1
  256. package/dist/terraform/score.js +14 -31
  257. package/dist/terraform/state.d.ts.map +1 -1
  258. package/dist/terraform/state.js +4 -2
  259. package/dist/terraform/types.d.ts +8 -0
  260. package/dist/terraform/types.d.ts.map +1 -1
  261. package/dist/wave-blocked.d.ts +10 -1
  262. package/dist/wave-blocked.d.ts.map +1 -1
  263. package/dist/wave-blocked.js +31 -3
  264. package/dist/wave-runtime.mjs +264 -254
  265. package/dist/workspace/check.schema.json +13 -2
  266. package/dist/workspace/checks/ci-branch.d.ts +44 -0
  267. package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
  268. package/dist/workspace/checks/ci-branch.js +133 -0
  269. package/dist/workspace/checks/gate-approval.d.ts +58 -0
  270. package/dist/workspace/checks/gate-approval.d.ts.map +1 -0
  271. package/dist/workspace/checks/gate-approval.js +103 -0
  272. package/dist/workspace/checks/links.d.ts +3 -0
  273. package/dist/workspace/checks/links.d.ts.map +1 -1
  274. package/dist/workspace/checks/links.js +12 -1
  275. package/dist/workspace/checks/org.d.ts +48 -0
  276. package/dist/workspace/checks/org.d.ts.map +1 -0
  277. package/dist/workspace/checks/org.js +156 -0
  278. package/dist/workspace/checks.d.ts +12 -1
  279. package/dist/workspace/checks.d.ts.map +1 -1
  280. package/dist/workspace/checks.js +63 -7
  281. package/dist/workspace/ci-branches.d.ts +16 -0
  282. package/dist/workspace/ci-branches.d.ts.map +1 -1
  283. package/dist/workspace/ci-branches.js +27 -0
  284. package/dist/workspace/ci-green-cli.js +7 -7
  285. package/dist/workspace/ci-green-workflow.d.ts +1 -1
  286. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  287. package/dist/workspace/ci-green-workflow.js +13 -8
  288. package/dist/workspace/ci-green.d.ts +14 -0
  289. package/dist/workspace/ci-green.d.ts.map +1 -1
  290. package/dist/workspace/ci-green.js +44 -11
  291. package/dist/workspace/ci-run.d.ts +9 -1
  292. package/dist/workspace/ci-run.d.ts.map +1 -1
  293. package/dist/workspace/ci-run.js +67 -6
  294. package/dist/workspace/ci-serve.d.ts +9 -0
  295. package/dist/workspace/ci-serve.d.ts.map +1 -1
  296. package/dist/workspace/ci-serve.js +114 -76
  297. package/dist/workspace/compose-graph.d.ts +14 -0
  298. package/dist/workspace/compose-graph.d.ts.map +1 -1
  299. package/dist/workspace/composites.d.ts +4 -1
  300. package/dist/workspace/composites.d.ts.map +1 -1
  301. package/dist/workspace/composites.js +5 -2
  302. package/dist/workspace/composites.schema.json +22 -0
  303. package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  304. package/dist/workspace/cross-root-lint.d.ts +56 -0
  305. package/dist/workspace/cross-root-lint.d.ts.map +1 -0
  306. package/dist/workspace/cross-root-lint.js +111 -0
  307. package/dist/workspace/dbt-models-reader.d.ts +44 -0
  308. package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
  309. package/dist/workspace/dbt-models-reader.js +356 -0
  310. package/dist/workspace/dbt-project-common.d.ts +40 -0
  311. package/dist/workspace/dbt-project-common.d.ts.map +1 -0
  312. package/dist/workspace/dbt-project-common.js +106 -0
  313. package/dist/workspace/dbt-project-reader.d.ts +4 -3
  314. package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
  315. package/dist/workspace/dbt-project-reader.js +14 -108
  316. package/dist/workspace/decision-rank.d.ts +26 -0
  317. package/dist/workspace/decision-rank.d.ts.map +1 -0
  318. package/dist/workspace/decision-rank.js +16 -0
  319. package/dist/workspace/declaration.d.ts +50 -2
  320. package/dist/workspace/declaration.d.ts.map +1 -1
  321. package/dist/workspace/declaration.js +57 -11
  322. package/dist/workspace/declaration.schema.json +166 -24
  323. package/dist/workspace/environments.d.ts +26 -2
  324. package/dist/workspace/environments.d.ts.map +1 -1
  325. package/dist/workspace/environments.js +26 -2
  326. package/dist/workspace/exit-cli.d.ts +44 -0
  327. package/dist/workspace/exit-cli.d.ts.map +1 -0
  328. package/dist/workspace/exit-cli.js +198 -0
  329. package/dist/workspace/exit.d.ts +159 -0
  330. package/dist/workspace/exit.d.ts.map +1 -0
  331. package/dist/workspace/exit.js +480 -0
  332. package/dist/workspace/exit.schema.json +257 -0
  333. package/dist/workspace/flyway-dir.d.ts +39 -0
  334. package/dist/workspace/flyway-dir.d.ts.map +1 -0
  335. package/dist/workspace/flyway-dir.js +104 -0
  336. package/dist/workspace/flyway-layout.d.ts +96 -0
  337. package/dist/workspace/flyway-layout.d.ts.map +1 -0
  338. package/dist/workspace/flyway-layout.js +308 -0
  339. package/dist/workspace/graph-cache.d.ts +3 -1
  340. package/dist/workspace/graph-cache.d.ts.map +1 -1
  341. package/dist/workspace/graph-cache.js +12 -1
  342. package/dist/workspace/graph-cli.d.ts.map +1 -1
  343. package/dist/workspace/graph-cli.js +26 -8
  344. package/dist/workspace/graph.schema.json +34 -0
  345. package/dist/workspace/import-fetch.d.ts +38 -0
  346. package/dist/workspace/import-fetch.d.ts.map +1 -0
  347. package/dist/workspace/import-fetch.js +99 -0
  348. package/dist/workspace/import-init.d.ts +26 -0
  349. package/dist/workspace/import-init.d.ts.map +1 -0
  350. package/dist/workspace/import-init.js +130 -0
  351. package/dist/workspace/import-source.d.ts +147 -0
  352. package/dist/workspace/import-source.d.ts.map +1 -0
  353. package/dist/workspace/import-source.js +370 -0
  354. package/dist/workspace/init.d.ts +4 -0
  355. package/dist/workspace/init.d.ts.map +1 -1
  356. package/dist/workspace/init.js +70 -3
  357. package/dist/workspace/intent.d.ts +2 -3
  358. package/dist/workspace/intent.d.ts.map +1 -1
  359. package/dist/workspace/intent.js +5 -9
  360. package/dist/workspace/kind-link-readers.d.ts +59 -2
  361. package/dist/workspace/kind-link-readers.d.ts.map +1 -1
  362. package/dist/workspace/kind-link-readers.js +17 -1
  363. package/dist/workspace/kind-readers.d.ts +6 -0
  364. package/dist/workspace/kind-readers.d.ts.map +1 -1
  365. package/dist/workspace/kind-readers.js +18 -0
  366. package/dist/workspace/kinds.d.ts +90 -3
  367. package/dist/workspace/kinds.d.ts.map +1 -1
  368. package/dist/workspace/kinds.js +161 -7
  369. package/dist/workspace/ledger.schema.json +158 -0
  370. package/dist/workspace/lexicon-outputs.d.ts +20 -1
  371. package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
  372. package/dist/workspace/lexicon-outputs.js +102 -10
  373. package/dist/workspace/lineage-check.d.ts +3 -0
  374. package/dist/workspace/lineage-check.d.ts.map +1 -1
  375. package/dist/workspace/lineage-check.js +23 -4
  376. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  377. package/dist/workspace/lineage-upgrade.js +13 -4
  378. package/dist/workspace/links.d.ts +8 -1
  379. package/dist/workspace/links.d.ts.map +1 -1
  380. package/dist/workspace/links.js +25 -1
  381. package/dist/workspace/ls.d.ts +8 -0
  382. package/dist/workspace/ls.d.ts.map +1 -1
  383. package/dist/workspace/ls.js +7 -1
  384. package/dist/workspace/ls.schema.json +7 -0
  385. package/dist/workspace/member-commands.d.ts.map +1 -1
  386. package/dist/workspace/member-commands.js +54 -5
  387. package/dist/workspace/migrate-links.d.ts +45 -0
  388. package/dist/workspace/migrate-links.d.ts.map +1 -0
  389. package/dist/workspace/migrate-links.js +100 -0
  390. package/dist/workspace/migration-dirs.d.ts +74 -0
  391. package/dist/workspace/migration-dirs.d.ts.map +1 -0
  392. package/dist/workspace/migration-dirs.js +254 -0
  393. package/dist/workspace/new-migrations.d.ts +47 -0
  394. package/dist/workspace/new-migrations.d.ts.map +1 -0
  395. package/dist/workspace/new-migrations.js +91 -0
  396. package/dist/workspace/pr-report.schema.json +46 -0
  397. package/dist/workspace/promote.d.ts +96 -0
  398. package/dist/workspace/promote.d.ts.map +1 -0
  399. package/dist/workspace/promote.js +263 -0
  400. package/dist/workspace/reason-codes.d.ts +21 -0
  401. package/dist/workspace/reason-codes.d.ts.map +1 -1
  402. package/dist/workspace/reason-codes.js +25 -0
  403. package/dist/workspace/records-cli.d.ts +11 -0
  404. package/dist/workspace/records-cli.d.ts.map +1 -1
  405. package/dist/workspace/records-cli.js +57 -5
  406. package/dist/workspace/records.schema.json +5 -0
  407. package/dist/workspace/release-candidates.d.ts +2 -0
  408. package/dist/workspace/release-candidates.d.ts.map +1 -1
  409. package/dist/workspace/release-candidates.js +5 -2
  410. package/dist/workspace/release-train.d.ts +53 -0
  411. package/dist/workspace/release-train.d.ts.map +1 -0
  412. package/dist/workspace/release-train.js +134 -0
  413. package/dist/workspace/release-workflow.d.ts.map +1 -1
  414. package/dist/workspace/release-workflow.js +4 -3
  415. package/dist/workspace/repo-ref.d.ts +45 -0
  416. package/dist/workspace/repo-ref.d.ts.map +1 -0
  417. package/dist/workspace/repo-ref.js +114 -0
  418. package/dist/workspace/run-event.schema.json +2 -2
  419. package/dist/workspace/runs-cli.d.ts +9 -0
  420. package/dist/workspace/runs-cli.d.ts.map +1 -1
  421. package/dist/workspace/runs-cli.js +48 -3
  422. package/dist/workspace/runs.schema.json +7 -0
  423. package/dist/workspace/search-contract.d.ts +1 -1
  424. package/dist/workspace/search-contract.d.ts.map +1 -1
  425. package/dist/workspace/status-decisions.d.ts +37 -0
  426. package/dist/workspace/status-decisions.d.ts.map +1 -0
  427. package/dist/workspace/status-decisions.js +147 -0
  428. package/dist/workspace/status-gates.d.ts +9 -0
  429. package/dist/workspace/status-gates.d.ts.map +1 -1
  430. package/dist/workspace/status.d.ts +4 -0
  431. package/dist/workspace/status.d.ts.map +1 -1
  432. package/dist/workspace/status.js +14 -2
  433. package/dist/workspace/status.schema.json +6 -0
  434. package/dist/workspace/work-cli.d.ts.map +1 -1
  435. package/dist/workspace/work-cli.js +5 -3
  436. package/dist/workspace/work-evidence-ops.d.ts +83 -0
  437. package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
  438. package/dist/workspace/work-evidence-ops.js +169 -0
  439. package/dist/workspace/work-evidence.d.ts +12 -2
  440. package/dist/workspace/work-evidence.d.ts.map +1 -1
  441. package/dist/workspace/work-evidence.js +21 -3
  442. package/dist/workspace/work-evidence.schema.json +49 -2
  443. package/dist/workspace/workspace-gates.d.ts +110 -0
  444. package/dist/workspace/workspace-gates.d.ts.map +1 -0
  445. package/dist/workspace/workspace-gates.js +140 -0
  446. package/dist/workspace/workspace-kinds.schema.json +108 -10
  447. package/dist/workspace/workspace-ledger.d.ts +76 -0
  448. package/dist/workspace/workspace-ledger.d.ts.map +1 -0
  449. package/dist/workspace/workspace-ledger.js +91 -0
  450. package/dist/workspace/workspace-run.d.ts +112 -0
  451. package/dist/workspace/workspace-run.d.ts.map +1 -0
  452. package/dist/workspace/workspace-run.js +432 -0
  453. package/package.json +1 -1
  454. package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  455. package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  456. package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  457. package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  458. package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  459. package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  460. package/src/__golden__/wave-loop/op-cost-member.json +13 -0
  461. package/src/__golden__/wave-loop/op-denied-source.json +16 -0
  462. package/src/__golden__/wave-loop/op-denied.json +16 -0
  463. package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  464. package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  465. package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
  466. package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
  467. package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
  468. package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  469. package/src/__golden__/wave-loop/op-held-on.json +16 -0
  470. package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  471. package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  472. package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  473. package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  474. package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
  475. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  476. package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
  477. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  478. package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
  479. package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
  480. package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  481. package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  482. package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
  483. package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  484. package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  485. package/src/__golden__/wave-loop/op-overridden.json +16 -0
  486. package/src/__golden__/wave-loop/op-per-run.json +20 -0
  487. package/src/__golden__/wave-loop/op-point.json +13 -0
  488. package/src/__golden__/wave-loop/op-pr-review.json +10 -0
  489. package/src/__golden__/wave-loop/op-sealed.json +10 -0
  490. package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
  491. package/src/__golden__/wave-loop/op-spend.json +10 -0
  492. package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
  493. package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
  494. package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
  495. package/src/__golden__/wave-loop/op-wide.json +39 -0
  496. package/src/action-pins.test.ts +78 -0
  497. package/src/action-pins.ts +92 -0
  498. package/src/cli/commands/carve-score-once.test.ts +99 -0
  499. package/src/cli/commands/carve.ts +37 -6
  500. package/src/cli/commands/check-lexicon.test.ts +2 -2
  501. package/src/cli/commands/import-report.ts +71 -0
  502. package/src/cli/commands/import.ts +33 -3
  503. package/src/cli/commands/migrate-dialect.test.ts +145 -0
  504. package/src/cli/commands/migrate.ts +132 -11
  505. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
  506. package/src/cli/handlers/approve.ts +33 -4
  507. package/src/cli/handlers/build.ts +7 -1
  508. package/src/cli/handlers/graph-reader.test.ts +31 -0
  509. package/src/cli/handlers/graph-reader.ts +51 -0
  510. package/src/cli/handlers/graph.ts +14 -0
  511. package/src/cli/handlers/ledger.ts +54 -0
  512. package/src/cli/handlers/migrate.ts +21 -12
  513. package/src/cli/handlers/misc.ts +10 -1
  514. package/src/cli/handlers/pr-env.ts +2 -2
  515. package/src/cli/handlers/pr.ts +176 -37
  516. package/src/cli/handlers/query.ts +16 -4
  517. package/src/cli/handlers/release.ts +6 -3
  518. package/src/cli/handlers/search.ts +13 -34
  519. package/src/cli/main.test.ts +17 -0
  520. package/src/cli/main.ts +87 -14
  521. package/src/cli/parse-args.ts +35 -2
  522. package/src/cli/registry.ts +22 -4
  523. package/src/components/builders.ts +8 -0
  524. package/src/components/capability-plugin-loader.ts +13 -1
  525. package/src/components/capability-plugin.ts +16 -0
  526. package/src/components/pr-env-run-bundle.test.ts +1 -0
  527. package/src/components/pr-hooks.test.ts +73 -5
  528. package/src/components/pr-hooks.ts +95 -5
  529. package/src/components/pr-pipeline.ts +64 -16
  530. package/src/components/pr-policy.test.ts +64 -1
  531. package/src/components/pr-policy.ts +53 -0
  532. package/src/components/pr-run.ts +4 -0
  533. package/src/components/registry.test.ts +1 -1
  534. package/src/components/starter-plugin.ts +6 -0
  535. package/src/components/verbs/index.ts +2 -0
  536. package/src/components/verbs/publish-artifact.test.ts +60 -0
  537. package/src/components/verbs/publish-artifact.ts +122 -0
  538. package/src/components/verbs/publish-image.test.ts +101 -0
  539. package/src/components/verbs/publish-image.ts +265 -0
  540. package/src/config-environments.ts +28 -1
  541. package/src/config.ts +24 -1
  542. package/src/gate-decision-bundle.test.ts +5 -2
  543. package/src/gate-decision-identity.test.ts +20 -0
  544. package/src/gate-decision.ts +46 -3
  545. package/src/graph-ir.ts +27 -0
  546. package/src/graph-walk.test.ts +44 -0
  547. package/src/graph-walk.ts +102 -0
  548. package/src/import/parser.ts +20 -0
  549. package/src/lexicon.ts +98 -6
  550. package/src/lifecycle/gate-ledger.ts +8 -0
  551. package/src/lifecycle/git.ts +2 -2
  552. package/src/lifecycle/ledger-read.test.ts +107 -0
  553. package/src/lifecycle/ledger-read.ts +195 -0
  554. package/src/lifecycle/release-workstation.ts +24 -0
  555. package/src/lifecycle/run-ledger.ts +5 -2
  556. package/src/lint/cross-root.test.ts +122 -0
  557. package/src/lint/discover.ts +3 -1
  558. package/src/lint/post-synth.ts +212 -2
  559. package/src/lint/rules/op/index.ts +2 -0
  560. package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
  561. package/src/op/activities/activity-contracts.ts +5 -2
  562. package/src/op/activities/index.ts +2 -2
  563. package/src/op/activities/review-agent.test.ts +221 -4
  564. package/src/op/activities/review-agent.ts +265 -22
  565. package/src/op/activities/work-evidence.ts +9 -1
  566. package/src/op/builders.ts +9 -5
  567. package/src/op/composites/apply-op.test.ts +108 -0
  568. package/src/op/composites/apply-op.ts +37 -2
  569. package/src/op/gate-approval-at-base.test.ts +97 -0
  570. package/src/op/gate-approval-base.ts +72 -0
  571. package/src/op/gate-approval.test.ts +6 -1
  572. package/src/op/gate-approval.ts +22 -27
  573. package/src/op/gate-name.ts +16 -1
  574. package/src/op/gate-quorum-at-base.test.ts +211 -0
  575. package/src/op/gate-quorum.ts +156 -8
  576. package/src/op/gate-review.ts +14 -0
  577. package/src/op/gate.ts +69 -9
  578. package/src/op/index.ts +3 -2
  579. package/src/op/local-executor.ts +91 -11
  580. package/src/op/op-waves-depends-on.test.ts +81 -0
  581. package/src/op/op-waves-hook-targets.test.ts +4 -2
  582. package/src/op/op-waves-quorum-product.test.ts +158 -0
  583. package/src/op/op-waves-run.ts +288 -14
  584. package/src/op/op-waves.ts +143 -14
  585. package/src/op/runtime.ts +8 -0
  586. package/src/op/schedule-overdue.ts +33 -0
  587. package/src/op/stage-hooks.ts +13 -5
  588. package/src/op/workspace-run-env.ts +29 -0
  589. package/src/pr-forge-bundle.test.ts +2 -2
  590. package/src/pr-forge.test.ts +47 -0
  591. package/src/pr-forge.ts +68 -0
  592. package/src/pr-loop-bundle.test.ts +3 -2
  593. package/src/pr-loop.test.ts +52 -0
  594. package/src/pr-loop.ts +12 -0
  595. package/src/pr-migrations.ts +97 -0
  596. package/src/pr-post-open.e2e.test.ts +36 -0
  597. package/src/pr-post.test.ts +102 -3
  598. package/src/pr-post.ts +90 -2
  599. package/src/read-filter.test.ts +54 -0
  600. package/src/read-filter.ts +193 -0
  601. package/src/run-event.ts +1 -1
  602. package/src/stage-hooks-bundle.test.ts +1 -0
  603. package/src/terraform/carve.ts +52 -15
  604. package/src/terraform/cuts.test.ts +173 -0
  605. package/src/terraform/cuts.ts +188 -0
  606. package/src/terraform/folds.ts +44 -0
  607. package/src/terraform/graph.ts +9 -0
  608. package/src/terraform/radius.test.ts +90 -0
  609. package/src/terraform/reach.test.ts +146 -0
  610. package/src/terraform/reach.ts +247 -0
  611. package/src/terraform/score.ts +27 -29
  612. package/src/terraform/state.ts +3 -1
  613. package/src/terraform/types.ts +8 -0
  614. package/src/wave-blocked.ts +28 -3
  615. package/src/wave-loop-golden.test.ts +4 -3
  616. package/src/workspace/__fixtures__/import/spacelift.json +9 -0
  617. package/src/workspace/__fixtures__/import/tfc.json +13 -0
  618. package/src/workspace/behold-kinds.test.ts +2 -1
  619. package/src/workspace/check-contract.test.ts +8 -6
  620. package/src/workspace/check.schema.json +13 -2
  621. package/src/workspace/checks/ci-branch.test.ts +128 -0
  622. package/src/workspace/checks/ci-branch.ts +141 -0
  623. package/src/workspace/checks/gate-approval.test.ts +77 -0
  624. package/src/workspace/checks/gate-approval.ts +121 -0
  625. package/src/workspace/checks/links.ts +12 -1
  626. package/src/workspace/checks/org.ts +169 -0
  627. package/src/workspace/checks.ts +68 -7
  628. package/src/workspace/ci-branches.ts +31 -0
  629. package/src/workspace/ci-green-branches.test.ts +153 -0
  630. package/src/workspace/ci-green-cli.ts +7 -7
  631. package/src/workspace/ci-green-workflow.test.ts +4 -3
  632. package/src/workspace/ci-green-workflow.ts +13 -9
  633. package/src/workspace/ci-green.ts +49 -12
  634. package/src/workspace/ci-run.test.ts +72 -1
  635. package/src/workspace/ci-run.ts +68 -8
  636. package/src/workspace/ci-serve.test.ts +95 -0
  637. package/src/workspace/ci-serve.ts +106 -65
  638. package/src/workspace/component-environments.test.ts +25 -2
  639. package/src/workspace/compose-graph.ts +9 -2
  640. package/src/workspace/composites.schema.json +22 -0
  641. package/src/workspace/composites.test.ts +39 -8
  642. package/src/workspace/composites.ts +6 -2
  643. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  644. package/src/workspace/cross-root-lint.test.ts +90 -0
  645. package/src/workspace/cross-root-lint.ts +126 -0
  646. package/src/workspace/dbt-kind.test.ts +3 -2
  647. package/src/workspace/dbt-models-reader.ts +362 -0
  648. package/src/workspace/dbt-models.test.ts +248 -0
  649. package/src/workspace/dbt-project-common.ts +113 -0
  650. package/src/workspace/dbt-project-reader.ts +29 -112
  651. package/src/workspace/decision-rank.ts +40 -0
  652. package/src/workspace/declaration.schema.json +166 -24
  653. package/src/workspace/declaration.ts +101 -15
  654. package/src/workspace/environments.ts +40 -4
  655. package/src/workspace/exit-cli.ts +219 -0
  656. package/src/workspace/exit.schema.json +257 -0
  657. package/src/workspace/exit.test.ts +185 -0
  658. package/src/workspace/exit.ts +560 -0
  659. package/src/workspace/flyway-dir.ts +113 -0
  660. package/src/workspace/flyway-layout.ts +337 -0
  661. package/src/workspace/graph-cache.ts +12 -2
  662. package/src/workspace/graph-cli.ts +25 -10
  663. package/src/workspace/graph-contract.test.ts +4 -2
  664. package/src/workspace/graph.schema.json +34 -0
  665. package/src/workspace/identity.test.ts +29 -2
  666. package/src/workspace/import-fetch.ts +151 -0
  667. package/src/workspace/import-init.ts +147 -0
  668. package/src/workspace/import-source.test.ts +183 -0
  669. package/src/workspace/import-source.ts +462 -0
  670. package/src/workspace/init.test.ts +55 -1
  671. package/src/workspace/init.ts +66 -4
  672. package/src/workspace/intent.ts +6 -14
  673. package/src/workspace/kind-link-readers.ts +68 -3
  674. package/src/workspace/kind-readers.test.ts +36 -0
  675. package/src/workspace/kind-readers.ts +18 -1
  676. package/src/workspace/kinds.test.ts +35 -7
  677. package/src/workspace/kinds.ts +212 -11
  678. package/src/workspace/ledger.schema.json +158 -0
  679. package/src/workspace/lexicon-outputs.ts +132 -13
  680. package/src/workspace/lineage-check.ts +30 -7
  681. package/src/workspace/lineage-upgrade.test.ts +20 -0
  682. package/src/workspace/lineage-upgrade.ts +16 -7
  683. package/src/workspace/links.ts +24 -1
  684. package/src/workspace/ls-contract.test.ts +1 -1
  685. package/src/workspace/ls.schema.json +7 -0
  686. package/src/workspace/ls.ts +10 -1
  687. package/src/workspace/member-commands.ts +60 -2
  688. package/src/workspace/member-file-schema.test.ts +124 -0
  689. package/src/workspace/migrate-links.test.ts +99 -0
  690. package/src/workspace/migrate-links.ts +108 -0
  691. package/src/workspace/migration-dirs.test.ts +272 -0
  692. package/src/workspace/migration-dirs.ts +267 -0
  693. package/src/workspace/new-migrations.test.ts +98 -0
  694. package/src/workspace/new-migrations.ts +109 -0
  695. package/src/workspace/org-scope.test.ts +238 -0
  696. package/src/workspace/pr-report.schema.json +46 -0
  697. package/src/workspace/promote.test.ts +114 -0
  698. package/src/workspace/promote.ts +302 -0
  699. package/src/workspace/reason-codes.test.ts +10 -1
  700. package/src/workspace/reason-codes.ts +25 -0
  701. package/src/workspace/records-cli.ts +58 -5
  702. package/src/workspace/records.schema.json +5 -0
  703. package/src/workspace/release-candidates.ts +7 -2
  704. package/src/workspace/release-train.ts +157 -0
  705. package/src/workspace/release-workflow.ts +4 -3
  706. package/src/workspace/repo-ref.ts +113 -0
  707. package/src/workspace/run-event.schema.json +2 -2
  708. package/src/workspace/runs-cli.ts +48 -4
  709. package/src/workspace/runs.schema.json +7 -0
  710. package/src/workspace/status-contract.test.ts +46 -1
  711. package/src/workspace/status-decisions.test.ts +100 -0
  712. package/src/workspace/status-decisions.ts +151 -0
  713. package/src/workspace/status-gates.ts +9 -0
  714. package/src/workspace/status.schema.json +6 -0
  715. package/src/workspace/status.ts +17 -3
  716. package/src/workspace/where-filters.test.ts +39 -0
  717. package/src/workspace/work-cli.ts +5 -3
  718. package/src/workspace/work-evidence-ops.test.ts +176 -0
  719. package/src/workspace/work-evidence-ops.ts +189 -0
  720. package/src/workspace/work-evidence.schema.json +49 -2
  721. package/src/workspace/work-evidence.ts +22 -3
  722. package/src/workspace/workspace-gates.ts +200 -0
  723. package/src/workspace/workspace-kinds.schema.json +108 -10
  724. package/src/workspace/workspace-ledger.ts +130 -0
  725. package/src/workspace/workspace-run.test.ts +322 -0
  726. package/src/workspace/workspace-run.ts +461 -0
@@ -0,0 +1,302 @@
1
+ /**
2
+ * `chant workspace promote <member>` (#3178): move one member one rung up the
3
+ * kind ladder, `other` or `terraform`, then `choudoufu`, then `chant`.
4
+ *
5
+ * The change is staged the way `workspace upgrade` stages one (#2550): in a
6
+ * git worktree at HEAD, so the tree is never touched until the gate passes.
7
+ * The gate is `workspace-promote/<member>` on the gate ledger and binds the
8
+ * digest of the patch the staging produced. The first run records a pending
9
+ * fact and exits 3. After `chant approve workspace-promote <member>`, the same
10
+ * command stages again, finds the approval for the same digest, applies the
11
+ * patch, and runs the rung's follow-up (for `choudoufu`, stamping the
12
+ * ownership markers with `live-import -approve`).
13
+ *
14
+ * Rungs:
15
+ *
16
+ * - `terraform` to `choudoufu`: `choudoufu live-check` in the member's
17
+ * directory must pass, then `choudoufu live-import -state=<--state>
18
+ * -estate=<member>` prints its ratification report (read-only: it stamps
19
+ * nothing without `-approve`). The patch changes the member's kind.
20
+ * - `choudoufu` or `other` to `chant`: `chant import` writes TypeScript into
21
+ * the member's directory. The patch holds those files and the kind change.
22
+ *
23
+ * Commands run through an injectable runner, so a test never starts a binary.
24
+ */
25
+
26
+ import { execFileSync, spawn } from "node:child_process";
27
+ import { existsSync, mkdirSync, realpathSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
28
+ import { tmpdir } from "node:os";
29
+ import { join, relative, resolve, sep } from "node:path";
30
+ import { formatError, formatInfo, formatSuccess, formatWarning } from "../cli/format";
31
+ import type { CommandContext } from "../cli/registry";
32
+ import { computePlanDigest } from "../lifecycle/plan-digest";
33
+ import { LIFECYCLE_LOCAL_NOTE, isLifecycleLocalNote } from "../lifecycle/local-note";
34
+ import { approveCommand, describeGateMismatch, evaluateGate, gateIsSealed, gitGateLedgerPort, type GateLedgerPort } from "../op/gate";
35
+ import { WORKSPACE_PROMOTE_GATE_OP } from "../op/gate-name";
36
+ import { DECLARATION_FILES, readDeclaration } from "./declaration";
37
+ import { setProperty } from "./json-edit";
38
+ import { workingTree } from "./tree";
39
+
40
+ export const PROMOTE_PLAN_KIND = "workspace-promote";
41
+ export const PROMOTE_GATED_EXIT = 3;
42
+ const USAGE = "chant workspace promote <member> [--state <terraform.tfstate>] [--lexicon <lexicon>] [--dry-run] [--output <patch file>] [--json]";
43
+
44
+ export class PromoteError extends Error {}
45
+
46
+ /** The ladder, lowest rung first. `other` and `terraform` share the bottom rung. */
47
+ export const LADDER = ["terraform", "choudoufu", "chant"] as const;
48
+
49
+ export interface Rung {
50
+ from: string;
51
+ to: "choudoufu" | "chant";
52
+ }
53
+
54
+ /** The next rung for a member of `kind`, or undefined at the top or off the ladder. */
55
+ export function nextRung(kind: string): Rung | undefined {
56
+ if (kind === "terraform") return { from: kind, to: "choudoufu" };
57
+ if (kind === "choudoufu" || kind === "other") return { from: kind, to: "chant" };
58
+ return undefined;
59
+ }
60
+
61
+ export interface CommandRun {
62
+ label: string;
63
+ argv: string[];
64
+ /** Directory relative to the project root. */
65
+ cwd: string;
66
+ }
67
+ export type PromoteRunner = (argv: string[], cwd: string) => Promise<{ exitCode: number; output: string }>;
68
+
69
+ export const spawnRunner: PromoteRunner = (argv, cwd) =>
70
+ new Promise((done) => {
71
+ const [bin, ...rest] = argv;
72
+ const child = spawn(bin, rest, { cwd, stdio: ["ignore", "pipe", "pipe"], env: process.env });
73
+ const out: Buffer[] = [];
74
+ child.stdout.on("data", (c: Buffer) => out.push(c));
75
+ child.stderr.on("data", (c: Buffer) => out.push(c));
76
+ child.on("error", (e) => done({ exitCode: 127, output: String(e.message) }));
77
+ child.on("close", (code) => done({ exitCode: code ?? 1, output: Buffer.concat(out).toString("utf-8") }));
78
+ });
79
+
80
+ /** The commands the rung runs in the staging worktree. */
81
+ export function stagingRuns(rung: Rung, member: { name: string; dir: string }, opts: { state?: string; lexicon?: string }): CommandRun[] {
82
+ if (rung.to === "choudoufu") {
83
+ if (!opts.state) throw new PromoteError(`promoting ${member.name} to choudoufu reads its state for the adoption report: pass --state <terraform.tfstate>`);
84
+ return [
85
+ { label: "choudoufu live-check", argv: ["choudoufu", "live-check"], cwd: member.dir },
86
+ { label: "choudoufu live-import (report)", argv: ["choudoufu", "live-import", `-state=${opts.state}`, `-estate=${member.name}`], cwd: member.dir },
87
+ ];
88
+ }
89
+ const lexicon = opts.lexicon ?? (rung.from === "choudoufu" ? "terraform" : undefined);
90
+ if (!lexicon) throw new PromoteError(`promoting ${member.name} (kind other) to chant needs --lexicon <lexicon>: what chant import should read it as`);
91
+ return [{ label: "chant import", argv: ["chant", "import", ".", "--lexicon", lexicon, "--output", "src/"], cwd: member.dir }];
92
+ }
93
+
94
+ /** After the approved patch is applied: stamping ownership markers on the live resources. */
95
+ export function followUpRuns(rung: Rung, member: { name: string; dir: string }, opts: { state?: string }): CommandRun[] {
96
+ if (rung.to !== "choudoufu") return [];
97
+ return [{ label: "choudoufu live-import -approve", argv: ["choudoufu", "live-import", `-state=${opts.state}`, `-estate=${member.name}`, "-approve"], cwd: member.dir }];
98
+ }
99
+
100
+ function git(cwd: string, args: string[]): string {
101
+ return execFileSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 256 * 1024 * 1024 });
102
+ }
103
+
104
+ export interface PromoteOptions {
105
+ root: string;
106
+ member: string;
107
+ state?: string;
108
+ lexicon?: string;
109
+ dryRun?: boolean;
110
+ output?: string;
111
+ json?: boolean;
112
+ /** For tests. */
113
+ runner?: PromoteRunner;
114
+ ledger?: GateLedgerPort;
115
+ now?: string;
116
+ }
117
+
118
+ export type PromoteOutcome = "top-of-ladder" | "checks-failed" | "dry-run" | "gated" | "applied";
119
+ export interface PromoteResult {
120
+ outcome: PromoteOutcome;
121
+ exitCode: number;
122
+ member: string;
123
+ from?: string;
124
+ to?: string;
125
+ digest?: string;
126
+ patch?: string;
127
+ ran?: { label: string; exitCode: number }[];
128
+ }
129
+
130
+ function declarationFile(root: string): string {
131
+ const f = DECLARATION_FILES.find((n) => existsSync(join(root, n)));
132
+ if (!f) throw new PromoteError(`no ${DECLARATION_FILES.join(" or ")} in ${root}`);
133
+ return f;
134
+ }
135
+
136
+ /** Rewrite the member's `kind` in the declaration text. */
137
+ export function setMemberKind(text: string, file: string, member: string, kind: string): string {
138
+ const raw = (file.endsWith(".jsonc") ? text.replace(/^\s*\/\/.*$/gm, "") : text);
139
+ const parsed = JSON.parse(raw) as { members?: { name?: string }[] };
140
+ const i = (parsed.members ?? []).findIndex((m) => m.name === member);
141
+ if (i < 0) throw new PromoteError(`the declaration has no member "${member}"`);
142
+ return setProperty(text, file.endsWith(".jsonc"), `/members/${i}`, "kind", kind);
143
+ }
144
+
145
+ export async function promoteCommand(opts: PromoteOptions): Promise<PromoteResult> {
146
+ const root = realpathSync(resolve(opts.root));
147
+ const run = opts.runner ?? spawnRunner;
148
+ const decl = readDeclaration(workingTree(root));
149
+ const found = decl.members.find((m) => m.name === opts.member);
150
+ if (!found) throw new PromoteError(`the declaration has no member "${opts.member}"; chant workspace ls lists them`);
151
+ const say = (m: string): void => {
152
+ if (!opts.json) console.error(m);
153
+ };
154
+ const rung = nextRung(found.kind);
155
+ if (!rung) {
156
+ say(formatInfo(`${found.name} is kind ${found.kind}, which has no rung above it on the ladder (terraform or other, choudoufu, chant)`));
157
+ return { outcome: "top-of-ladder", exitCode: 0, member: found.name, from: found.kind };
158
+ }
159
+ const member = { name: found.name, dir: found.dir === "." ? "" : found.dir };
160
+ const staging = stagingRuns(rung, member, opts);
161
+
162
+ let repo: string;
163
+ let head: string;
164
+ try {
165
+ repo = git(root, ["rev-parse", "--show-toplevel"]).trim();
166
+ head = git(root, ["rev-parse", "HEAD"]).trim();
167
+ } catch {
168
+ throw new PromoteError("chant workspace promote stages its change in a git worktree, so the project must be in a git repository with at least one commit");
169
+ }
170
+ const projectRel = relative(repo, root).split(sep).join("/");
171
+ const declFile = declarationFile(root);
172
+ const watched = [declFile, member.dir].filter(Boolean).map((p) => [projectRel, p].filter(Boolean).join("/"));
173
+ const dirty = git(repo, ["status", "--porcelain", "--untracked-files=all", "--", ...watched]).split("\n").filter(Boolean);
174
+ if (dirty.length > 0) {
175
+ throw new PromoteError(`${found.name} has uncommitted changes (${dirty.slice(0, 5).map((l) => l.slice(3)).join(", ")}). Commit them: promote stages from HEAD and applies its patch to the tree.`);
176
+ }
177
+
178
+ const holder = mkdtempSync(join(tmpdir(), "chant-promote-"));
179
+ const worktree = join(holder, "wt");
180
+ const dispose = (): void => {
181
+ try {
182
+ git(repo, ["worktree", "remove", "--force", worktree]);
183
+ } catch {
184
+ // Fall through to the directory removal and a prune.
185
+ }
186
+ rmSync(holder, { recursive: true, force: true });
187
+ try {
188
+ git(repo, ["worktree", "prune"]);
189
+ } catch {
190
+ // Nothing to prune.
191
+ }
192
+ };
193
+
194
+ try {
195
+ git(repo, ["worktree", "add", "-q", "--detach", worktree, head]);
196
+ const project = projectRel ? join(worktree, projectRel) : worktree;
197
+ const ran: { label: string; exitCode: number }[] = [];
198
+ for (const step of staging) {
199
+ const cwd = join(project, step.cwd);
200
+ mkdirSync(cwd, { recursive: true });
201
+ const result = await run(step.argv, cwd);
202
+ ran.push({ label: step.label, exitCode: result.exitCode });
203
+ if (!opts.json) say(formatInfo(`${step.label}: exit ${result.exitCode}`));
204
+ if (result.exitCode !== 0) {
205
+ say(formatError({ message: `${step.label} failed in the staging worktree`, hint: result.output.trimEnd().split("\n").slice(-20).join("\n") }));
206
+ say(formatError({ message: "the promotion was not gated: its checks must pass first. The tree is unchanged." }));
207
+ if (opts.json) console.log(JSON.stringify({ outcome: "checks-failed", member: found.name, ran }, null, 2));
208
+ return { outcome: "checks-failed", exitCode: 1, member: found.name, from: rung.from, to: rung.to, ran };
209
+ }
210
+ }
211
+ const declPath = join(project, declFile);
212
+ writeFileSync(declPath, setMemberKind(readFileSync(declPath, "utf-8"), declFile, found.name, rung.to));
213
+ git(worktree, ["add", "-A"]);
214
+ const patch = git(worktree, ["diff", "--cached", "--binary", "HEAD"]);
215
+ const digest = computePlanDigest(PROMOTE_PLAN_KIND, { member: found.name, from: rung.from, to: rung.to, patch });
216
+ const base: PromoteResult = { outcome: "dry-run", exitCode: 0, member: found.name, from: rung.from, to: rung.to, digest, patch, ran };
217
+ const report = (outcome: PromoteOutcome, exitCode: number, extra: Record<string, unknown> = {}): PromoteResult => {
218
+ if (opts.json) console.log(JSON.stringify({ outcome, member: found.name, from: rung.from, to: rung.to, digest, ran, ...extra }, null, 2));
219
+ return { ...base, outcome, exitCode };
220
+ };
221
+ say(formatInfo(`${found.name}: ${rung.from} to ${rung.to}, patch ${digest}`));
222
+ if (opts.output) writeFileSync(resolve(opts.output), patch);
223
+ if (opts.dryRun) {
224
+ say(formatInfo("--dry-run: staged and checked; no gate recorded, the tree is unchanged"));
225
+ return report("dry-run", 0);
226
+ }
227
+
228
+ const check = await evaluateGate(opts.ledger ?? gitGateLedgerPort({ cwd: repo }), {
229
+ op: WORKSPACE_PROMOTE_GATE_OP,
230
+ gate: found.name,
231
+ description: `promote ${found.name} from ${rung.from} to ${rung.to}`,
232
+ planDigest: digest,
233
+ ...(opts.now ? { now: opts.now } : {}),
234
+ });
235
+ if (!check.satisfied) {
236
+ if (!opts.json) {
237
+ const sealed = await gateIsSealed(found.name);
238
+ if (check.mismatch) console.error(formatWarning({ message: describeGateMismatch(WORKSPACE_PROMOTE_GATE_OP, found.name, check.mismatch, sealed) }));
239
+ if (isLifecycleLocalNote(check.pushWarning)) console.error(formatInfo(LIFECYCLE_LOCAL_NOTE));
240
+ else if (check.pushWarning) console.error(formatWarning({ message: check.pushWarning }));
241
+ console.error(
242
+ formatInfo(
243
+ `Gated: the patch ${digest} waits for approval. Review it (--output <file> writes it), then run \`${approveCommand(WORKSPACE_PROMOTE_GATE_OP, found.name, undefined, undefined, sealed)}\` and repeat this command to apply it.`,
244
+ ),
245
+ );
246
+ }
247
+ return report("gated", PROMOTE_GATED_EXIT, { pending: check.pending });
248
+ }
249
+
250
+ const patchDir = mkdtempSync(join(tmpdir(), "chant-promote-patch-"));
251
+ try {
252
+ const file = join(patchDir, "promote.patch");
253
+ writeFileSync(file, patch);
254
+ try {
255
+ git(repo, ["apply", "--binary", "--whitespace=nowarn", file]);
256
+ } catch (err) {
257
+ const stderr = (err as { stderr?: Buffer | string }).stderr?.toString().trim();
258
+ throw new PromoteError(`the approved patch no longer applies to the tree${stderr ? `: ${stderr}` : ""}`);
259
+ }
260
+ } finally {
261
+ rmSync(patchDir, { recursive: true, force: true });
262
+ }
263
+ for (const step of followUpRuns(rung, member, opts)) {
264
+ const result = await run(step.argv, join(root, step.cwd));
265
+ ran.push({ label: step.label, exitCode: result.exitCode });
266
+ if (result.exitCode !== 0) {
267
+ say(formatError({ message: `${step.label} failed after the patch was applied`, hint: result.output.trimEnd().split("\n").slice(-20).join("\n") }));
268
+ return report("applied", 1, { followUpFailed: step.label });
269
+ }
270
+ }
271
+ say(formatSuccess(`applied the approved promotion of "${found.name}" to ${rung.to} (${digest}). Review and commit it.`));
272
+ return report("applied", 0);
273
+ } finally {
274
+ dispose();
275
+ }
276
+ }
277
+
278
+ export async function runWorkspacePromote(ctx: CommandContext): Promise<number> {
279
+ const { args } = ctx;
280
+ if (!args.extraPositional || args.extraPositional2) {
281
+ console.error(formatError({ message: "promote takes exactly one member", hint: USAGE }));
282
+ return 1;
283
+ }
284
+ try {
285
+ const result = await promoteCommand({
286
+ root: process.cwd(),
287
+ member: args.extraPositional,
288
+ state: args.statePath,
289
+ lexicon: args.lexicon,
290
+ dryRun: args.dryRun,
291
+ output: args.output,
292
+ json: args.json,
293
+ });
294
+ return result.exitCode;
295
+ } catch (err) {
296
+ if (err instanceof PromoteError) {
297
+ console.error(formatError({ message: err.message, hint: USAGE }));
298
+ return 1;
299
+ }
300
+ throw err;
301
+ }
302
+ }
@@ -11,7 +11,7 @@ import { describe, expect, test } from "vitest";
11
11
  import { REPO } from "./__fixtures__/contract-repo";
12
12
  import { CHANGES_ERROR_CODES, CHANGES_FINDING_CODES, COMMIT_LINK_FINDING_CODES } from "./changes";
13
13
  import { MEMBER_RUN_REASON_CODES } from "./compose-graph";
14
- import { COMPOSITES_ENVIRONMENT_REASON_CODES, COMPOSITES_ERROR_CODES, COMPOSITES_REASON_CODES, COMPOSITES_RUNTIME_REASON_CODES } from "./composites";
14
+ import { COMPOSITES_ENVIRONMENT_REASON_CODES, COMPOSITES_ERROR_CODES, COMPOSITES_EXECUTOR_REASON_CODES, COMPOSITES_REASON_CODES, COMPOSITES_RUNTIME_REASON_CODES } from "./composites";
15
15
  import { WORKSPACE_ERROR_CODES } from "./declaration";
16
16
  import { GRAPH_ERROR_CODES } from "./graph-cli";
17
17
  import { INTENT_ERROR_CODES, INTENT_FINDING_CODES, INTENT_REASON_CODES, INTENT_WHY_CODES } from "./intent";
@@ -30,9 +30,12 @@ import { BOX_FINDING_CODES } from "./checks/boxes";
30
30
  import { DIAGRAM_FINDING_CODES } from "./checks/diagrams";
31
31
  import { SECURITY_FINDING_CODES } from "./checks/security";
32
32
  import { CI_WORKFLOW_FINDING_CODES } from "./ci-workflow";
33
+ import { CI_BRANCH_FINDING_CODES } from "./checks/ci-branch";
34
+ import { GATE_APPROVAL_FINDING_CODES } from "./checks/gate-approval";
33
35
  import { WORK_ERROR_CODES, WORK_HISTORY_ERROR_CODES, WORK_LEASE_REFUSALS } from "./work-cli";
34
36
  import { RUN_STATEMENT_ERROR_CODES, RUNS_ERROR_CODES, RUNS_REASON_CODES, RUNS_WRITE_ERROR_CODES } from "./runs-cli";
35
37
  import { RUN_STATEMENT_FAILURE_CODES } from "./trust/run-statement";
38
+ import { LEDGER_READ_ERROR_CODES } from "../lifecycle/ledger-read";
36
39
  import { WORK_EVIDENCE_ERROR_CODES } from "./work-evidence";
37
40
  import { RECORD_FINDING_CODES } from "./checks/records";
38
41
  import { ANSWER_WARNING_CODES } from "./points";
@@ -49,6 +52,7 @@ import { DECLARATION_WRITE_ERROR_CODES } from "./declaration-write";
49
52
  import { TRUST_WRITE_ERROR_CODES } from "./trust/trust-write";
50
53
  import { BOX_PUBLISH_ERROR_CODES } from "./box-publish";
51
54
  import { WRITE_LOCK_ERROR_CODES } from "./write-lock-cli";
55
+ import { EXIT_CODES } from "./exit";
52
56
  import { WIP_ERROR_CODES, WIP_WRITE_ERROR_CODES } from "./wip";
53
57
  import { CI_GREEN_ERROR_CODES } from "./ci-green";
54
58
  import { ROTATION_REFUSAL_CODES } from "./trust/rotation";
@@ -72,6 +76,8 @@ const PER_COMMAND: Record<string, readonly string[]> = {
72
76
  DIAGRAM_FINDING_CODES,
73
77
  SECURITY_FINDING_CODES,
74
78
  CI_WORKFLOW_FINDING_CODES,
79
+ CI_BRANCH_FINDING_CODES,
80
+ GATE_APPROVAL_FINDING_CODES,
75
81
  STATUS_REASON_CODES,
76
82
  STATUS_ERROR_CODES,
77
83
  STATUS_GATE_REASON_CODES,
@@ -100,6 +106,7 @@ const PER_COMMAND: Record<string, readonly string[]> = {
100
106
  COMPOSITES_REASON_CODES,
101
107
  COMPOSITES_RUNTIME_REASON_CODES,
102
108
  COMPOSITES_ENVIRONMENT_REASON_CODES,
109
+ COMPOSITES_EXECUTOR_REASON_CODES,
103
110
  WORK_ERROR_CODES,
104
111
  WORK_HISTORY_ERROR_CODES,
105
112
  WORK_LEASE_REFUSALS,
@@ -108,6 +115,7 @@ const PER_COMMAND: Record<string, readonly string[]> = {
108
115
  RUNS_WRITE_ERROR_CODES,
109
116
  RUN_STATEMENT_ERROR_CODES,
110
117
  RUN_STATEMENT_FAILURE_CODES,
118
+ LEDGER_READ_ERROR_CODES,
111
119
  WORK_EVIDENCE_ERROR_CODES,
112
120
  RECORD_FINDING_CODES,
113
121
  FLAG_WARNING_CODES,
@@ -139,6 +147,7 @@ const PER_COMMAND: Record<string, readonly string[]> = {
139
147
  SEARCH_MEMBER_REASON_CODES,
140
148
  CAPABILITIES_ERROR_CODES,
141
149
  CAPABILITY_SUPPORT_CODES,
150
+ EXIT_CODES,
142
151
  };
143
152
 
144
153
  /** Every string in an `enum` under a property named `code`, anywhere in a schema. */
@@ -66,6 +66,9 @@ export const REASONS = {
66
66
  // A ledger status can't fully read.
67
67
  "ledger-unreadable": "Reading the ledger failed, so nothing from it is listed.",
68
68
  "ledger-malformed": "Some lines of the ledger aren't release records; the rest are listed.",
69
+ // chant ledger (#4363): a read that can't start.
70
+ "filter-invalid": "A --where or --since names a field the read doesn't have, an operator its type doesn't take, or a value not of its type; nothing was read.",
71
+ "table-unknown": "chant ledger was given a table that is not one of resources, snapshots, runs, gates, deploys, releases or cuts.",
69
72
  // A member's gates status can't list (status, #2674).
70
73
  "gates-no-ledger": "The checkout has no chant/lifecycle branch, so there is no gate ledger to read.",
71
74
  "gates-no-gate-ledger": "The branch has no gate ledger for the member: no run of it has reached a gate.",
@@ -237,6 +240,9 @@ export const REASONS = {
237
240
  "environments-ledger-undeclared": "The member's ledger has releases in an environment its config's environments don't cover, so chant run --env would refuse it and it is not listed.",
238
241
  "environments-ledger-unreadable": "The chant/lifecycle branch exists and the member's ledger environments could not be listed.",
239
242
  "environments-component-undeclared": "A component declares an environment its member's chant.config.ts environments don't cover, so chant run --env would refuse it and it is not listed (#3153).",
243
+ // The forge workflow that deploys an environment (graph --composites, #4402): an environment row's executor.reason.
244
+ "executor-none-declared": "The member's chant.config.ts declares no executor for the environment, so nothing names the forge workflow that deploys it.",
245
+ "executor-config-unreadable": "The member's chant.config.ts could not be read, so whether a forge workflow deploys the environment is unknown.",
240
246
  // A declared diagram's source or render (check, #2764). Each is also a WSP finding.
241
247
  "diagram-source-missing": "A declared diagram's source file does not exist in the tree read.",
242
248
  "diagram-render-missing": "A declared diagram's render file does not exist in the tree read.",
@@ -269,6 +275,8 @@ export const REASONS = {
269
275
  "ci-workflow-pipeline-missing": "Under ci.workflow, no pipeline file runs the plan job, the merge job or chant ci tick.",
270
276
  "ci-workflow-pipeline-differs": "Under ci.workflow, the pipeline does not match the workflow: it applies on merge under trunk-curated, records under trunk-curated+apply-on-merge, or applies before merge, or fails to, against apply-before-merge.",
271
277
  "ci-workflow-publish-missing": "Under ci.workflow, no pipeline file runs chant release publish.",
278
+ "gate-approval-unbased": "An Op gate's approval block sets a quorum, policy, mode or context that identity.gates does not set at base, so the change being run can edit it.",
279
+ "ci-branch-route-differs": "A member's generated pull-request pipeline targets a branch other than the one ci.branches routes the member to.",
272
280
  // A box that holds a credential (check, #2726). Each is also a WSP finding.
273
281
  "box-credential-declared": "A file in a box member's directory carries a literal secret: a credential's shape, or a literal where a credential goes. A variable or secret-manager reference is not one.",
274
282
  "box-capability-unbrokered": "A capability in a member's box block names no broker, so the box would hold its credential.",
@@ -291,6 +299,10 @@ export const REASONS = {
291
299
  "lease-held": "Someone holds a live lease on the work item: another worker, or, for a claim, the same one.",
292
300
  "lease-not-held": "Nobody holds a live lease on the work item: it expired, was released or was never claimed.",
293
301
  "lease-token-mismatch": "The live lease on the work item carries another fencing token than the one given.",
302
+ // Evidence that cites an ops result (work evidence, #3171): why the citation was refused. Nothing is written.
303
+ "work-evidence-ops-missing": "Work evidence cites a run, deploy, gate answer or release plan the local chant/lifecycle branch does not hold.",
304
+ "work-evidence-ops-mismatch": "Work evidence cites an ops record that does not hash to the sha256 given, or a run whose outcome disagrees with the evidence's result.",
305
+ "work-evidence-ops-unfinished": "Work evidence cites a run that is still gated or waiting, so it has no outcome to show.",
294
306
  "lease-race": "Another writer changed the lease between this command's read and its write.",
295
307
  "lease-push-rejected": "The remote refused the lease push: another clone claimed the item first, or the remote could not be reached.",
296
308
  // The agent run record (chant workspace runs, #3033): why a write was refused, and what a read could not see. Nothing is written on a refusal.
@@ -365,6 +377,19 @@ export const REASONS = {
365
377
  // The lineage lock (check).
366
378
  "lock-invalid": "The lineage lock can't be read.",
367
379
  "manual-step-open": "A scope in the lineage lock has an open manual step.",
380
+ // workspace exit (#3177): why a member can't be exited, and what the exit drill finds wrong with one that was.
381
+ "missing-dir": "The chant member's directory does not exist, so there is nothing to build.",
382
+ "no-lexicon": "No lexicon is named in the member's chant.config.* or package.json, so there is nothing to build.",
383
+ "lexicon-unsupported": "A lexicon the member uses has no native target in workspace exit.",
384
+ "exit-failed": "The member's exit did not finish: its build failed, or it was refused.",
385
+ "choudoufu-steps-missing": "A choudoufu member's exit listed no roundtrip steps.",
386
+ "native-missing": "A native file the exit wrote is missing or empty.",
387
+ "native-unreadable": "A native file the exit wrote is not valid JSON, or has no content.",
388
+ "no-deploy-command": "A native file that can be deployed has no stock deploy command.",
389
+ "chant-config-left": "A chant.config.* file is still in the exited member.",
390
+ "chant-dependency": "The member's package.json still has a chant dependency, or a script that calls chant.",
391
+ "chant-in-ci": "A CI file of the exited member still calls chant.",
392
+ "declaration-not-other": "The declaration still gives the exited member a kind other than other.",
368
393
  } as const;
369
394
 
370
395
  export type ReasonCode = keyof typeof REASONS;
@@ -56,6 +56,7 @@ import {
56
56
  } from "./records";
57
57
  import { readCheckoutHead, worktreeStates, type CheckoutView, type WorktreeState } from "./records-checkout";
58
58
  import { lastWriteReader, type LastWrite } from "./write-lock";
59
+ import { FilterError, matchesWhere, parseWhere, type FilterFields, type WhereClause } from "../read-filter";
59
60
 
60
61
  function readTextOrNull(file: string): string | null {
61
62
  try {
@@ -78,7 +79,7 @@ export const RECORDS_CONTRACT_VERSION = 1;
78
79
  export const RECORDS_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/records/v1/records.schema.json";
79
80
 
80
81
  const USAGE =
81
- "chant workspace records [--kind <kind file>] [--current] [--uncommitted | --at <rev>] [--base <rev>] [--require attested] [--json] | chant workspace records [--kind <kind file>] --since <rev|session id> [--at <rev>] [--json] | chant workspace records pin <path> [--kind <kind file>] | chant workspace records new|amend|review|close (#2670, #2693)";
82
+ "chant workspace records [--kind <kind file>] [--current] [--uncommitted | --at <rev>] [--base <rev>] [--require attested] [--where <field><op><value>]... [--json] | chant workspace records [--kind <kind file>] --since <rev|session id> [--at <rev>] [--json] | chant workspace records pin <path> [--kind <kind file>] | chant workspace records new|amend|review|close (#2670, #2693)";
82
83
 
83
84
  /** Exit code when the read worked and a record falls below `--require`. */
84
85
  export const EXIT_BELOW_REQUIRED = 2;
@@ -196,6 +197,8 @@ export type RecordsDocument =
196
197
  summary: { total: number; valid: number; invalid: number; superseded: number };
197
198
  /** For a work kind (#2683): each decision its decision kind reads, with the work records implementing it. */
198
199
  decisions?: DecisionWork[];
200
+ /** The `--where` clauses the records were filtered with (#4363); absent without one. `summary` then counts the records listed. */
201
+ where?: string[];
199
202
  }
200
203
  | { $schema: string; contract: number; error: { code: ReadErrorCode; message: string } };
201
204
 
@@ -697,7 +700,12 @@ export async function runWorkspaceRecords(ctx: CommandContext): Promise<number>
697
700
  console.error(formatError({ message: pairing, hint: USAGE }));
698
701
  return 1;
699
702
  }
700
- if (!args.kind) return runDeclaredRecords(args);
703
+ const filter = recordsWhere(args);
704
+ if ("error" in filter) {
705
+ console.error(formatError({ message: filter.error, hint: USAGE }));
706
+ return 1;
707
+ }
708
+ if (!args.kind) return runDeclaredRecords(args, filter.clauses);
701
709
  if (args.require !== undefined && args.require !== "attested") {
702
710
  console.error(formatError({ message: `--require takes one level, attested, not ${JSON.stringify(args.require)}`, hint: USAGE }));
703
711
  return 1;
@@ -715,7 +723,7 @@ export async function runWorkspaceRecords(ctx: CommandContext): Promise<number>
715
723
  else console.log(formatSince(since));
716
724
  return "error" in since ? 1 : 0;
717
725
  }
718
- const doc = await queryRecords({ kind: args.kind, current: args.current, uncommitted: args.uncommitted, at: args.at, base: args.base, cwd: process.cwd(), fetchLedger: true });
726
+ const doc = filterRecordsDocument(await queryRecords({ kind: args.kind, current: args.current, uncommitted: args.uncommitted, at: args.at, base: args.base, cwd: process.cwd(), fetchLedger: true }), filter.clauses, args.where ?? []);
719
727
  if (args.json) {
720
728
  console.log(JSON.stringify(doc, null, 2));
721
729
  } else if ("error" in doc) {
@@ -756,7 +764,7 @@ export async function runWorkspaceRecords(ctx: CommandContext): Promise<number>
756
764
  * declaration-level code the schema doesn't carry (`declaration-invalid` and
757
765
  * the rest of `WorkspaceErrorCode`) still prints text on stderr only.
758
766
  */
759
- async function runDeclaredRecords(args: CommandContext["args"]): Promise<number> {
767
+ async function runDeclaredRecords(args: CommandContext["args"], clauses: readonly WhereClause[] = []): Promise<number> {
760
768
  if (args.require !== undefined && args.require !== "attested") {
761
769
  console.error(formatError({ message: `--require takes one level, attested, not ${JSON.stringify(args.require)}`, hint: USAGE }));
762
770
  return 1;
@@ -779,7 +787,9 @@ async function runDeclaredRecords(args: CommandContext["args"]): Promise<number>
779
787
  return 1;
780
788
  }
781
789
  if (args.since !== undefined) return runDeclaredSince(declared, args);
782
- const set = await queryDeclaredRecords(declared, { current: args.current, uncommitted: args.uncommitted, at: args.at, base: args.base, cwd: process.cwd(), fetchLedger: true });
790
+ const read = await queryDeclaredRecords(declared, { current: args.current, uncommitted: args.uncommitted, at: args.at, base: args.base, cwd: process.cwd(), fetchLedger: true });
791
+ // The spec stays the whole current spec; --where narrows only the records each kind lists.
792
+ const set = { ...read, kinds: read.kinds.map((k) => filterRecordsDocument(k, clauses, args.where ?? [])) };
783
793
  if (args.json) console.log(JSON.stringify(set, null, 2));
784
794
  for (const doc of args.json ? [] : set.kinds) {
785
795
  if ("error" in doc) {
@@ -854,6 +864,49 @@ export function belowRequired(records: RecordView[], required: ProvenanceLevel):
854
864
  }
855
865
 
856
866
  /** Why `--uncommitted` can't be given with the other flags given, or undefined when it can (#3160). */
867
+ /**
868
+ * The fields `records --where` filters on (#4363). `data` is the record's
869
+ * own fields, so `data.<key>` names any of them.
870
+ */
871
+ export const RECORD_FILTER_FIELDS: FilterFields = {
872
+ id: "text",
873
+ path: "text",
874
+ state: "text",
875
+ valid: "boolean",
876
+ supersededBy: "text",
877
+ digest: "text",
878
+ ready: "boolean",
879
+ attested: "boolean",
880
+ worktree: "text",
881
+ ledger: "text",
882
+ "provenance.level": "text",
883
+ data: "json",
884
+ };
885
+
886
+ /** Keep the records every clause matches, counting `summary` over the records listed. A failure is left as it is. */
887
+ export function filterRecordsDocument<D extends RecordsDocument>(doc: D, clauses: readonly WhereClause[], where: readonly string[]): D {
888
+ if (where.length === 0 || "error" in doc) return doc;
889
+ const records = doc.records.filter((r) => matchesWhere(r, clauses));
890
+ return {
891
+ ...doc,
892
+ records,
893
+ summary: { ...doc.summary, total: records.length, valid: records.filter((r) => r.valid).length, invalid: records.filter((r) => !r.valid).length },
894
+ where: [...where],
895
+ };
896
+ }
897
+
898
+ /** The `--where` clauses, or a message for a person. */
899
+ function recordsWhere(args: CommandContext["args"]): { clauses: WhereClause[] } | { error: string } {
900
+ const where = args.where ?? [];
901
+ if (where.length > 0 && args.since !== undefined) return { error: "--where filters a records read and takes no --since: --since compares two revisions" };
902
+ try {
903
+ return { clauses: parseWhere(where, RECORD_FILTER_FIELDS) };
904
+ } catch (err) {
905
+ if (err instanceof FilterError) return { error: err.message };
906
+ throw err;
907
+ }
908
+ }
909
+
857
910
  function uncommittedPairing(args: CommandContext["args"]): string | undefined {
858
911
  if (!args.uncommitted) return undefined;
859
912
  if (args.at !== undefined) return "--uncommitted reads the working tree against HEAD, and takes no --at";
@@ -152,6 +152,11 @@
152
152
  "description": "Added in contract 1 by #2683, for a work kind only. Every decision the kind file named in the work kind's work.decisions reads at the same revision, whether or not a work record names it, each with the work records implementing it. A decision with an empty implementedBy has no work item yet.",
153
153
  "type": "array",
154
154
  "items": { "$ref": "#/$defs/decisionWork" }
155
+ },
156
+ "where": {
157
+ "description": "Added in contract 1 by #4363. Each --where clause, <field><op><value>, as given; every one held for each record listed, and summary's total, valid and invalid count the records listed. Absent without --where.",
158
+ "type": "array",
159
+ "items": { "type": "string" }
155
160
  }
156
161
  },
157
162
  "allOf": [
@@ -39,7 +39,7 @@ import { latestPerComponent, readReleaseLedger } from "../lifecycle/release-ledg
39
39
  import { readAllReleases, readCuts } from "../lifecycle/release-store";
40
40
  import { resolveMemberLedger } from "../lifecycle/member-ledger";
41
41
  import { readBlobFromPath } from "../lifecycle/git";
42
- import { readerVersion } from "./declaration";
42
+ import { greenBranches, readerVersion } from "./declaration";
43
43
 
44
44
  export const RELEASE_CANDIDATES_CONTRACT_VERSION = 1;
45
45
  export const RELEASE_CANDIDATES_SCHEMA_ID = "https://intentius.io/chant/schemas/workspace/release-candidates/v1/release-candidates.schema.json";
@@ -145,6 +145,8 @@ export interface ReleaseCandidatesQuery {
145
145
  /** Only this environment's view: the walk stops at what it runs, and `newFor` names only it. */
146
146
  env?: string;
147
147
  limit?: number;
148
+ /** Walk this branch of `ci.green.branch` (#4325) instead of the first. */
149
+ branch?: string;
148
150
  }
149
151
 
150
152
  function git(top: string, args: string[]): string {
@@ -218,7 +220,10 @@ export async function releaseCandidatesDocument(query: ReleaseCandidatesQuery):
218
220
  const { commitDetails } = await import("./intent");
219
221
  const source = scopeSource(cwd);
220
222
  const green = source.declaration?.ci?.green ?? null;
221
- const trunk = resolveTrunk(top, green?.branch ?? null);
223
+ if (query.branch !== undefined && !(green && greenBranches(green).includes(query.branch))) {
224
+ throw new Error(`--branch ${query.branch} is not a branch ci.green judges${green ? ` (${greenBranches(green).join(", ")})` : ", and the declaration has no ci.green"}`);
225
+ }
226
+ const trunk = resolveTrunk(top, query.branch ?? green?.branch ?? null);
222
227
  const tip =
223
228
  tryGit(top, ["rev-parse", "--verify", "--quiet", `refs/remotes/${trunk.remote}/${trunk.branch}^{commit}`]) ??
224
229
  tryGit(top, ["rev-parse", "--verify", "--quiet", `refs/heads/${trunk.branch}^{commit}`]);