@intentius/chant 0.124.45 → 0.124.48

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 (772) 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/capabilities/aws.paths +148 -0
  47. package/dist/capabilities/base-mappings.json +122 -0
  48. package/dist/capabilities/catalog.d.ts +89 -0
  49. package/dist/capabilities/catalog.d.ts.map +1 -0
  50. package/dist/capabilities/catalog.js +204 -0
  51. package/dist/capabilities/language.d.ts +103 -0
  52. package/dist/capabilities/language.d.ts.map +1 -0
  53. package/dist/capabilities/language.js +335 -0
  54. package/dist/capabilities/matcher.d.ts +65 -0
  55. package/dist/capabilities/matcher.d.ts.map +1 -0
  56. package/dist/capabilities/matcher.js +299 -0
  57. package/dist/capabilities/view.d.ts +207 -0
  58. package/dist/capabilities/view.d.ts.map +1 -0
  59. package/dist/capabilities/view.js +484 -0
  60. package/dist/cli/commands/carve.d.ts +3 -0
  61. package/dist/cli/commands/carve.d.ts.map +1 -1
  62. package/dist/cli/commands/carve.js +36 -7
  63. package/dist/cli/commands/import-report.d.ts +26 -0
  64. package/dist/cli/commands/import-report.d.ts.map +1 -0
  65. package/dist/cli/commands/import-report.js +65 -0
  66. package/dist/cli/commands/import.d.ts +11 -1
  67. package/dist/cli/commands/import.d.ts.map +1 -1
  68. package/dist/cli/commands/import.js +22 -3
  69. package/dist/cli/commands/lint.d.ts.map +1 -1
  70. package/dist/cli/commands/lint.js +1 -0
  71. package/dist/cli/commands/migrate.d.ts +13 -1
  72. package/dist/cli/commands/migrate.d.ts.map +1 -1
  73. package/dist/cli/commands/migrate.js +134 -10
  74. package/dist/cli/handlers/approve.d.ts.map +1 -1
  75. package/dist/cli/handlers/approve.js +21 -2
  76. package/dist/cli/handlers/build.d.ts.map +1 -1
  77. package/dist/cli/handlers/build.js +6 -1
  78. package/dist/cli/handlers/declared-graph.d.ts +44 -0
  79. package/dist/cli/handlers/declared-graph.d.ts.map +1 -0
  80. package/dist/cli/handlers/declared-graph.js +87 -0
  81. package/dist/cli/handlers/graph.d.ts +25 -0
  82. package/dist/cli/handlers/graph.d.ts.map +1 -1
  83. package/dist/cli/handlers/graph.js +93 -87
  84. package/dist/cli/handlers/ledger.d.ts +3 -0
  85. package/dist/cli/handlers/ledger.d.ts.map +1 -0
  86. package/dist/cli/handlers/ledger.js +55 -0
  87. package/dist/cli/handlers/migrate.d.ts.map +1 -1
  88. package/dist/cli/handlers/migrate.js +18 -11
  89. package/dist/cli/handlers/misc.d.ts.map +1 -1
  90. package/dist/cli/handlers/misc.js +12 -1
  91. package/dist/cli/handlers/pr-env.d.ts.map +1 -1
  92. package/dist/cli/handlers/pr-env.js +4 -3
  93. package/dist/cli/handlers/pr.d.ts +15 -1
  94. package/dist/cli/handlers/pr.d.ts.map +1 -1
  95. package/dist/cli/handlers/pr.js +143 -39
  96. package/dist/cli/handlers/query.d.ts +7 -2
  97. package/dist/cli/handlers/query.d.ts.map +1 -1
  98. package/dist/cli/handlers/query.js +16 -4
  99. package/dist/cli/handlers/release.d.ts.map +1 -1
  100. package/dist/cli/handlers/release.js +6 -3
  101. package/dist/cli/handlers/search-count.d.ts +89 -0
  102. package/dist/cli/handlers/search-count.d.ts.map +1 -0
  103. package/dist/cli/handlers/search-count.js +132 -0
  104. package/dist/cli/handlers/search.d.ts +356 -6
  105. package/dist/cli/handlers/search.d.ts.map +1 -1
  106. package/dist/cli/handlers/search.js +1039 -155
  107. package/dist/cli/main.d.ts.map +1 -1
  108. package/dist/cli/main.js +88 -17
  109. package/dist/cli/mcp/server.d.ts.map +1 -1
  110. package/dist/cli/mcp/server.js +3 -0
  111. package/dist/cli/mcp/tools/capabilities.d.ts +7 -0
  112. package/dist/cli/mcp/tools/capabilities.d.ts.map +1 -0
  113. package/dist/cli/mcp/tools/capabilities.js +27 -0
  114. package/dist/cli/mcp/workspace-tools.d.ts +3 -1
  115. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  116. package/dist/cli/mcp/workspace-tools.js +47 -2
  117. package/dist/cli/parse-args.d.ts.map +1 -1
  118. package/dist/cli/parse-args.js +100 -19
  119. package/dist/cli/registry.d.ts +36 -4
  120. package/dist/cli/registry.d.ts.map +1 -1
  121. package/dist/components/builders.d.ts +5 -1
  122. package/dist/components/builders.d.ts.map +1 -1
  123. package/dist/components/builders.js +5 -0
  124. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  125. package/dist/components/capability-plugin-loader.js +16 -1
  126. package/dist/components/capability-plugin.d.ts +14 -0
  127. package/dist/components/capability-plugin.d.ts.map +1 -1
  128. package/dist/components/pr-env-ports.d.ts +29 -0
  129. package/dist/components/pr-env-ports.d.ts.map +1 -0
  130. package/dist/components/pr-env-ports.js +77 -0
  131. package/dist/components/pr-env-run.d.ts +5 -21
  132. package/dist/components/pr-env-run.d.ts.map +1 -1
  133. package/dist/components/pr-env-run.js +6 -70
  134. package/dist/components/pr-environment.d.ts +2 -1
  135. package/dist/components/pr-environment.d.ts.map +1 -1
  136. package/dist/components/pr-environment.js +1 -1
  137. package/dist/components/pr-hooks.d.ts +21 -1
  138. package/dist/components/pr-hooks.d.ts.map +1 -1
  139. package/dist/components/pr-hooks.js +72 -4
  140. package/dist/components/pr-pipeline.d.ts +45 -10
  141. package/dist/components/pr-pipeline.d.ts.map +1 -1
  142. package/dist/components/pr-pipeline.js +47 -14
  143. package/dist/components/pr-policy.d.ts +36 -0
  144. package/dist/components/pr-policy.d.ts.map +1 -1
  145. package/dist/components/pr-policy.js +36 -0
  146. package/dist/components/starter-plugin.d.ts +1 -0
  147. package/dist/components/starter-plugin.d.ts.map +1 -1
  148. package/dist/components/starter-plugin.js +5 -1
  149. package/dist/components/verbs/index.d.ts +2 -0
  150. package/dist/components/verbs/index.d.ts.map +1 -1
  151. package/dist/components/verbs/index.js +2 -0
  152. package/dist/components/verbs/publish-artifact.d.ts +65 -0
  153. package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
  154. package/dist/components/verbs/publish-artifact.js +74 -0
  155. package/dist/components/verbs/publish-image.d.ts +129 -0
  156. package/dist/components/verbs/publish-image.d.ts.map +1 -0
  157. package/dist/components/verbs/publish-image.js +145 -0
  158. package/dist/config-environments.d.ts +112 -0
  159. package/dist/config-environments.d.ts.map +1 -0
  160. package/dist/config-environments.js +114 -0
  161. package/dist/config.d.ts +32 -84
  162. package/dist/config.d.ts.map +1 -1
  163. package/dist/config.js +13 -96
  164. package/dist/gate-decision.d.ts +11 -2
  165. package/dist/gate-decision.d.ts.map +1 -1
  166. package/dist/gate-decision.js +15 -3
  167. package/dist/graph-detail.d.ts.map +1 -1
  168. package/dist/graph-detail.js +15 -3
  169. package/dist/graph-effective.d.ts +33 -2
  170. package/dist/graph-effective.d.ts.map +1 -1
  171. package/dist/graph-effective.js +215 -68
  172. package/dist/graph-ir.d.ts +48 -0
  173. package/dist/graph-ir.d.ts.map +1 -1
  174. package/dist/graph-ir.js +130 -0
  175. package/dist/graph-sub-template.d.ts +11 -0
  176. package/dist/graph-sub-template.d.ts.map +1 -0
  177. package/dist/graph-sub-template.js +19 -0
  178. package/dist/graph-walk.d.ts +66 -0
  179. package/dist/graph-walk.d.ts.map +1 -0
  180. package/dist/graph-walk.js +70 -0
  181. package/dist/import/parser.d.ts +19 -0
  182. package/dist/import/parser.d.ts.map +1 -1
  183. package/dist/lexicon.d.ts +80 -6
  184. package/dist/lexicon.d.ts.map +1 -1
  185. package/dist/lifecycle/gate-ledger.d.ts +11 -0
  186. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  187. package/dist/lifecycle/git.d.ts +2 -5
  188. package/dist/lifecycle/git.d.ts.map +1 -1
  189. package/dist/lifecycle/ledger-read.d.ts +65 -0
  190. package/dist/lifecycle/ledger-read.d.ts.map +1 -0
  191. package/dist/lifecycle/ledger-read.js +160 -0
  192. package/dist/lifecycle/observe.d.ts +28 -0
  193. package/dist/lifecycle/observe.d.ts.map +1 -1
  194. package/dist/lifecycle/observe.js +23 -1
  195. package/dist/lifecycle/release-workstation.d.ts +7 -0
  196. package/dist/lifecycle/release-workstation.d.ts.map +1 -1
  197. package/dist/lifecycle/release-workstation.js +25 -0
  198. package/dist/lifecycle/run-ledger.d.ts +4 -3
  199. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  200. package/dist/lifecycle/run-ledger.js +1 -0
  201. package/dist/lint/discover.js +3 -1
  202. package/dist/lint/post-synth.d.ts +127 -1
  203. package/dist/lint/post-synth.d.ts.map +1 -1
  204. package/dist/lint/post-synth.js +84 -2
  205. package/dist/lint/rule.d.ts +6 -0
  206. package/dist/lint/rule.d.ts.map +1 -1
  207. package/dist/lint/rules/op/index.d.ts +1 -0
  208. package/dist/lint/rules/op/index.d.ts.map +1 -1
  209. package/dist/lint/rules/op/index.js +2 -0
  210. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
  211. package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
  212. package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
  213. package/dist/live-endpoint.d.ts +1 -1
  214. package/dist/live-endpoint.d.ts.map +1 -1
  215. package/dist/live-endpoint.js +1 -1
  216. package/dist/observation.d.ts +48 -1
  217. package/dist/observation.d.ts.map +1 -1
  218. package/dist/observation.js +21 -5
  219. package/dist/op/activities/activity-contracts.d.ts +9 -6
  220. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  221. package/dist/op/activities/activity-contracts.js +5 -2
  222. package/dist/op/activities/index.d.ts +2 -2
  223. package/dist/op/activities/index.d.ts.map +1 -1
  224. package/dist/op/activities/index.js +1 -1
  225. package/dist/op/activities/review-agent.d.ts +90 -4
  226. package/dist/op/activities/review-agent.d.ts.map +1 -1
  227. package/dist/op/activities/review-agent.js +217 -19
  228. package/dist/op/activities/work-evidence.d.ts +8 -1
  229. package/dist/op/activities/work-evidence.d.ts.map +1 -1
  230. package/dist/op/activities/work-evidence.js +1 -0
  231. package/dist/op/builders.d.ts +9 -5
  232. package/dist/op/builders.d.ts.map +1 -1
  233. package/dist/op/builders.js +9 -5
  234. package/dist/op/composites/apply-op.d.ts +29 -2
  235. package/dist/op/composites/apply-op.d.ts.map +1 -1
  236. package/dist/op/composites/apply-op.js +20 -1
  237. package/dist/op/gate-approval.d.ts +11 -5
  238. package/dist/op/gate-approval.d.ts.map +1 -1
  239. package/dist/op/gate-approval.js +11 -6
  240. package/dist/op/gate-quorum.d.ts +100 -3
  241. package/dist/op/gate-quorum.d.ts.map +1 -1
  242. package/dist/op/gate-quorum.js +108 -6
  243. package/dist/op/gate-review.d.ts +9 -0
  244. package/dist/op/gate-review.d.ts.map +1 -1
  245. package/dist/op/gate-review.js +13 -0
  246. package/dist/op/gate.d.ts +44 -3
  247. package/dist/op/gate.d.ts.map +1 -1
  248. package/dist/op/gate.js +25 -4
  249. package/dist/op/index.d.ts +3 -3
  250. package/dist/op/index.d.ts.map +1 -1
  251. package/dist/op/index.js +1 -1
  252. package/dist/op/local-executor.d.ts +38 -3
  253. package/dist/op/local-executor.d.ts.map +1 -1
  254. package/dist/op/local-executor.js +48 -6
  255. package/dist/op/op-waves-run.d.ts +26 -1
  256. package/dist/op/op-waves-run.d.ts.map +1 -1
  257. package/dist/op/op-waves-run.js +259 -13
  258. package/dist/op/op-waves.d.ts +72 -5
  259. package/dist/op/op-waves.d.ts.map +1 -1
  260. package/dist/op/op-waves.js +110 -15
  261. package/dist/op/runtime.d.ts +11 -0
  262. package/dist/op/runtime.d.ts.map +1 -1
  263. package/dist/op/schedule-overdue.d.ts +16 -0
  264. package/dist/op/schedule-overdue.d.ts.map +1 -1
  265. package/dist/op/schedule-overdue.js +36 -0
  266. package/dist/op/stage-hooks.d.ts +9 -2
  267. package/dist/op/stage-hooks.d.ts.map +1 -1
  268. package/dist/op/stage-hooks.js +7 -5
  269. package/dist/op/workspace-run-env.d.ts +22 -0
  270. package/dist/op/workspace-run-env.d.ts.map +1 -0
  271. package/dist/op/workspace-run-env.js +21 -0
  272. package/dist/pr-forge.d.ts +24 -0
  273. package/dist/pr-forge.d.ts.map +1 -1
  274. package/dist/pr-forge.js +47 -0
  275. package/dist/pr-post.d.ts +42 -0
  276. package/dist/pr-post.d.ts.map +1 -1
  277. package/dist/pr-post.js +67 -1
  278. package/dist/read-filter.d.ts +65 -0
  279. package/dist/read-filter.d.ts.map +1 -0
  280. package/dist/read-filter.js +179 -0
  281. package/dist/run-event.d.ts +1 -1
  282. package/dist/run-event.d.ts.map +1 -1
  283. package/dist/terraform/carve.d.ts +24 -3
  284. package/dist/terraform/carve.d.ts.map +1 -1
  285. package/dist/terraform/carve.js +32 -14
  286. package/dist/terraform/cuts.d.ts +97 -0
  287. package/dist/terraform/cuts.d.ts.map +1 -0
  288. package/dist/terraform/cuts.js +138 -0
  289. package/dist/terraform/folds.d.ts +26 -0
  290. package/dist/terraform/folds.d.ts.map +1 -0
  291. package/dist/terraform/folds.js +38 -0
  292. package/dist/terraform/graph.d.ts.map +1 -1
  293. package/dist/terraform/graph.js +10 -0
  294. package/dist/terraform/reach.d.ts +140 -0
  295. package/dist/terraform/reach.d.ts.map +1 -0
  296. package/dist/terraform/reach.js +170 -0
  297. package/dist/terraform/score.d.ts +14 -0
  298. package/dist/terraform/score.d.ts.map +1 -1
  299. package/dist/terraform/score.js +14 -31
  300. package/dist/terraform/state.d.ts.map +1 -1
  301. package/dist/terraform/state.js +4 -2
  302. package/dist/terraform/types.d.ts +8 -0
  303. package/dist/terraform/types.d.ts.map +1 -1
  304. package/dist/wave-blocked.d.ts +10 -1
  305. package/dist/wave-blocked.d.ts.map +1 -1
  306. package/dist/wave-blocked.js +31 -3
  307. package/dist/wave-runtime.mjs +266 -256
  308. package/dist/workspace/capabilities-contract.d.ts +66 -0
  309. package/dist/workspace/capabilities-contract.d.ts.map +1 -0
  310. package/dist/workspace/capabilities-contract.js +107 -0
  311. package/dist/workspace/capabilities.schema.json +229 -0
  312. package/dist/workspace/check.schema.json +11 -2
  313. package/dist/workspace/checks/ci-branch.d.ts +44 -0
  314. package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
  315. package/dist/workspace/checks/ci-branch.js +133 -0
  316. package/dist/workspace/checks/links.d.ts +3 -0
  317. package/dist/workspace/checks/links.d.ts.map +1 -1
  318. package/dist/workspace/checks/links.js +12 -1
  319. package/dist/workspace/checks/org.d.ts +48 -0
  320. package/dist/workspace/checks/org.d.ts.map +1 -0
  321. package/dist/workspace/checks/org.js +156 -0
  322. package/dist/workspace/checks.d.ts +11 -1
  323. package/dist/workspace/checks.d.ts.map +1 -1
  324. package/dist/workspace/checks.js +59 -7
  325. package/dist/workspace/ci-branches.d.ts +16 -0
  326. package/dist/workspace/ci-branches.d.ts.map +1 -1
  327. package/dist/workspace/ci-branches.js +27 -0
  328. package/dist/workspace/ci-green-cli.js +7 -7
  329. package/dist/workspace/ci-green-workflow.d.ts +1 -1
  330. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  331. package/dist/workspace/ci-green-workflow.js +13 -8
  332. package/dist/workspace/ci-green.d.ts +14 -0
  333. package/dist/workspace/ci-green.d.ts.map +1 -1
  334. package/dist/workspace/ci-green.js +44 -11
  335. package/dist/workspace/ci-run.d.ts +9 -1
  336. package/dist/workspace/ci-run.d.ts.map +1 -1
  337. package/dist/workspace/ci-run.js +67 -6
  338. package/dist/workspace/ci-serve.d.ts +9 -0
  339. package/dist/workspace/ci-serve.d.ts.map +1 -1
  340. package/dist/workspace/ci-serve.js +114 -76
  341. package/dist/workspace/compose-graph.d.ts +23 -0
  342. package/dist/workspace/compose-graph.d.ts.map +1 -1
  343. package/dist/workspace/compose-graph.js +3 -1
  344. package/dist/workspace/composites.d.ts +4 -1
  345. package/dist/workspace/composites.d.ts.map +1 -1
  346. package/dist/workspace/composites.js +5 -2
  347. package/dist/workspace/composites.schema.json +22 -0
  348. package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  349. package/dist/workspace/conformance/index.d.ts +1 -1
  350. package/dist/workspace/conformance/index.d.ts.map +1 -1
  351. package/dist/workspace/conformance/index.js +39 -2
  352. package/dist/workspace/cross-root-lint.d.ts +56 -0
  353. package/dist/workspace/cross-root-lint.d.ts.map +1 -0
  354. package/dist/workspace/cross-root-lint.js +111 -0
  355. package/dist/workspace/dbt-models-reader.d.ts +44 -0
  356. package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
  357. package/dist/workspace/dbt-models-reader.js +356 -0
  358. package/dist/workspace/dbt-project-common.d.ts +40 -0
  359. package/dist/workspace/dbt-project-common.d.ts.map +1 -0
  360. package/dist/workspace/dbt-project-common.js +106 -0
  361. package/dist/workspace/dbt-project-reader.d.ts +4 -3
  362. package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
  363. package/dist/workspace/dbt-project-reader.js +14 -108
  364. package/dist/workspace/decision-rank.d.ts +26 -0
  365. package/dist/workspace/decision-rank.d.ts.map +1 -0
  366. package/dist/workspace/decision-rank.js +16 -0
  367. package/dist/workspace/declaration.d.ts +43 -2
  368. package/dist/workspace/declaration.d.ts.map +1 -1
  369. package/dist/workspace/declaration.js +45 -11
  370. package/dist/workspace/declaration.schema.json +133 -24
  371. package/dist/workspace/environments.d.ts +26 -2
  372. package/dist/workspace/environments.d.ts.map +1 -1
  373. package/dist/workspace/environments.js +26 -2
  374. package/dist/workspace/flyway-dir.d.ts +39 -0
  375. package/dist/workspace/flyway-dir.d.ts.map +1 -0
  376. package/dist/workspace/flyway-dir.js +104 -0
  377. package/dist/workspace/flyway-layout.d.ts +96 -0
  378. package/dist/workspace/flyway-layout.d.ts.map +1 -0
  379. package/dist/workspace/flyway-layout.js +308 -0
  380. package/dist/workspace/graph-cache.d.ts +8 -0
  381. package/dist/workspace/graph-cache.d.ts.map +1 -1
  382. package/dist/workspace/graph-cache.js +27 -3
  383. package/dist/workspace/graph-cli.d.ts +39 -2
  384. package/dist/workspace/graph-cli.d.ts.map +1 -1
  385. package/dist/workspace/graph-cli.js +92 -32
  386. package/dist/workspace/graph.schema.json +182 -0
  387. package/dist/workspace/intent.d.ts +2 -3
  388. package/dist/workspace/intent.d.ts.map +1 -1
  389. package/dist/workspace/intent.js +5 -9
  390. package/dist/workspace/kind-link-readers.d.ts +59 -2
  391. package/dist/workspace/kind-link-readers.d.ts.map +1 -1
  392. package/dist/workspace/kind-link-readers.js +17 -1
  393. package/dist/workspace/kind-readers.d.ts +3 -0
  394. package/dist/workspace/kind-readers.d.ts.map +1 -1
  395. package/dist/workspace/kind-readers.js +7 -1
  396. package/dist/workspace/kinds.d.ts +66 -2
  397. package/dist/workspace/kinds.d.ts.map +1 -1
  398. package/dist/workspace/kinds.js +98 -4
  399. package/dist/workspace/ledger.schema.json +158 -0
  400. package/dist/workspace/lexicon-outputs.d.ts +20 -1
  401. package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
  402. package/dist/workspace/lexicon-outputs.js +102 -10
  403. package/dist/workspace/lineage-check.d.ts +3 -0
  404. package/dist/workspace/lineage-check.d.ts.map +1 -1
  405. package/dist/workspace/lineage-check.js +23 -4
  406. package/dist/workspace/links.d.ts +8 -1
  407. package/dist/workspace/links.d.ts.map +1 -1
  408. package/dist/workspace/links.js +25 -1
  409. package/dist/workspace/ls.d.ts +8 -0
  410. package/dist/workspace/ls.d.ts.map +1 -1
  411. package/dist/workspace/ls.js +7 -1
  412. package/dist/workspace/ls.schema.json +7 -0
  413. package/dist/workspace/member-commands.d.ts +10 -1
  414. package/dist/workspace/member-commands.d.ts.map +1 -1
  415. package/dist/workspace/member-commands.js +71 -6
  416. package/dist/workspace/migrate-links.d.ts +45 -0
  417. package/dist/workspace/migrate-links.d.ts.map +1 -0
  418. package/dist/workspace/migrate-links.js +100 -0
  419. package/dist/workspace/migration-dirs.d.ts +74 -0
  420. package/dist/workspace/migration-dirs.d.ts.map +1 -0
  421. package/dist/workspace/migration-dirs.js +254 -0
  422. package/dist/workspace/nested-graph.d.ts +2 -0
  423. package/dist/workspace/nested-graph.d.ts.map +1 -1
  424. package/dist/workspace/nested-graph.js +32 -1
  425. package/dist/workspace/reason-codes.d.ts +18 -0
  426. package/dist/workspace/reason-codes.d.ts.map +1 -1
  427. package/dist/workspace/reason-codes.js +23 -0
  428. package/dist/workspace/records-cli.d.ts +11 -0
  429. package/dist/workspace/records-cli.d.ts.map +1 -1
  430. package/dist/workspace/records-cli.js +57 -5
  431. package/dist/workspace/records.schema.json +5 -0
  432. package/dist/workspace/release-candidates.d.ts +2 -0
  433. package/dist/workspace/release-candidates.d.ts.map +1 -1
  434. package/dist/workspace/release-candidates.js +5 -2
  435. package/dist/workspace/release-train.d.ts +53 -0
  436. package/dist/workspace/release-train.d.ts.map +1 -0
  437. package/dist/workspace/release-train.js +134 -0
  438. package/dist/workspace/release-workflow.d.ts.map +1 -1
  439. package/dist/workspace/release-workflow.js +4 -3
  440. package/dist/workspace/repo-ref.d.ts +45 -0
  441. package/dist/workspace/repo-ref.d.ts.map +1 -0
  442. package/dist/workspace/repo-ref.js +114 -0
  443. package/dist/workspace/run-event.schema.json +2 -2
  444. package/dist/workspace/runs-cli.d.ts +9 -0
  445. package/dist/workspace/runs-cli.d.ts.map +1 -1
  446. package/dist/workspace/runs-cli.js +48 -3
  447. package/dist/workspace/runs.schema.json +7 -0
  448. package/dist/workspace/search-cli.d.ts +204 -0
  449. package/dist/workspace/search-cli.d.ts.map +1 -0
  450. package/dist/workspace/search-cli.js +466 -0
  451. package/dist/workspace/search-contract.d.ts +56 -0
  452. package/dist/workspace/search-contract.d.ts.map +1 -0
  453. package/dist/workspace/search-contract.js +70 -0
  454. package/dist/workspace/search.schema.json +822 -0
  455. package/dist/workspace/status-decisions.d.ts +37 -0
  456. package/dist/workspace/status-decisions.d.ts.map +1 -0
  457. package/dist/workspace/status-decisions.js +147 -0
  458. package/dist/workspace/status-gates.d.ts +9 -0
  459. package/dist/workspace/status-gates.d.ts.map +1 -1
  460. package/dist/workspace/status.d.ts +4 -0
  461. package/dist/workspace/status.d.ts.map +1 -1
  462. package/dist/workspace/status.js +14 -2
  463. package/dist/workspace/status.schema.json +6 -0
  464. package/dist/workspace/work-cli.d.ts.map +1 -1
  465. package/dist/workspace/work-cli.js +5 -3
  466. package/dist/workspace/work-evidence-ops.d.ts +83 -0
  467. package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
  468. package/dist/workspace/work-evidence-ops.js +169 -0
  469. package/dist/workspace/work-evidence.d.ts +12 -2
  470. package/dist/workspace/work-evidence.d.ts.map +1 -1
  471. package/dist/workspace/work-evidence.js +21 -3
  472. package/dist/workspace/work-evidence.schema.json +49 -2
  473. package/dist/workspace/workspace-gates.d.ts +110 -0
  474. package/dist/workspace/workspace-gates.d.ts.map +1 -0
  475. package/dist/workspace/workspace-gates.js +140 -0
  476. package/dist/workspace/workspace-kinds.schema.json +58 -3
  477. package/dist/workspace/workspace-ledger.d.ts +76 -0
  478. package/dist/workspace/workspace-ledger.d.ts.map +1 -0
  479. package/dist/workspace/workspace-ledger.js +91 -0
  480. package/dist/workspace/workspace-run.d.ts +112 -0
  481. package/dist/workspace/workspace-run.d.ts.map +1 -0
  482. package/dist/workspace/workspace-run.js +432 -0
  483. package/package.json +1 -1
  484. package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
  485. package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
  486. package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
  487. package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
  488. package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
  489. package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
  490. package/src/__golden__/wave-loop/op-cost-member.json +13 -0
  491. package/src/__golden__/wave-loop/op-denied-source.json +16 -0
  492. package/src/__golden__/wave-loop/op-denied.json +16 -0
  493. package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
  494. package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
  495. package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
  496. package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
  497. package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
  498. package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
  499. package/src/__golden__/wave-loop/op-held-on.json +16 -0
  500. package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
  501. package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
  502. package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
  503. package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
  504. package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
  505. package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
  506. package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
  507. package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
  508. package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
  509. package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
  510. package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
  511. package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
  512. package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
  513. package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
  514. package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
  515. package/src/__golden__/wave-loop/op-overridden.json +16 -0
  516. package/src/__golden__/wave-loop/op-per-run.json +20 -0
  517. package/src/__golden__/wave-loop/op-point.json +13 -0
  518. package/src/__golden__/wave-loop/op-pr-review.json +10 -0
  519. package/src/__golden__/wave-loop/op-sealed.json +10 -0
  520. package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
  521. package/src/__golden__/wave-loop/op-spend.json +10 -0
  522. package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
  523. package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
  524. package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
  525. package/src/__golden__/wave-loop/op-wide.json +39 -0
  526. package/src/__snapshots__/okf.test.ts.snap +10 -0
  527. package/src/action-pins.test.ts +78 -0
  528. package/src/action-pins.ts +92 -0
  529. package/src/capabilities/aws.paths +148 -0
  530. package/src/capabilities/base-mappings.json +122 -0
  531. package/src/capabilities/catalog.ts +230 -0
  532. package/src/capabilities/language.test.ts +191 -0
  533. package/src/capabilities/language.ts +373 -0
  534. package/src/capabilities/matcher.ts +315 -0
  535. package/src/capabilities/view-compose.test.ts +76 -0
  536. package/src/capabilities/view.ts +631 -0
  537. package/src/cli/commands/carve-score-once.test.ts +99 -0
  538. package/src/cli/commands/carve.ts +37 -6
  539. package/src/cli/commands/check-lexicon.test.ts +2 -2
  540. package/src/cli/commands/import-report.ts +71 -0
  541. package/src/cli/commands/import.ts +33 -3
  542. package/src/cli/commands/lint.ts +1 -0
  543. package/src/cli/commands/migrate-dialect.test.ts +145 -0
  544. package/src/cli/commands/migrate.ts +132 -11
  545. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
  546. package/src/cli/handlers/approve.ts +23 -2
  547. package/src/cli/handlers/build.ts +7 -1
  548. package/src/cli/handlers/declared-graph.ts +99 -0
  549. package/src/cli/handlers/graph.test.ts +94 -3
  550. package/src/cli/handlers/graph.ts +123 -96
  551. package/src/cli/handlers/ledger.ts +54 -0
  552. package/src/cli/handlers/migrate.ts +21 -12
  553. package/src/cli/handlers/misc.ts +10 -1
  554. package/src/cli/handlers/pr-env.ts +3 -4
  555. package/src/cli/handlers/pr.ts +138 -36
  556. package/src/cli/handlers/query.ts +16 -4
  557. package/src/cli/handlers/release.ts +6 -3
  558. package/src/cli/handlers/search-build-roots.test.ts +144 -0
  559. package/src/cli/handlers/search-count.test.ts +191 -0
  560. package/src/cli/handlers/search-count.ts +165 -0
  561. package/src/cli/handlers/search-json.test.ts +333 -0
  562. package/src/cli/handlers/search-live.test.ts +387 -0
  563. package/src/cli/handlers/search-paths.test.ts +235 -0
  564. package/src/cli/handlers/search.ts +1291 -166
  565. package/src/cli/main.test.ts +43 -3
  566. package/src/cli/main.ts +88 -17
  567. package/src/cli/mcp/server.test.ts +3 -3
  568. package/src/cli/mcp/server.ts +3 -0
  569. package/src/cli/mcp/tools/capabilities.ts +32 -0
  570. package/src/cli/mcp/workspace-tools.e2e.test.ts +21 -1
  571. package/src/cli/mcp/workspace-tools.ts +47 -2
  572. package/src/cli/parse-args.ts +79 -15
  573. package/src/cli/registry.ts +36 -4
  574. package/src/components/builders.ts +8 -0
  575. package/src/components/capability-plugin-loader.ts +13 -1
  576. package/src/components/capability-plugin.ts +16 -0
  577. package/src/components/pr-env-ports.ts +89 -0
  578. package/src/components/pr-env-run-bundle.test.ts +54 -0
  579. package/src/components/pr-env-run.ts +5 -76
  580. package/src/components/pr-environment.ts +2 -1
  581. package/src/components/pr-hooks.test.ts +73 -5
  582. package/src/components/pr-hooks.ts +95 -5
  583. package/src/components/pr-pipeline.ts +64 -16
  584. package/src/components/pr-policy.test.ts +64 -1
  585. package/src/components/pr-policy.ts +53 -0
  586. package/src/components/registry.test.ts +1 -1
  587. package/src/components/starter-plugin.ts +6 -0
  588. package/src/components/verbs/index.ts +2 -0
  589. package/src/components/verbs/publish-artifact.test.ts +60 -0
  590. package/src/components/verbs/publish-artifact.ts +122 -0
  591. package/src/components/verbs/publish-image.test.ts +101 -0
  592. package/src/components/verbs/publish-image.ts +265 -0
  593. package/src/config-environments.ts +160 -0
  594. package/src/config.ts +44 -124
  595. package/src/gate-decision-bundle.test.ts +1 -0
  596. package/src/gate-decision-identity.test.ts +9 -0
  597. package/src/gate-decision.ts +26 -3
  598. package/src/graph-detail.ts +15 -3
  599. package/src/graph-effective.ts +226 -75
  600. package/src/graph-ir.test.ts +163 -0
  601. package/src/graph-ir.ts +174 -0
  602. package/src/graph-sub-template.ts +22 -0
  603. package/src/graph-walk.test.ts +44 -0
  604. package/src/graph-walk.ts +102 -0
  605. package/src/import/parser.ts +20 -0
  606. package/src/lexicon.ts +84 -6
  607. package/src/lifecycle/gate-ledger.ts +8 -0
  608. package/src/lifecycle/git.ts +2 -2
  609. package/src/lifecycle/ledger-read.test.ts +107 -0
  610. package/src/lifecycle/ledger-read.ts +195 -0
  611. package/src/lifecycle/observe.test.ts +27 -1
  612. package/src/lifecycle/observe.ts +43 -1
  613. package/src/lifecycle/release-workstation.ts +24 -0
  614. package/src/lifecycle/run-ledger.ts +5 -2
  615. package/src/lint/cross-root.test.ts +122 -0
  616. package/src/lint/discover.ts +3 -1
  617. package/src/lint/post-synth.ts +212 -2
  618. package/src/lint/rule.ts +6 -0
  619. package/src/lint/rules/op/index.ts +2 -0
  620. package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
  621. package/src/live-endpoint.ts +1 -1
  622. package/src/observation.test.ts +25 -0
  623. package/src/observation.ts +69 -5
  624. package/src/op/activities/activity-contracts.ts +5 -2
  625. package/src/op/activities/index.ts +2 -2
  626. package/src/op/activities/review-agent.test.ts +221 -4
  627. package/src/op/activities/review-agent.ts +265 -22
  628. package/src/op/activities/work-evidence.ts +9 -1
  629. package/src/op/builders.ts +9 -5
  630. package/src/op/composites/apply-op.test.ts +108 -0
  631. package/src/op/composites/apply-op.ts +37 -2
  632. package/src/op/gate-approval.test.ts +6 -1
  633. package/src/op/gate-approval.ts +12 -6
  634. package/src/op/gate-quorum-at-base.test.ts +211 -0
  635. package/src/op/gate-quorum.ts +156 -8
  636. package/src/op/gate-review.ts +14 -0
  637. package/src/op/gate.ts +67 -8
  638. package/src/op/index.ts +3 -2
  639. package/src/op/local-executor.ts +69 -9
  640. package/src/op/op-waves-depends-on.test.ts +81 -0
  641. package/src/op/op-waves-hook-targets.test.ts +4 -2
  642. package/src/op/op-waves-quorum-product.test.ts +158 -0
  643. package/src/op/op-waves-run.ts +288 -14
  644. package/src/op/op-waves.ts +143 -14
  645. package/src/op/runtime.ts +8 -0
  646. package/src/op/schedule-overdue.ts +33 -0
  647. package/src/op/stage-hooks.ts +13 -5
  648. package/src/op/workspace-run-env.ts +29 -0
  649. package/src/pr-forge-bundle.test.ts +2 -2
  650. package/src/pr-forge.test.ts +47 -0
  651. package/src/pr-forge.ts +68 -0
  652. package/src/pr-post-open.e2e.test.ts +36 -0
  653. package/src/pr-post.test.ts +102 -3
  654. package/src/pr-post.ts +89 -1
  655. package/src/read-filter.test.ts +54 -0
  656. package/src/read-filter.ts +193 -0
  657. package/src/run-event.ts +1 -1
  658. package/src/stage-hooks-bundle.test.ts +1 -0
  659. package/src/terraform/carve.ts +52 -15
  660. package/src/terraform/cuts.test.ts +173 -0
  661. package/src/terraform/cuts.ts +188 -0
  662. package/src/terraform/folds.ts +44 -0
  663. package/src/terraform/graph.ts +9 -0
  664. package/src/terraform/radius.test.ts +90 -0
  665. package/src/terraform/reach.test.ts +146 -0
  666. package/src/terraform/reach.ts +247 -0
  667. package/src/terraform/score.ts +27 -29
  668. package/src/terraform/state.ts +3 -1
  669. package/src/terraform/types.ts +8 -0
  670. package/src/wave-blocked.ts +28 -3
  671. package/src/wave-loop-golden.test.ts +4 -3
  672. package/src/workspace/behold-kinds.test.ts +1 -1
  673. package/src/workspace/capabilities-contract.test.ts +88 -0
  674. package/src/workspace/capabilities-contract.ts +132 -0
  675. package/src/workspace/capabilities.schema.json +229 -0
  676. package/src/workspace/check-contract.test.ts +7 -6
  677. package/src/workspace/check.schema.json +11 -2
  678. package/src/workspace/checks/ci-branch.test.ts +128 -0
  679. package/src/workspace/checks/ci-branch.ts +141 -0
  680. package/src/workspace/checks/links.ts +12 -1
  681. package/src/workspace/checks/org.ts +169 -0
  682. package/src/workspace/checks.ts +64 -7
  683. package/src/workspace/ci-branches.ts +31 -0
  684. package/src/workspace/ci-green-branches.test.ts +153 -0
  685. package/src/workspace/ci-green-cli.ts +7 -7
  686. package/src/workspace/ci-green-workflow.test.ts +4 -3
  687. package/src/workspace/ci-green-workflow.ts +13 -9
  688. package/src/workspace/ci-green.ts +49 -12
  689. package/src/workspace/ci-run.test.ts +72 -1
  690. package/src/workspace/ci-run.ts +68 -8
  691. package/src/workspace/ci-serve.test.ts +95 -0
  692. package/src/workspace/ci-serve.ts +106 -65
  693. package/src/workspace/component-environments.test.ts +25 -2
  694. package/src/workspace/compose-graph.ts +19 -3
  695. package/src/workspace/composites.schema.json +22 -0
  696. package/src/workspace/composites.test.ts +39 -8
  697. package/src/workspace/composites.ts +6 -2
  698. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
  699. package/src/workspace/conformance/conformance.e2e.test.ts +14 -1
  700. package/src/workspace/conformance/index.ts +31 -2
  701. package/src/workspace/cross-root-lint.test.ts +90 -0
  702. package/src/workspace/cross-root-lint.ts +126 -0
  703. package/src/workspace/dbt-kind.test.ts +3 -2
  704. package/src/workspace/dbt-models-reader.ts +362 -0
  705. package/src/workspace/dbt-models.test.ts +248 -0
  706. package/src/workspace/dbt-project-common.ts +113 -0
  707. package/src/workspace/dbt-project-reader.ts +29 -112
  708. package/src/workspace/decision-rank.ts +40 -0
  709. package/src/workspace/declaration.schema.json +133 -24
  710. package/src/workspace/declaration.ts +84 -15
  711. package/src/workspace/environments.ts +40 -4
  712. package/src/workspace/flyway-dir.ts +113 -0
  713. package/src/workspace/flyway-layout.ts +337 -0
  714. package/src/workspace/graph-cache.ts +27 -3
  715. package/src/workspace/graph-cli.ts +119 -32
  716. package/src/workspace/graph-contract.test.ts +4 -2
  717. package/src/workspace/graph.schema.json +182 -0
  718. package/src/workspace/identity.test.ts +14 -2
  719. package/src/workspace/intent.ts +6 -14
  720. package/src/workspace/kind-link-readers.ts +68 -3
  721. package/src/workspace/kind-readers.e2e.test.ts +28 -0
  722. package/src/workspace/kind-readers.test.ts +1 -1
  723. package/src/workspace/kind-readers.ts +7 -1
  724. package/src/workspace/kinds.test.ts +12 -7
  725. package/src/workspace/kinds.ts +132 -7
  726. package/src/workspace/ledger.schema.json +158 -0
  727. package/src/workspace/lexicon-outputs.ts +132 -13
  728. package/src/workspace/lineage-check.ts +30 -7
  729. package/src/workspace/links.ts +24 -1
  730. package/src/workspace/ls-contract.test.ts +1 -1
  731. package/src/workspace/ls.schema.json +7 -0
  732. package/src/workspace/ls.ts +10 -1
  733. package/src/workspace/member-commands.ts +82 -3
  734. package/src/workspace/member-file-schema.test.ts +124 -0
  735. package/src/workspace/migrate-links.test.ts +99 -0
  736. package/src/workspace/migrate-links.ts +108 -0
  737. package/src/workspace/migration-dirs.test.ts +272 -0
  738. package/src/workspace/migration-dirs.ts +267 -0
  739. package/src/workspace/nested-graph.ts +32 -1
  740. package/src/workspace/org-scope.test.ts +238 -0
  741. package/src/workspace/reason-codes.test.ts +13 -1
  742. package/src/workspace/reason-codes.ts +23 -0
  743. package/src/workspace/records-cli.ts +58 -5
  744. package/src/workspace/records.schema.json +5 -0
  745. package/src/workspace/release-candidates.ts +7 -2
  746. package/src/workspace/release-train.ts +157 -0
  747. package/src/workspace/release-workflow.ts +4 -3
  748. package/src/workspace/repo-ref.ts +113 -0
  749. package/src/workspace/run-event.schema.json +2 -2
  750. package/src/workspace/runs-cli.ts +48 -4
  751. package/src/workspace/runs.schema.json +7 -0
  752. package/src/workspace/search-cli.e2e.test.ts +305 -0
  753. package/src/workspace/search-cli.ts +591 -0
  754. package/src/workspace/search-contract.ts +95 -0
  755. package/src/workspace/search.schema.json +822 -0
  756. package/src/workspace/status-contract.test.ts +46 -1
  757. package/src/workspace/status-decisions.test.ts +100 -0
  758. package/src/workspace/status-decisions.ts +151 -0
  759. package/src/workspace/status-gates.ts +9 -0
  760. package/src/workspace/status.schema.json +6 -0
  761. package/src/workspace/status.ts +17 -3
  762. package/src/workspace/where-filters.test.ts +39 -0
  763. package/src/workspace/work-cli.ts +5 -3
  764. package/src/workspace/work-evidence-ops.test.ts +176 -0
  765. package/src/workspace/work-evidence-ops.ts +189 -0
  766. package/src/workspace/work-evidence.schema.json +49 -2
  767. package/src/workspace/work-evidence.ts +22 -3
  768. package/src/workspace/workspace-gates.ts +200 -0
  769. package/src/workspace/workspace-kinds.schema.json +58 -3
  770. package/src/workspace/workspace-ledger.ts +130 -0
  771. package/src/workspace/workspace-run.test.ts +322 -0
  772. package/src/workspace/workspace-run.ts +461 -0
@@ -6,19 +6,30 @@
6
6
  * stdout/stderr surfaces, and exit codes.
7
7
  */
8
8
 
9
- import { readFileSync, writeFileSync } from "node:fs";
9
+ import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
10
+ import { dirname } from "node:path";
10
11
  import { spawnSync } from "node:child_process";
11
12
  import { formatError, formatInfo } from "../format";
12
13
  import { formatSarif } from "../reporters/stylish";
13
14
  import type { LexiconPlugin } from "../../lexicon";
14
15
  import type { LintRule, LintDiagnostic } from "../../lint/rule";
15
16
  import { ensureTypeScriptLoader } from "../../ts-loader";
17
+ import { planMigrateLinks } from "../../workspace/migrate-links";
18
+
19
+ /**
20
+ * A side of `--from` or `--to`: a lexicon, or a lexicon and one of its
21
+ * dialects, `sql/clickhouse` (#4399). The plugin is the part before the slash.
22
+ */
23
+ export function lexiconOfSide(side: string): string {
24
+ const slash = side.indexOf("/");
25
+ return slash === -1 ? side : side.slice(0, slash);
26
+ }
16
27
 
17
28
  export interface MigrateCliOpts {
18
29
  sourceFile: string;
19
30
  from: string;
20
31
  to: string;
21
- emit: "yaml" | "ts";
32
+ emit: "yaml" | "ts" | "sql";
22
33
  strict: boolean;
23
34
  validate: boolean;
24
35
  useComposites: boolean;
@@ -39,10 +50,13 @@ export interface MigrateCliResult {
39
50
  error?: string;
40
51
  /** Markdown summary lines printed to stderr */
41
52
  markdownSummary?: string;
53
+ /** What was done about workspace links, or why nothing was (#4399) */
54
+ linkNote?: string;
42
55
  }
43
56
 
44
57
  export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliResult> {
45
- const targetPlugin = opts.plugins.find((p) => p.name === opts.to);
58
+ const targetLexicon = lexiconOfSide(opts.to);
59
+ const targetPlugin = opts.plugins.find((p) => p.name === targetLexicon);
46
60
  if (!targetPlugin) {
47
61
  return {
48
62
  exitCode: 1,
@@ -59,7 +73,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
59
73
  error: `Lexicon "${opts.to}" does not support migration`,
60
74
  };
61
75
  }
62
- const source = targetPlugin.migrationSource(opts.from);
76
+ const source = targetPlugin.migrationSource(opts.from, opts.to);
63
77
  if (!source) {
64
78
  return {
65
79
  exitCode: 1,
@@ -70,8 +84,23 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
70
84
  }
71
85
 
72
86
  let content: string;
87
+ // A directory is a workspace member: the source reads it itself (#4399).
88
+ let isDirectory = false;
89
+ try {
90
+ isDirectory = statSync(opts.sourceFile).isDirectory();
91
+ } catch {
92
+ // The read below names the problem.
93
+ }
94
+ if (isDirectory && !source.directory) {
95
+ return {
96
+ exitCode: 1,
97
+ diagnostics: [],
98
+ provenance: [],
99
+ error: `${opts.sourceFile} is a directory, and migrating from "${opts.from}" reads a file`,
100
+ };
101
+ }
73
102
  try {
74
- content = readFileSync(opts.sourceFile, "utf-8");
103
+ content = isDirectory ? "" : readFileSync(opts.sourceFile, "utf-8");
75
104
  } catch (err) {
76
105
  return {
77
106
  exitCode: 1,
@@ -81,7 +110,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
81
110
  };
82
111
  }
83
112
 
84
- if (!source.detect(content)) {
113
+ if (!isDirectory && !source.detect(content)) {
85
114
  return {
86
115
  exitCode: 1,
87
116
  diagnostics: [],
@@ -113,6 +142,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
113
142
  // Write output (--output file or stdout)
114
143
  if (opts.output && opts.output !== "-") {
115
144
  try {
145
+ mkdirSync(dirname(opts.output), { recursive: true });
116
146
  writeFileSync(opts.output, result.output);
117
147
  } catch (err) {
118
148
  return {
@@ -126,9 +156,34 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
126
156
  process.stdout.write(result.output);
127
157
  }
128
158
 
159
+ // The target's own server (--validate), when the source has one (#4399).
160
+ // A refusal always fails the run; so does a server that could not start,
161
+ // since a validation that did not run is not a pass.
162
+ let validationFailed = false;
163
+ if (opts.validate && result.validate) {
164
+ try {
165
+ const found = await result.validate();
166
+ result.diagnostics.push(...found);
167
+ if (found.some((d) => d.severity === "error")) {
168
+ validationFailed = true;
169
+ console.error(`Validator found ${found.filter((d) => d.severity === "error").length} refused statement(s):\n${found.map((d) => ` ${String(d.message)}`).join("\n")}`);
170
+ } else {
171
+ console.error("Validator (target server) OK");
172
+ }
173
+ } catch (err) {
174
+ return {
175
+ exitCode: 1,
176
+ output: result.output,
177
+ diagnostics: result.diagnostics,
178
+ provenance: result.provenance,
179
+ error: `--validate did not run: ${err instanceof Error ? err.message : String(err)}`,
180
+ };
181
+ }
182
+ }
183
+
129
184
  // External validator (--validate) — glci preferred, glab fallback.
130
185
  let validatorWarning: string | undefined;
131
- if (opts.validate && opts.emit === "yaml") {
186
+ if (opts.validate && !result.validate && opts.emit === "yaml") {
132
187
  const v = tryValidateExternal(result.output);
133
188
  if (!v.ran) {
134
189
  validatorWarning = "neither glci nor glab is on PATH; skipping --validate";
@@ -157,11 +212,35 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
157
212
  }
158
213
  }
159
214
 
215
+ // Links from the output's workspace member to the outputs it reads (#4399).
216
+ let linkNote: string | undefined;
217
+ if (result.links && result.links.length > 0) {
218
+ const outcome = planMigrateLinks({
219
+ sourcePath: opts.sourceFile,
220
+ outputPath: opts.output && opts.output !== "-" ? opts.output : undefined,
221
+ outputs: result.links,
222
+ });
223
+ if (outcome && "skipped" in outcome) linkNote = outcome.skipped;
224
+ else if (outcome) {
225
+ const { plan } = outcome;
226
+ if (plan.added.length === 0) {
227
+ linkNote = `member ${plan.consumer} already links every output it reads from ${plan.producer}`;
228
+ } else {
229
+ try {
230
+ writeFileSync(plan.file, plan.text);
231
+ linkNote = `added ${plan.added.length} link${plan.added.length === 1 ? "" : "s"} from member ${plan.consumer} to ${plan.producer} in ${plan.file}`;
232
+ } catch (err) {
233
+ linkNote = `could not write the links to ${plan.file}: ${err instanceof Error ? err.message : String(err)}`;
234
+ }
235
+ }
236
+ }
237
+ }
238
+
160
239
  // SARIF report (--report <path>) — reuse the lint-side formatSarif so any
161
240
  // CI SARIF ingest path treats migration findings uniformly.
162
241
  if (opts.reportFile) {
163
242
  try {
164
- const rules = await loadMigrationRules(opts.to);
243
+ const rules = await loadMigrationRules(targetLexicon);
165
244
  const lintShape = result.diagnostics as unknown as LintDiagnostic[];
166
245
  const sarif = formatSarif(lintShape, rules);
167
246
  writeFileSync(opts.reportFile, sarif);
@@ -172,7 +251,8 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
172
251
  }
173
252
 
174
253
  // Markdown summary (always to stderr — leaves stdout clean for piping)
175
- let markdownSummary = formatMarkdownSummary(result.provenance, result.diagnostics, content);
254
+ let markdownSummary =
255
+ targetLexicon === "gitlab" ? formatMarkdownSummary(result.provenance, result.diagnostics, content) : formatDiagnosticSummary(result.provenance, result.diagnostics);
176
256
  // Append the security posture section when security analysis ran (#306).
177
257
  if (result.securityPosture) {
178
258
  markdownSummary += `\n\n${result.securityPosture}`;
@@ -182,7 +262,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
182
262
  // The transformer already escalates needs-review → error when opts.strict
183
263
  // is passed via MigrationSource.transform(); we double-check here.
184
264
  const errorDiagnostics = result.diagnostics.filter((d) => d.severity === "error");
185
- const exitCode = opts.strict && errorDiagnostics.length > 0 ? 1 : 0;
265
+ const exitCode = validationFailed || (opts.strict && errorDiagnostics.length > 0) ? 1 : 0;
186
266
 
187
267
  return {
188
268
  exitCode,
@@ -190,6 +270,7 @@ export async function migrateCommand(opts: MigrateCliOpts): Promise<MigrateCliRe
190
270
  diagnostics: result.diagnostics,
191
271
  provenance: result.provenance,
192
272
  markdownSummary,
273
+ ...(linkNote ? { linkNote } : {}),
193
274
  };
194
275
  }
195
276
 
@@ -231,7 +312,7 @@ export function tryValidateExternal(yamlText: string): ValidatorResult {
231
312
  * Returns an empty array if the lexicon doesn't expose them.
232
313
  */
233
314
  async function loadMigrationRules(targetLexicon: string): Promise<LintRule[]> {
234
- // For now only gitlab exposes migration rules. Hard-coded import keeps
315
+ // gitlab and sql expose migration rules. Hard-coded imports keep
235
316
  // the dependency direction explicit; widen the switch when more
236
317
  // lexicons ship their own migrate paths.
237
318
  if (targetLexicon === "gitlab") {
@@ -243,9 +324,46 @@ async function loadMigrationRules(targetLexicon: string): Promise<LintRule[]> {
243
324
  return [];
244
325
  }
245
326
  }
327
+ // The sql lexicon's needs-review catalog (#4399), one rule per finding id.
328
+ if (targetLexicon === "sql") {
329
+ try {
330
+ ensureTypeScriptLoader();
331
+ const mod = await import("@intentius/chant-lexicon-sql/clickhouse/review-catalog");
332
+ const rules = (mod as { REVIEW_RULES: Record<string, { id: string; name: string; summary: string; docs: readonly string[] }> }).REVIEW_RULES;
333
+ return Object.values(rules).map((r): LintRule => ({
334
+ id: r.id,
335
+ severity: "warning",
336
+ category: "correctness",
337
+ description: `${r.name}: ${r.summary}`,
338
+ helpUri: r.docs[0] ?? "https://intentius.io/chant/lexicons/sql/migrate-postgres-to-clickhouse/",
339
+ check: () => [],
340
+ }));
341
+ } catch {
342
+ return [];
343
+ }
344
+ }
246
345
  return [];
247
346
  }
248
347
 
348
+ /**
349
+ * The report for a pair that is not GitHub to GitLab: the counts and the
350
+ * diagnostics, with none of that pair's workflow advice (#4399).
351
+ */
352
+ export function formatDiagnosticSummary(provenance: Array<Record<string, unknown>>, diagnostics: Array<Record<string, unknown>>): string {
353
+ const totals = { error: 0, warning: 0, info: 0 };
354
+ for (const d of diagnostics) {
355
+ const sev = d.severity as string;
356
+ if (sev === "error" || sev === "warning" || sev === "info") totals[sev]++;
357
+ }
358
+ const lines = ["", "## Migration report", "", `- Translated: ${provenance.length}`, `- Diagnostics: ${totals.error} error, ${totals.warning} warning, ${totals.info} info`];
359
+ if (diagnostics.length > 0) {
360
+ lines.push("", "### Diagnostics", "", "| Severity | Rule | Message |", "|---|---|---|");
361
+ for (const d of diagnostics.slice(0, 50)) lines.push(`| ${String(d.severity)} | ${String(d.ruleId)} | ${String(d.message).replace(/\|/g, "\\|").slice(0, 160)} |`);
362
+ if (diagnostics.length > 50) lines.push(`| ... | ... | ${diagnostics.length - 50} more diagnostics omitted |`);
363
+ }
364
+ return lines.join("\n");
365
+ }
366
+
249
367
  /**
250
368
  * Format the migration report as Markdown, mirroring the output format
251
369
  * prescribed by the upstream gitlab-org/ci-cd/github-actions-to-gitlab-ci
@@ -471,6 +589,9 @@ export function printMigrateResult(result: MigrateCliResult): void {
471
589
  if (result.markdownSummary) {
472
590
  console.error(result.markdownSummary);
473
591
  }
592
+ if (result.linkNote) {
593
+ console.error(`\nWorkspace links: ${result.linkNote}`);
594
+ }
474
595
  if (result.exitCode === 0) {
475
596
  console.error(formatInfo("\nMigration complete."));
476
597
  } else {
@@ -14,10 +14,10 @@ jobs:
14
14
  runs-on: ubuntu-latest
15
15
  container: node:22
16
16
  steps:
17
- - uses: actions/checkout@v7
17
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
18
18
  - run: chant run --components shared-alb --env staging --dump-outputs shared-alb.outputs.json
19
19
  - name: Upload shared-alb outputs
20
- uses: actions/upload-artifact@v4
20
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
21
21
  with:
22
22
  name: shared-alb-outputs
23
23
  path: shared-alb.outputs.json
@@ -27,9 +27,9 @@ jobs:
27
27
  - shared-alb
28
28
  container: node:22
29
29
  steps:
30
- - uses: actions/checkout@v7
30
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
31
31
  - name: Download shared-alb outputs
32
- uses: actions/download-artifact@v4
32
+ uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
33
33
  with:
34
34
  name: shared-alb-outputs
35
35
  path: .
@@ -599,6 +599,21 @@ export async function recordGateApproval(
599
599
  // decision is written next to the approval, so a pass can be traced to the
600
600
  // rule that allowed it.
601
601
  const approval = standingForOrigin?.approval;
602
+ // #4290, #4324: roles come from .chant/trust.json at base, for an approver
603
+ // a seal proves. The quorum and the policy both read these, never --role.
604
+ const judge = trustQuorumJudge({ signers: scope.policy, roles: scope.policy.roles });
605
+ const trusted = judge({
606
+ version: 1,
607
+ op: opName,
608
+ gate,
609
+ ...(environment !== undefined ? { environment } : {}),
610
+ ...(planDigest !== undefined ? { planDigest } : {}),
611
+ resolvedBy,
612
+ ...(relayedBy ? { relayedBy } : {}),
613
+ timestamp,
614
+ ...(checkpointDigest !== undefined ? { checkpointDigest } : {}),
615
+ ...(seal ? { seal } : {}),
616
+ }).roles;
602
617
  let policyDecision: GatePolicyDecision | undefined;
603
618
  if (approval?.policy) {
604
619
  try {
@@ -610,6 +625,7 @@ export async function recordGateApproval(
610
625
  gate,
611
626
  resolvedBy,
612
627
  approver,
628
+ roles: trusted,
613
629
  ...(planDigest !== undefined ? { planDigest } : {}),
614
630
  ...(approval.context ? { context: approval.context } : {}),
615
631
  }),
@@ -680,9 +696,14 @@ export async function recordGateApproval(
680
696
  "after it plans again. A moved plan or another commit starts it at the first phase.",
681
697
  ));
682
698
  }
699
+ const untrusted = (approver.roles ?? []).filter((r) => !trusted.includes(r));
700
+ if (untrusted.length > 0) {
701
+ console.error(formatInfo(
702
+ `--role ${untrusted.join(", ")} is recorded on the approval and trusted by nothing: a gate's quorum and policy read ` +
703
+ `${record.resolvedBy}'s roles from .chant/trust.json at base, and only for an approval sealed by a signer listed at base (chant approve --sign).`,
704
+ ));
705
+ }
683
706
  if (approval) {
684
- // #4290: the rules count roles from .chant/trust.json at base, for a proven approver.
685
- const judge = trustQuorumJudge({ signers: scope.policy, roles: scope.policy.roles });
686
707
  for (const line of describeApprovalProgress(approval, record, ledger.resolutions, standingForOrigin, ledger.pending, judge)) {
687
708
  console.error(formatInfo(line));
688
709
  }
@@ -171,6 +171,12 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
171
171
  }
172
172
  }
173
173
 
174
+ // #4327: ci.locks: plan adds the lock and unlock jobs. Read from the declaration, as the security groups are; GitLab keeps its own jobs.
175
+ let locks: "plan" | undefined;
176
+ if (found && args.prLoop && lexicon !== "gitlab") {
177
+ locks = (await import("../../workspace/ci-locks")).ciLocksAt(resolve(args.path)) === "plan" ? "plan" : undefined;
178
+ }
179
+
174
180
  // Which lexicons support generate mode is a property of the loaded lexicon
175
181
  // plugins (those implementing `generateComponentPipeline`, #688), not a
176
182
  // hard-coded core list — `generateComponentsPipeline` returns a descriptive
@@ -192,7 +198,7 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
192
198
  : {}),
193
199
  // #3183: a plan job per pull request and an apply job per merge.
194
200
  // #4292: on the branch ci.branches routes the member to, when it routes it.
195
- ...(args.prLoop ? { prLoop: { ...prLoopOption(args, reportUrl, reviewRules, isolatedRunners), ...(plan?.branch ? { branch: plan.branch } : {}), ...(identity ? { identity } : {}), ...(prEnvIdentity ? { prEnvIdentity } : {}) } } : {}),
201
+ ...(args.prLoop ? { prLoop: { ...prLoopOption(args, reportUrl, reviewRules, isolatedRunners), ...(plan?.branch ? { branch: plan.branch } : {}), ...(identity ? { identity } : {}), ...(prEnvIdentity ? { prEnvIdentity } : {}), ...(locks ? { locks } : {}) } } : {}),
196
202
  // #4002: the job image and the lines that install what it lacks, chant itself included.
197
203
  ...(args.image ? { image: args.image } : {}),
198
204
  ...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
@@ -0,0 +1,99 @@
1
+ import { dirname } from "node:path";
2
+ import { mergeBuildRootEntities } from "../../build";
3
+ import { loadChantConfigUpward, type ChantConfig } from "../../config";
4
+ import type { Declarable } from "../../declarable";
5
+ import { applyLexiconGraphEdges, type GraphIR, type LexiconGraphEdges } from "../../graph-ir";
6
+ import type { BuildRootContributor, LexiconPlugin } from "../../lexicon";
7
+ import { formatError, formatWarning } from "../format";
8
+ import { collectBuildRootContributors, loadPlugins, resolveProjectLexicons } from "../plugins";
9
+ import type { CommandContext } from "../registry";
10
+
11
+ /**
12
+ * The pieces of the declared graph that `chant graph` and `chant search` both
13
+ * read (#1626, #4365, #4368). They live here, once, so the two commands answer
14
+ * over the same entity set and the same edges: search drifted from graph once
15
+ * already, answering `(no matches)` over a `terraform.roots` project graph drew
16
+ * in full, because it never ran the build-root contributors.
17
+ */
18
+
19
+ /**
20
+ * The build-root contributors this invocation's project configures (#1626):
21
+ * a `terraform.roots` root's blocks, a `k8s.kustomize.roots` root's rendered
22
+ * objects. The same closures `chant build` and the lifecycle handlers hand to
23
+ * `BuildOptions.buildRoots`, bound here for the discover-based paths, which
24
+ * never run `build()` and so never ran the hook.
25
+ *
26
+ * Neither command is `requiresPlugins` (Op/source-graph modes must work
27
+ * without a lexicon), so plugins are loaded here when `ctx.plugins` is empty.
28
+ * Rooted at the config's own directory, like `cli/commands/build.ts`: a
29
+ * relative root resolves against where it was declared, not against a
30
+ * sourceDir-scoped path. A project that fails to load plugins degrades to no
31
+ * contributors with a warning rather than failing modes that never needed
32
+ * plugins at all.
33
+ */
34
+ export async function declaredBuildRootContributors(
35
+ ctx: CommandContext,
36
+ projectPath: string,
37
+ ): Promise<BuildRootContributor[]> {
38
+ const { config, configPath } = await loadChantConfigUpward(projectPath).catch(
39
+ () => ({ config: {} as ChantConfig, configPath: undefined }),
40
+ );
41
+ let plugins = ctx.plugins;
42
+ if (plugins.length === 0) {
43
+ try {
44
+ plugins = await loadPlugins(await resolveProjectLexicons(projectPath));
45
+ } catch (err) {
46
+ console.error(formatWarning({
47
+ message: `could not load the project's lexicons — build-root entities (terraform and kustomize roots) will be missing from the graph (${err instanceof Error ? err.message : String(err)})`,
48
+ }));
49
+ return [];
50
+ }
51
+ }
52
+ return collectBuildRootContributors(
53
+ plugins,
54
+ config as unknown as Record<string, unknown>,
55
+ configPath ? dirname(configPath) : projectPath,
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Merge build-root contributions into a discovered entity set: the exact
61
+ * merge `build()` performs (one implementation: `mergeBuildRootEntities`,
62
+ * ../../build.ts), with its warnings and errors printed. Returns false when a
63
+ * contributor failed or a name collided; the caller stops, because a graph
64
+ * missing the entities the build would refuse over must not be answered from
65
+ * as if complete.
66
+ */
67
+ export async function mergeDeclaredBuildRoots(
68
+ entities: Map<string, Declarable>,
69
+ contributors: BuildRootContributor[],
70
+ ): Promise<boolean> {
71
+ if (contributors.length === 0) return true;
72
+ const merged = await mergeBuildRootEntities(entities, contributors);
73
+ for (const w of merged.warnings) console.error(formatWarning({ message: w }));
74
+ if (merged.errors.length > 0) {
75
+ for (const message of merged.errors) console.error(formatError({ message }));
76
+ return false;
77
+ }
78
+ return true;
79
+ }
80
+
81
+ /**
82
+ * Add the edges the lexicons' `graphEdges` hooks resolve (#3910): CI
83
+ * dependencies written as strings (`needs`, `uses:`, `trigger:`, `include:`,
84
+ * `extends`), which the AttrRef walk in `buildGraphIr` cannot see. A hook that
85
+ * throws costs its own edges and a warning, not the graph.
86
+ */
87
+ export function withLexiconEdges(ir: GraphIR, plugins: readonly LexiconPlugin[], entities: Map<string, Declarable>): GraphIR {
88
+ const reports: LexiconGraphEdges[] = [];
89
+ for (const p of plugins) {
90
+ if (!p.graphEdges) continue;
91
+ try {
92
+ const report = p.graphEdges(entities);
93
+ if (report) reports.push(report);
94
+ } catch (err) {
95
+ console.error(formatWarning({ message: `the ${p.name} lexicon's graphEdges failed (${err instanceof Error ? err.message : String(err)}); its edges are left out` }));
96
+ }
97
+ }
98
+ return reports.length === 0 ? ir : applyLexiconGraphEdges(ir, reports);
99
+ }
@@ -75,9 +75,10 @@ vi.mock("../../lifecycle/replay", () => ({
75
75
  hasSnapshot: (...a: unknown[]) => hasSnapshotMock(...a),
76
76
  }));
77
77
 
78
- vi.mock("../../lifecycle/observe", () => ({
79
- observeResources: (...a: unknown[]) => observeMock(...a),
80
- }));
78
+ vi.mock("../../lifecycle/observe", async () => {
79
+ const actual = await vi.importActual<typeof import("../../lifecycle/observe")>("../../lifecycle/observe");
80
+ return { carryAnnotations: actual.carryAnnotations, observeResources: (...a: unknown[]) => observeMock(...a) };
81
+ });
81
82
  // `runGraphLive` resolves each component's `cfn-deploy` stack(s) (#57) so a
82
83
  // multi-stack, per-component project observes the right stacks; default to
83
84
  // "no components" (empty map, no errors) so the existing single-stack --live
@@ -544,6 +545,66 @@ describe("runGraph", () => {
544
545
  });
545
546
  });
546
547
 
548
+ // behold#919: a project that reads source it did not author (a workspace
549
+ // reader project, behold's scratch project for a bare Terraform folder)
550
+ // sets `graph.lint: "report"`, and a lint error is a finding about the
551
+ // estate, carried on meta.lint, not a reason to draw nothing.
552
+ describe('graph.lint: "report" (behold#919)', () => {
553
+ const finding = { file: "/abs/estate/db.tf", line: 4, column: 3, ruleId: "TF033", severity: "error", message: "[estate/aws_db_instance.orders] storage_encrypted is false", entity: "estate/aws_db_instance.orders" };
554
+ const warning = { file: "/abs/estate/net.tf", line: 9, column: 1, ruleId: "TF010", severity: "warning", message: "a warning" };
555
+ const reportMode = (): void => {
556
+ loadChantConfigUpwardMock.mockResolvedValue({ config: { graph: { lint: "report" } } });
557
+ };
558
+
559
+ test("emits the graph with lint errors, every finding on meta.lint", async () => {
560
+ reportMode(); discovered();
561
+ lintMock.mockResolvedValue({ success: false, diagnostics: [finding, warning] });
562
+ const exit = await runGraph({ args: makeArgs({ format: "ir" }), plugins: [], serializers: [] });
563
+ expect(exit).toBe(0);
564
+ const ir = JSON.parse(stdoutBuf.join("\n"));
565
+ expect(ir.nodes.map((n: { id: string }) => n.id).sort()).toEqual(["pod", "subnet", "vpc"]);
566
+ expect(ir.meta.lint).toEqual({
567
+ errors: 1,
568
+ warnings: 1,
569
+ findings: [
570
+ { ruleId: "TF033", severity: "error", message: "[estate/aws_db_instance.orders] storage_encrypted is false", file: "/abs/estate/db.tf", line: 4, column: 3, entity: "estate/aws_db_instance.orders" },
571
+ { ruleId: "TF010", severity: "warning", message: "a warning", file: "/abs/estate/net.tf", line: 9, column: 1 },
572
+ ],
573
+ });
574
+ expect(stderrBuf.join("\n")).toMatch(/with 1 lint error: graph\.lint is "report"/);
575
+ });
576
+
577
+ test("a clean read still carries meta.lint, so a reader can tell clean from not looked", async () => {
578
+ reportMode(); lintClean(); discovered();
579
+ const exit = await runGraph({ args: makeArgs({ format: "ir" }), plugins: [], serializers: [] });
580
+ expect(exit).toBe(0);
581
+ expect(JSON.parse(stdoutBuf.join("\n")).meta.lint).toEqual({ errors: 0, warnings: 0, findings: [] });
582
+ });
583
+
584
+ test("the default gate is unchanged, and adds no meta.lint", async () => {
585
+ lintClean(); discovered();
586
+ await runGraph({ args: makeArgs({ format: "ir" }), plugins: [], serializers: [] });
587
+ expect(JSON.parse(stdoutBuf.join("\n")).meta?.lint).toBeUndefined();
588
+ });
589
+
590
+ test("an uninstalled dependency still refuses: there is no source to read", async () => {
591
+ const project = realpathSync(mkdtempSync(join(tmpdir(), "chant-919-graph-")));
592
+ try {
593
+ reportMode(); discovered();
594
+ lintMock.mockResolvedValue({
595
+ success: false,
596
+ diagnostics: [{ file: join(project, "a.ts"), line: 1, column: 1, ruleId: "LEX002", severity: "error", message: `Cannot find package '@intentius/chant-lexicon-aws' imported from ${join(project, "a.ts")}` }],
597
+ });
598
+ const exit = await runGraph({ args: makeArgs({ format: "ir", path: project }), plugins: [], serializers: [] });
599
+ expect(exit).toBe(1);
600
+ expect(stdoutBuf.join("\n")).toBe("");
601
+ expect(stderrBuf.join("\n")).toContain("dependencies not installed");
602
+ } finally {
603
+ rmSync(project, { recursive: true, force: true });
604
+ }
605
+ });
606
+ });
607
+
547
608
  test("--format mermaid emits a flowchart", async () => {
548
609
  lintClean(); discovered();
549
610
  const exit = await runGraph({ args: makeArgs({ format: "mermaid" }), plugins: [], serializers: [] });
@@ -872,6 +933,36 @@ describe("runGraph", () => {
872
933
  expect(out).toContain("web-vpc");
873
934
  });
874
935
 
936
+ // #4372 — a planned create is absent, and its plan attributes ride beside
937
+ // the verdict as annotations. `--overlay` puts them on the declared node,
938
+ // which keeps its pending paint: behold's plan cards read this IR.
939
+ test("--overlay carries an absent entity's annotations onto its declared node, still pending", async () => {
940
+ resolveLexMock.mockResolvedValue(["terraform"]);
941
+ loadPluginsMock.mockResolvedValue([
942
+ { name: "terraform", serializer: {}, describeResources: () => Promise.resolve({}) },
943
+ ]);
944
+ discoverMock.mockResolvedValue({
945
+ entities: new Map([
946
+ ["app/terraform_data.created", decl({ lexicon: "terraform", entityType: "Terraform::Resource", props: {} })],
947
+ ]),
948
+ errors: [],
949
+ sourceFiles: [],
950
+ });
951
+ observeMock.mockResolvedValue({
952
+ observations: [],
953
+ errors: [],
954
+ warnings: [],
955
+ annotations: { "app/terraform_data.created": { planAction: "create", planAfterUnknown: ["id"] } },
956
+ });
957
+ // `--detail 3`, as behold asks: lower tiers thin list attributes.
958
+ const exit = await runGraph({ args: makeArgs({ format: "ir", live: true, overlay: true, env: "prod", detail: 3 }), plugins: [], serializers: [] });
959
+ expect(exit).toBe(0);
960
+ const ir = JSON.parse(stdoutBuf.join("\n")) as { nodes: Array<{ id: string; physicalId?: string; attrs: Record<string, unknown> }> };
961
+ const node = ir.nodes.find((n) => n.id === "app/terraform_data.created");
962
+ expect(node?.attrs).toMatchObject({ _status: "accent", planAction: "create", planAfterUnknown: ["id"] });
963
+ expect(node?.physicalId).toBeUndefined();
964
+ });
965
+
875
966
  // #2377 — the overlay carries the prediction. behold's reader takes
876
967
  // `attrs._behaviour` per node and `meta._behaviour` on the graph, and
877
968
  // reads the absence of both as "not looked" rather than as a refusal, so