@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
@@ -0,0 +1,373 @@
1
+ /**
2
+ * The capability rule language (#4375, ruled on #4361).
3
+ *
4
+ * A capability is a named path pattern over the lexicon-neutral view
5
+ * (`./view.ts`). Its steps are #4359's edge terms: an arrow, an optional
6
+ * depth, then what the edge is. A rule file is data, read at run time:
7
+ *
8
+ * # a comment
9
+ * ## meaning: what the capability says, in one line (catalog metadata)
10
+ * in-sg(x, g) := x ->{0,1}template ->sg g:SecurityGroup
11
+ * open-ingress(c; port?, proto?)
12
+ * := c ->in-sg ->ingress :IngressRule[cidrs in ("0.0.0.0/0"), from <= $port]
13
+ * internet-reachable(c; port?)
14
+ * := c[@internet-facing, @open-ingress($port)]
15
+ * | c:Function <-function :FunctionUrl[authType = "NONE"]
16
+ *
17
+ * One variable makes a node set, used as `[@name]`. Two make a named edge,
18
+ * followed as `->name` or `<-name`, which carries the hops that proved it.
19
+ * Parameters come after `;`; a `?` makes one optional, and a test that names
20
+ * an absent parameter is left out. Lines starting `|` add an alternative.
21
+ *
22
+ * A step is `->` or `<-`, an optional depth (`?`, `*`, `+`, `{n}`, `{m,n}`,
23
+ * `{m,}`; a rule may start at 0, which #4359's query grammar refuses), an
24
+ * edge name or `(a|b)`, and an optional node: `var:Label|Label[tests]`.
25
+ * `!->name node` and `!<-name node` are negated steps: the walk stays where
26
+ * it is and goes on only when no such edge leads to such a node.
27
+ *
28
+ * A node test is `attr = v`, `attr != v`, `attr in (v, ...)`, `attr ~ "glob"`,
29
+ * `attr < n` (and `<=`, `>`, `>=`), a bare `attr` (present and not false),
30
+ * or `@cap` / `@cap(args)`. Any test takes a leading `!`. Against a list
31
+ * attribute, a test holds when it holds for any element.
32
+ */
33
+
34
+ export type Literal = string | number | boolean | null;
35
+
36
+ /** A value in a test or an argument: a literal, or a reference to a parameter. */
37
+ export type Value = { lit: Literal } | { param: string };
38
+
39
+ export type Test =
40
+ | { kind: "attr"; negated: boolean; attr: string; op: "=" | "!=" | "in" | "~" | "<" | "<=" | ">" | ">=" | "present"; values: Value[] }
41
+ | { kind: "cap"; negated: boolean; cap: string; args: Value[] };
42
+
43
+ export interface NodeSpec {
44
+ v?: string;
45
+ labels?: string[];
46
+ tests: Test[];
47
+ }
48
+
49
+ export interface Step {
50
+ dir: "out" | "in";
51
+ negated: boolean;
52
+ /** Edge names: view edges or two-variable capabilities. */
53
+ names: { name: string; args: Value[] }[];
54
+ min: number;
55
+ max: number;
56
+ node: NodeSpec;
57
+ }
58
+
59
+ export interface Alternative {
60
+ head: NodeSpec;
61
+ steps: Step[];
62
+ /** 1-based line in the rule file, for messages. */
63
+ line: number;
64
+ }
65
+
66
+ export interface Param {
67
+ name: string;
68
+ optional: boolean;
69
+ }
70
+
71
+ export interface Rule {
72
+ name: string;
73
+ vars: string[];
74
+ params: Param[];
75
+ alts: Alternative[];
76
+ /** `## key: value` lines above the rule. */
77
+ meta: Record<string, string>;
78
+ line: number;
79
+ /** The rule as written, one alternative per line, comments dropped. */
80
+ text: string;
81
+ }
82
+
83
+ /** A rule file the parser cannot read, with the line it failed on. */
84
+ export class RuleSyntaxError extends Error {
85
+ constructor(
86
+ message: string,
87
+ readonly line: number,
88
+ ) {
89
+ super(`line ${line}: ${message}`);
90
+ }
91
+ }
92
+
93
+ // An identifier may hold `-` (`can-assume`), but not one that starts an arrow.
94
+ const TOKEN = /\s*(!->|!<-|->|<-|:=|<=|>=|!=|\{\d*(?:,\d*)?\}|"(?:[^"\\]|\\.)*"|-?\d+(?:\.\d+)?(?![\w-])|[$]?[A-Za-z_](?:\w|-(?!>))*|[()[\],|?*+@:=~<>!;])/y;
95
+
96
+ function tokenize(text: string, line: number): string[] {
97
+ const out: string[] = [];
98
+ TOKEN.lastIndex = 0;
99
+ const end = text.trimEnd().length;
100
+ while (TOKEN.lastIndex < end) {
101
+ const at = TOKEN.lastIndex;
102
+ const m = TOKEN.exec(text);
103
+ if (!m) throw new RuleSyntaxError(`cannot read "${text.slice(at).trim()}"`, line);
104
+ out.push(m[1]);
105
+ }
106
+ return out;
107
+ }
108
+
109
+ /**
110
+ * Parse a rule file. Rules may span lines: a line that starts with `|`
111
+ * continues the rule above it, and so does an indented line when the rule's
112
+ * `:=` has nothing after it yet.
113
+ */
114
+ export function parseRules(text: string): Rule[] {
115
+ const rules: Rule[] = [];
116
+ let meta: Record<string, string> = {};
117
+ let pending: { text: string; line: number; rule?: Rule } | undefined;
118
+ const lines = text.split("\n");
119
+
120
+ const flush = (): void => {
121
+ if (!pending) return;
122
+ const { text: body, line } = pending;
123
+ const toks = tokenize(body, line);
124
+ const p = new Parser(toks, line);
125
+ if (pending.rule) {
126
+ p.eat("|");
127
+ pending.rule.alts.push(p.alternative());
128
+ pending.rule.text += `\n${body.trim()}`;
129
+ } else {
130
+ const rule = p.header(meta, body.trim());
131
+ meta = {};
132
+ rule.alts.push(p.alternative());
133
+ rules.push(rule);
134
+ }
135
+ p.done();
136
+ pending = undefined;
137
+ };
138
+
139
+ lines.forEach((raw, i) => {
140
+ const line = i + 1;
141
+ const docMatch = /^\s*##\s*([\w-]+)\s*:\s*(.*)$/.exec(raw);
142
+ if (docMatch) {
143
+ flush();
144
+ const [, key, value] = docMatch;
145
+ meta[key] = meta[key] ? `${meta[key]}\n${value.trim()}` : value.trim();
146
+ return;
147
+ }
148
+ const code = raw.replace(/(^|\s)#.*$/, "");
149
+ if (!code.trim()) return;
150
+ if (/^\s*\|/.test(code)) {
151
+ flush();
152
+ const rule = rules.at(-1);
153
+ if (!rule) throw new RuleSyntaxError("an alternative needs a rule above it", line);
154
+ pending = { text: code, line, rule };
155
+ return;
156
+ }
157
+ if (/^\s/.test(code) && pending) {
158
+ pending.text += ` ${code.trim()}`;
159
+ return;
160
+ }
161
+ flush();
162
+ pending = { text: code, line };
163
+ });
164
+ flush();
165
+
166
+ const seen = new Set<string>();
167
+ for (const r of rules) {
168
+ if (seen.has(r.name)) throw new RuleSyntaxError(`"${r.name}" is defined twice`, r.line);
169
+ seen.add(r.name);
170
+ }
171
+ return rules;
172
+ }
173
+
174
+ const LIT = (tok: string): Literal => {
175
+ if (tok === "null") return null;
176
+ if (tok === "true") return true;
177
+ if (tok === "false") return false;
178
+ if (tok.startsWith('"')) return JSON.parse(tok) as string;
179
+ if (/^-?\d/.test(tok)) return Number(tok);
180
+ return tok;
181
+ };
182
+
183
+ const NAME = /^[A-Za-z_][\w-]*$/;
184
+
185
+ class Parser {
186
+ private i = 0;
187
+ constructor(
188
+ private readonly t: string[],
189
+ private readonly line: number,
190
+ ) {}
191
+
192
+ private peek(k = 0): string | undefined {
193
+ return this.t[this.i + k];
194
+ }
195
+ private next(): string {
196
+ const tok = this.t[this.i++];
197
+ if (tok === undefined) throw new RuleSyntaxError("the rule ends too early", this.line);
198
+ return tok;
199
+ }
200
+ eat(x: string): void {
201
+ if (this.t[this.i] !== x) {
202
+ throw new RuleSyntaxError(`expected "${x}" at "${this.t.slice(this.i).join(" ") || "end of rule"}"`, this.line);
203
+ }
204
+ this.i++;
205
+ }
206
+ done(): void {
207
+ if (this.i !== this.t.length) throw new RuleSyntaxError(`cannot read "${this.t.slice(this.i).join(" ")}"`, this.line);
208
+ }
209
+ private name(what: string): string {
210
+ const tok = this.next();
211
+ if (!NAME.test(tok)) throw new RuleSyntaxError(`expected ${what}, found "${tok}"`, this.line);
212
+ return tok;
213
+ }
214
+
215
+ header(meta: Record<string, string>, text: string): Rule {
216
+ const name = this.name("a capability name");
217
+ this.eat("(");
218
+ const vars = [this.name("a variable")];
219
+ if (this.peek() === ",") {
220
+ this.next();
221
+ vars.push(this.name("a variable"));
222
+ }
223
+ const params: Param[] = [];
224
+ if (this.peek() === ";") {
225
+ this.next();
226
+ for (;;) {
227
+ const p = this.name("a parameter");
228
+ const optional = this.peek() === "?";
229
+ if (optional) this.next();
230
+ params.push({ name: p, optional });
231
+ if (this.peek() !== ",") break;
232
+ this.next();
233
+ }
234
+ }
235
+ this.eat(")");
236
+ this.eat(":=");
237
+ return { name, vars, params, alts: [], meta, line: this.line, text };
238
+ }
239
+
240
+ alternative(): Alternative {
241
+ const head = this.node();
242
+ const steps: Step[] = [];
243
+ while (this.peek() && /^!?(->|<-)$/.test(this.peek()!)) steps.push(this.step());
244
+ return { head, steps, line: this.line };
245
+ }
246
+
247
+ private step(): Step {
248
+ const arrow = this.next();
249
+ const negated = arrow.startsWith("!");
250
+ const dir = arrow.endsWith("->") ? "out" : "in";
251
+ let min = 1;
252
+ let max = 1;
253
+ const q = this.peek();
254
+ if (q === "?") {
255
+ this.next();
256
+ min = 0;
257
+ } else if (q === "*") {
258
+ this.next();
259
+ max = Infinity;
260
+ } else if (q === "+") {
261
+ this.next();
262
+ max = Infinity;
263
+ } else if (q && q.startsWith("{")) {
264
+ this.next();
265
+ const m = /^\{(\d*)(,(\d*))?\}$/.exec(q)!;
266
+ min = m[1] === "" ? 0 : Number(m[1]);
267
+ max = m[2] === undefined ? min : m[3] === "" ? Infinity : Number(m[3]);
268
+ if (max < min) throw new RuleSyntaxError(`depth ${q} has its maximum below its minimum`, this.line);
269
+ }
270
+ if (negated && (min !== 1 || max !== 1)) throw new RuleSyntaxError("a negated step takes no depth", this.line);
271
+ const names: Step["names"] = [];
272
+ if (this.peek() === "(") {
273
+ this.next();
274
+ for (;;) {
275
+ names.push(this.edgeName());
276
+ if (this.peek() !== "|") break;
277
+ this.next();
278
+ }
279
+ this.eat(")");
280
+ } else names.push(this.edgeName());
281
+ return { dir, negated, names, min, max, node: this.node() };
282
+ }
283
+
284
+ private edgeName(): { name: string; args: Value[] } {
285
+ const name = this.name("an edge name");
286
+ // `->grants($action)`: arguments must touch the name, so a following
287
+ // `(a|b)` step is not read as arguments.
288
+ return { name, args: this.peek() === "(" ? this.args() : [] };
289
+ }
290
+
291
+ private args(): Value[] {
292
+ this.eat("(");
293
+ const out: Value[] = [];
294
+ while (this.peek() !== ")") {
295
+ out.push(this.value());
296
+ if (this.peek() === ",") this.next();
297
+ }
298
+ this.eat(")");
299
+ return out;
300
+ }
301
+
302
+ private value(): Value {
303
+ const tok = this.next();
304
+ if (tok.startsWith("$")) return { param: tok.slice(1) };
305
+ return { lit: LIT(tok) };
306
+ }
307
+
308
+ private node(): NodeSpec {
309
+ const spec: NodeSpec = { tests: [] };
310
+ const p = this.peek();
311
+ if (p && NAME.test(p) && /^[a-z_]/.test(p) && this.peek(1) !== "(") {
312
+ spec.v = this.next();
313
+ }
314
+ if (this.peek() === ":") {
315
+ this.next();
316
+ spec.labels = [this.name("a label")];
317
+ while (this.peek() === "|" && /^[A-Z]/.test(this.peek(1) ?? "")) {
318
+ this.next();
319
+ spec.labels.push(this.name("a label"));
320
+ }
321
+ }
322
+ if (this.peek() === "[") {
323
+ this.next();
324
+ while (this.peek() !== "]") {
325
+ spec.tests.push(this.test());
326
+ if (this.peek() === ",") this.next();
327
+ else if (this.peek() !== "]") throw new RuleSyntaxError(`expected "," or "]" at "${this.peek() ?? "end of rule"}"`, this.line);
328
+ }
329
+ this.eat("]");
330
+ }
331
+ return spec;
332
+ }
333
+
334
+ private test(): Test {
335
+ let negated = false;
336
+ if (this.peek() === "!") {
337
+ this.next();
338
+ negated = true;
339
+ }
340
+ if (this.peek() === "@") {
341
+ this.next();
342
+ const cap = this.name("a capability name");
343
+ return { kind: "cap", negated, cap, args: this.peek() === "(" ? this.args() : [] };
344
+ }
345
+ const attr = this.name("an attribute");
346
+ const op = this.peek();
347
+ if (op === "," || op === "]") return { kind: "attr", negated, attr, op: "present", values: [] };
348
+ this.next();
349
+ if (op === "in") {
350
+ return { kind: "attr", negated, attr, op: "in", values: this.args() };
351
+ }
352
+ if (op === "=" || op === "!=" || op === "~" || op === "<" || op === "<=" || op === ">" || op === ">=") {
353
+ return { kind: "attr", negated, attr, op, values: [this.value()] };
354
+ }
355
+ throw new RuleSyntaxError(`"${op}" is not a test operator`, this.line);
356
+ }
357
+ }
358
+
359
+ /** The capabilities a rule refers to, by name: in `[@cap]` tests and in steps. */
360
+ export function ruleDependencies(rule: Rule): Set<string> {
361
+ const out = new Set<string>();
362
+ const node = (n: NodeSpec): void => {
363
+ for (const t of n.tests) if (t.kind === "cap") out.add(t.cap);
364
+ };
365
+ for (const a of rule.alts) {
366
+ node(a.head);
367
+ for (const s of a.steps) {
368
+ for (const n of s.names) out.add(n.name);
369
+ node(s.node);
370
+ }
371
+ }
372
+ return out;
373
+ }
@@ -0,0 +1,315 @@
1
+ /**
2
+ * The matcher for capability rules (#4375): evaluates `./language.ts` rules
3
+ * over a `./view.ts` view, lazily, keeping the path that proved each fact.
4
+ *
5
+ * A capability is computed the first time something asks for it, over the
6
+ * whole view, and kept. One that refers to another asks for it first, so
7
+ * negation is stratified by construction: `[!@cap]` reads a set that is
8
+ * already complete. Two capabilities that need each other are refused.
9
+ */
10
+ import type { Alternative, Literal, NodeSpec, Rule, Step, Test, Value } from "./language";
11
+ import type { View, ViewHop } from "./view";
12
+
13
+ /** Why a node is in a set, or a pair in an edge: the hops walked, and the sets it relied on. */
14
+ export interface Evidence {
15
+ /** IR hops in walk order. Each keeps the edge's own direction. */
16
+ hops: ViewHop[];
17
+ /** The `[@cap]` tests the match relied on, each with its own evidence. */
18
+ because: { capability: string; id: string; evidence: Evidence }[];
19
+ }
20
+
21
+ export type Args = Record<string, Literal | undefined>;
22
+
23
+ /** An edge capability: each source's targets, with evidence. */
24
+ export interface Relation {
25
+ out: Map<string, Map<string, Evidence>>;
26
+ in: Map<string, Map<string, Evidence>>;
27
+ }
28
+
29
+ export class CapabilityError extends Error {}
30
+
31
+ const glob = (pattern: string, s: string): boolean =>
32
+ new RegExp(`^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".")}$`, "i").test(s);
33
+
34
+ function equal(a: unknown, b: Literal): boolean {
35
+ if (b === null) return a === null || a === undefined;
36
+ if (a === b) return true;
37
+ if (a === null || a === undefined || typeof a === "object") return false;
38
+ return String(a) === String(b);
39
+ }
40
+
41
+ function present(a: unknown): boolean {
42
+ return a !== undefined && a !== null && a !== false && !(Array.isArray(a) && a.length === 0);
43
+ }
44
+
45
+ const reverseHops = (hops: ViewHop[]): ViewHop[] => [...hops].reverse();
46
+
47
+ export class CapabilityEngine {
48
+ private readonly rules = new Map<string, Rule>();
49
+ private readonly sets = new Map<string, Map<string, Evidence>>();
50
+ private readonly relations = new Map<string, Relation>();
51
+ private readonly busy = new Set<string>();
52
+ private readonly out = new Map<string, Map<string, { to: string; hops: ViewHop[] }[]>>();
53
+ private readonly in = new Map<string, Map<string, { to: string; hops: ViewHop[] }[]>>();
54
+ private readonly byLabel = new Map<string, string[]>();
55
+
56
+ constructor(
57
+ readonly view: View,
58
+ rules: Rule[],
59
+ ) {
60
+ for (const r of rules) this.rules.set(r.name, r);
61
+ for (const e of view.edges) {
62
+ this.index(this.out, e.from, e.name, e.to, e.hops);
63
+ this.index(this.in, e.to, e.name, e.from, reverseHops(e.hops));
64
+ }
65
+ for (const n of view.nodes.values()) {
66
+ if (!this.byLabel.has(n.label)) this.byLabel.set(n.label, []);
67
+ this.byLabel.get(n.label)!.push(n.id);
68
+ }
69
+ for (const r of rules) this.check(r);
70
+ }
71
+
72
+ private index(ix: CapabilityEngine["out"], a: string, name: string, b: string, hops: ViewHop[]): void {
73
+ let m = ix.get(a);
74
+ if (!m) ix.set(a, (m = new Map()));
75
+ let l = m.get(name);
76
+ if (!l) m.set(name, (l = []));
77
+ l.push({ to: b, hops });
78
+ }
79
+
80
+ /** Refuse a rule that names a capability that doesn't exist, or uses one in the wrong shape. */
81
+ private check(r: Rule): void {
82
+ const node = (n: NodeSpec, alt: Alternative): void => {
83
+ for (const t of n.tests) {
84
+ if (t.kind !== "cap") continue;
85
+ const target = this.rules.get(t.cap);
86
+ if (!target) throw new CapabilityError(`${r.name} (line ${alt.line}): no capability "${t.cap}"`);
87
+ if (target.vars.length !== 1) throw new CapabilityError(`${r.name} (line ${alt.line}): "@${t.cap}" is an edge, not a set; follow it with ->${t.cap}`);
88
+ }
89
+ };
90
+ for (const alt of r.alts) {
91
+ node(alt.head, alt);
92
+ for (const s of alt.steps) {
93
+ node(s.node, alt);
94
+ for (const n of s.names) {
95
+ const target = this.rules.get(n.name);
96
+ if (target && target.vars.length !== 2) {
97
+ throw new CapabilityError(`${r.name} (line ${alt.line}): "${n.name}" is a set, not an edge; test it with [@${n.name}]`);
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ has(name: string): boolean {
105
+ return this.rules.has(name);
106
+ }
107
+
108
+ /** The capabilities the catalog lists: rules that carry a `## meaning`. */
109
+ publicNames(): string[] {
110
+ return [...this.rules.values()].filter((r) => r.meta.meaning !== undefined).map((r) => r.name);
111
+ }
112
+
113
+ rule(name: string): Rule | undefined {
114
+ return this.rules.get(name);
115
+ }
116
+
117
+ /** Bind positional arguments to a rule's parameters. */
118
+ bind(name: string, positional: (Literal | undefined)[]): Args {
119
+ const r = this.rules.get(name);
120
+ if (!r) throw new CapabilityError(`no capability "${name}"`);
121
+ if (positional.length > r.params.length) {
122
+ throw new CapabilityError(`${name} takes ${r.params.length === 0 ? "no arguments" : `at most ${r.params.length} (${r.params.map((p) => p.name).join(", ")})`}`);
123
+ }
124
+ const args: Args = {};
125
+ r.params.forEach((p, i) => {
126
+ const v = positional[i];
127
+ if (v === undefined && !p.optional) throw new CapabilityError(`${name} needs ${p.name}`);
128
+ args[p.name] = v;
129
+ });
130
+ return args;
131
+ }
132
+
133
+ private key(name: string, args: Args): string {
134
+ return `${name}(${JSON.stringify(Object.entries(args).filter(([, v]) => v !== undefined).sort())})`;
135
+ }
136
+
137
+ /** The nodes in a set capability, with evidence. */
138
+ set(name: string, args: Args = {}): Map<string, Evidence> {
139
+ const r = this.rules.get(name);
140
+ if (!r) throw new CapabilityError(`no capability "${name}"`);
141
+ if (r.vars.length !== 1) throw new CapabilityError(`"${name}" is an edge, not a set`);
142
+ const key = this.key(name, args);
143
+ const cached = this.sets.get(key);
144
+ if (cached) return cached;
145
+ this.enter(key);
146
+ const out = new Map<string, Evidence>();
147
+ for (const alt of r.alts) {
148
+ for (const s of this.starts(alt.head)) {
149
+ this.match(alt, s, args, (env, ev) => {
150
+ const x = env[r.vars[0]] ?? s;
151
+ if (!out.has(x)) out.set(x, ev);
152
+ });
153
+ }
154
+ }
155
+ this.busy.delete(key);
156
+ this.sets.set(key, out);
157
+ return out;
158
+ }
159
+
160
+ /** The pairs in an edge capability, with evidence. */
161
+ relation(name: string, args: Args = {}): Relation {
162
+ const r = this.rules.get(name);
163
+ if (!r) throw new CapabilityError(`no capability "${name}"`);
164
+ if (r.vars.length !== 2) throw new CapabilityError(`"${name}" is a set, not an edge`);
165
+ const key = this.key(name, args);
166
+ const cached = this.relations.get(key);
167
+ if (cached) return cached;
168
+ this.enter(key);
169
+ const rel: Relation = { out: new Map(), in: new Map() };
170
+ for (const alt of r.alts) {
171
+ for (const s of this.starts(alt.head)) {
172
+ this.match(alt, s, args, (env, ev, last) => {
173
+ const a = env[r.vars[0]] ?? s;
174
+ const b = env[r.vars[1]] ?? last;
175
+ if (a === b) return;
176
+ let m = rel.out.get(a);
177
+ if (!m) rel.out.set(a, (m = new Map()));
178
+ if (m.has(b)) return;
179
+ m.set(b, ev);
180
+ let back = rel.in.get(b);
181
+ if (!back) rel.in.set(b, (back = new Map()));
182
+ back.set(a, ev);
183
+ });
184
+ }
185
+ }
186
+ this.busy.delete(key);
187
+ this.relations.set(key, rel);
188
+ return rel;
189
+ }
190
+
191
+ private enter(key: string): void {
192
+ if (this.busy.has(key)) {
193
+ throw new CapabilityError(`capability ${key} refers to itself through ${[...this.busy].join(" -> ")}`);
194
+ }
195
+ this.busy.add(key);
196
+ }
197
+
198
+ private starts(head: NodeSpec): string[] {
199
+ if (!head.labels) return [...this.view.nodes.keys()];
200
+ return head.labels.flatMap((l) => this.byLabel.get(l) ?? []);
201
+ }
202
+
203
+ private resolve(v: Value, args: Args): Literal | undefined {
204
+ return "lit" in v ? v.lit : args[v.param];
205
+ }
206
+
207
+ private test(id: string, t: Test, args: Args, because: Evidence["because"]): boolean {
208
+ const result = ((): boolean => {
209
+ if (t.kind === "cap") {
210
+ const capArgs = this.bind(t.cap, t.args.map((v) => this.resolve(v, args)));
211
+ const ev = this.set(t.cap, capArgs).get(id);
212
+ if (ev && !t.negated) because.push({ capability: t.cap, id, evidence: ev });
213
+ return !!ev;
214
+ }
215
+ const n = this.view.nodes.get(id)!;
216
+ const a = n.attrs[t.attr];
217
+ if (t.op === "present") return present(a);
218
+ const values = t.values.map((v) => this.resolve(v, args));
219
+ // A test on a parameter nobody passed is left out, whatever else it names.
220
+ if (values.some((v) => v === undefined)) return !t.negated;
221
+ const given = values as Literal[];
222
+ const each = Array.isArray(a) ? a : [a];
223
+ switch (t.op) {
224
+ case "=":
225
+ case "in":
226
+ return each.some((x) => given.some((v) => equal(x, v)));
227
+ case "!=":
228
+ return !each.some((x) => equal(x, given[0]));
229
+ case "~":
230
+ return each.some((x) => typeof x === "string" && given.some((v) => typeof v === "string" && (glob(x, v) || glob(v, x))));
231
+ default: {
232
+ const v = Number(given[0]);
233
+ return each.some((x) => {
234
+ const nx = Number(x);
235
+ if (x === null || x === undefined || Number.isNaN(nx) || Number.isNaN(v)) return false;
236
+ return t.op === "<" ? nx < v : t.op === "<=" ? nx <= v : t.op === ">" ? nx > v : nx >= v;
237
+ });
238
+ }
239
+ }
240
+ })();
241
+ return t.negated ? !result : result;
242
+ }
243
+
244
+ private ok(id: string, s: NodeSpec, env: Record<string, string>, args: Args, because: Evidence["because"]): boolean {
245
+ if (s.v && env[s.v] !== undefined && env[s.v] !== id) return false;
246
+ const n = this.view.nodes.get(id);
247
+ if (!n) return false;
248
+ if (s.labels && !s.labels.includes(n.label)) return false;
249
+ return s.tests.every((t) => this.test(id, t, args, because));
250
+ }
251
+
252
+ private hop(id: string, step: Step, args: Args): { to: string; hops: ViewHop[] }[] {
253
+ const out: { to: string; hops: ViewHop[] }[] = [];
254
+ for (const n of step.names) {
255
+ if (this.rules.has(n.name)) {
256
+ const rel = this.relation(n.name, this.bind(n.name, n.args.map((v) => this.resolve(v, args))));
257
+ const m = (step.dir === "out" ? rel.out : rel.in).get(id);
258
+ if (m) for (const [to, ev] of m) out.push({ to, hops: step.dir === "out" ? ev.hops : reverseHops(ev.hops) });
259
+ } else {
260
+ out.push(...((step.dir === "out" ? this.out : this.in).get(id)?.get(n.name) ?? []));
261
+ }
262
+ }
263
+ return out;
264
+ }
265
+
266
+ /** Every node within the step's depth range, by its shortest walk. */
267
+ private walk(id: string, step: Step, args: Args): { to: string; hops: ViewHop[] }[] {
268
+ const res: { to: string; hops: ViewHop[] }[] = [];
269
+ const seen = new Set([id]);
270
+ let frontier = [{ to: id, hops: [] as ViewHop[] }];
271
+ if (step.min === 0) res.push(frontier[0]);
272
+ for (let d = 1; d <= step.max && frontier.length > 0; d++) {
273
+ const next: typeof frontier = [];
274
+ for (const f of frontier) {
275
+ for (const h of this.hop(f.to, step, args)) {
276
+ if (step.max > 1) {
277
+ if (seen.has(h.to)) continue;
278
+ seen.add(h.to);
279
+ }
280
+ const p = { to: h.to, hops: [...f.hops, ...h.hops] };
281
+ next.push(p);
282
+ if (d >= step.min) res.push(p);
283
+ }
284
+ }
285
+ frontier = next;
286
+ }
287
+ return res;
288
+ }
289
+
290
+ private match(
291
+ alt: Alternative,
292
+ start: string,
293
+ args: Args,
294
+ emit: (env: Record<string, string>, ev: Evidence, last: string) => void,
295
+ ): void {
296
+ const because0: Evidence["because"] = [];
297
+ if (!this.ok(start, alt.head, {}, args, because0)) return;
298
+ const env0: Record<string, string> = alt.head.v ? { [alt.head.v]: start } : {};
299
+ const go = (k: number, at: string, env: Record<string, string>, hops: ViewHop[], because: Evidence["because"]): void => {
300
+ if (k === alt.steps.length) return emit(env, { hops, because }, at);
301
+ const st = alt.steps[k];
302
+ if (st.negated) {
303
+ const blocked = this.walk(at, st, args).some((w) => this.ok(w.to, st.node, env, args, []));
304
+ if (!blocked) go(k + 1, at, env, hops, because);
305
+ return;
306
+ }
307
+ for (const w of this.walk(at, st, args)) {
308
+ const b: Evidence["because"] = [];
309
+ if (!this.ok(w.to, st.node, env, args, b)) continue;
310
+ go(k + 1, w.to, st.node.v ? { ...env, [st.node.v]: w.to } : env, [...hops, ...w.hops], [...because, ...b]);
311
+ }
312
+ };
313
+ go(0, start, env0, [], because0);
314
+ }
315
+ }