@intentius/chant 0.124.52 → 0.124.54

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 (584) hide show
  1. package/dist/audit/discover.d.ts.map +1 -1
  2. package/dist/audit/discover.js +3 -1
  3. package/dist/behaviour.d.ts +1 -1
  4. package/dist/behaviour.d.ts.map +1 -1
  5. package/dist/capabilities/templates.d.ts +65 -0
  6. package/dist/capabilities/templates.d.ts.map +1 -0
  7. package/dist/capabilities/templates.js +193 -0
  8. package/dist/capabilities/templates.json +145 -0
  9. package/dist/change-set-graph.d.ts +35 -3
  10. package/dist/change-set-graph.d.ts.map +1 -1
  11. package/dist/change-set-graph.js +60 -9
  12. package/dist/change-set.d.ts +65 -7
  13. package/dist/change-set.d.ts.map +1 -1
  14. package/dist/change-set.js +23 -12
  15. package/dist/ci-identity.d.ts +7 -2
  16. package/dist/ci-identity.d.ts.map +1 -1
  17. package/dist/ci-identity.js +4 -1
  18. package/dist/cli/commands/import-index.d.ts +52 -0
  19. package/dist/cli/commands/import-index.d.ts.map +1 -0
  20. package/dist/cli/commands/import-index.js +226 -0
  21. package/dist/cli/commands/lint.d.ts.map +1 -1
  22. package/dist/cli/commands/lint.js +4 -2
  23. package/dist/cli/handlers/components.d.ts.map +1 -1
  24. package/dist/cli/handlers/components.js +11 -2
  25. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  26. package/dist/cli/handlers/fan-out.js +16 -3
  27. package/dist/cli/handlers/graph.d.ts.map +1 -1
  28. package/dist/cli/handlers/graph.js +22 -4
  29. package/dist/cli/handlers/index-cloud.d.ts +14 -0
  30. package/dist/cli/handlers/index-cloud.d.ts.map +1 -0
  31. package/dist/cli/handlers/index-cloud.js +22 -0
  32. package/dist/cli/handlers/index-diff.d.ts +18 -0
  33. package/dist/cli/handlers/index-diff.d.ts.map +1 -0
  34. package/dist/cli/handlers/index-diff.js +142 -0
  35. package/dist/cli/handlers/lifecycle-drift.d.ts +25 -0
  36. package/dist/cli/handlers/lifecycle-drift.d.ts.map +1 -0
  37. package/dist/cli/handlers/lifecycle-drift.js +64 -0
  38. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  39. package/dist/cli/handlers/lifecycle.js +188 -28
  40. package/dist/cli/handlers/misc.d.ts +9 -0
  41. package/dist/cli/handlers/misc.d.ts.map +1 -1
  42. package/dist/cli/handlers/misc.js +77 -0
  43. package/dist/cli/handlers/pr.d.ts.map +1 -1
  44. package/dist/cli/handlers/pr.js +15 -2
  45. package/dist/cli/handlers/promote.d.ts.map +1 -1
  46. package/dist/cli/handlers/promote.js +89 -15
  47. package/dist/cli/handlers/query.d.ts.map +1 -1
  48. package/dist/cli/handlers/query.js +28 -4
  49. package/dist/cli/handlers/scenario.d.ts.map +1 -1
  50. package/dist/cli/handlers/scenario.js +8 -7
  51. package/dist/cli/handlers/search.d.ts +34 -4
  52. package/dist/cli/handlers/search.d.ts.map +1 -1
  53. package/dist/cli/handlers/search.js +216 -36
  54. package/dist/cli/main.d.ts.map +1 -1
  55. package/dist/cli/main.js +55 -1
  56. package/dist/cli/mcp/lifecycle-tools.d.ts.map +1 -1
  57. package/dist/cli/mcp/lifecycle-tools.js +3 -2
  58. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  59. package/dist/cli/mcp/resource-handlers.js +4 -3
  60. package/dist/cli/mcp/workspace-tools.js +1 -1
  61. package/dist/cli/parse-args.d.ts.map +1 -1
  62. package/dist/cli/parse-args.js +55 -2
  63. package/dist/cli/registry.d.ts +19 -1
  64. package/dist/cli/registry.d.ts.map +1 -1
  65. package/dist/cloud-lister/aws.d.ts +35 -0
  66. package/dist/cloud-lister/aws.d.ts.map +1 -0
  67. package/dist/cloud-lister/aws.js +203 -0
  68. package/dist/cloud-lister/azure.d.ts +34 -0
  69. package/dist/cloud-lister/azure.d.ts.map +1 -0
  70. package/dist/cloud-lister/azure.js +129 -0
  71. package/dist/cloud-lister/common.d.ts +40 -0
  72. package/dist/cloud-lister/common.d.ts.map +1 -0
  73. package/dist/cloud-lister/common.js +83 -0
  74. package/dist/cloud-lister/credentials.d.ts +50 -0
  75. package/dist/cloud-lister/credentials.d.ts.map +1 -0
  76. package/dist/cloud-lister/credentials.js +86 -0
  77. package/dist/cloud-lister/fakes.d.ts +27 -0
  78. package/dist/cloud-lister/fakes.d.ts.map +1 -0
  79. package/dist/cloud-lister/fakes.js +50 -0
  80. package/dist/cloud-lister/gcp.d.ts +42 -0
  81. package/dist/cloud-lister/gcp.d.ts.map +1 -0
  82. package/dist/cloud-lister/gcp.js +143 -0
  83. package/dist/cloud-lister/guard.d.ts +49 -0
  84. package/dist/cloud-lister/guard.d.ts.map +1 -0
  85. package/dist/cloud-lister/guard.js +103 -0
  86. package/dist/cloud-lister/ids.d.ts +23 -0
  87. package/dist/cloud-lister/ids.d.ts.map +1 -0
  88. package/dist/cloud-lister/ids.js +42 -0
  89. package/dist/cloud-lister/index.d.ts +67 -0
  90. package/dist/cloud-lister/index.d.ts.map +1 -0
  91. package/dist/cloud-lister/index.js +102 -0
  92. package/dist/cloud-lister/kubernetes.d.ts +64 -0
  93. package/dist/cloud-lister/kubernetes.d.ts.map +1 -0
  94. package/dist/cloud-lister/kubernetes.js +276 -0
  95. package/dist/cloud-lister/markers.d.ts +31 -0
  96. package/dist/cloud-lister/markers.d.ts.map +1 -0
  97. package/dist/cloud-lister/markers.js +73 -0
  98. package/dist/cloud-lister/mask.d.ts +31 -0
  99. package/dist/cloud-lister/mask.d.ts.map +1 -0
  100. package/dist/cloud-lister/mask.js +74 -0
  101. package/dist/cloud-lister/sigv4.d.ts +29 -0
  102. package/dist/cloud-lister/sigv4.d.ts.map +1 -0
  103. package/dist/cloud-lister/sigv4.js +54 -0
  104. package/dist/cloud-lister/transport.d.ts +55 -0
  105. package/dist/cloud-lister/transport.d.ts.map +1 -0
  106. package/dist/cloud-lister/transport.js +86 -0
  107. package/dist/cloud-lister/types.d.ts +121 -0
  108. package/dist/cloud-lister/types.d.ts.map +1 -0
  109. package/dist/cloud-lister/types.js +24 -0
  110. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  111. package/dist/components/capability-plugin-loader.js +6 -0
  112. package/dist/components/capability-plugin.d.ts +9 -0
  113. package/dist/components/capability-plugin.d.ts.map +1 -1
  114. package/dist/components/capability.d.ts +215 -0
  115. package/dist/components/capability.d.ts.map +1 -1
  116. package/dist/components/cli-support.d.ts +21 -0
  117. package/dist/components/cli-support.d.ts.map +1 -1
  118. package/dist/components/cli-support.js +58 -14
  119. package/dist/components/declared-reads.d.ts +38 -0
  120. package/dist/components/declared-reads.d.ts.map +1 -0
  121. package/dist/components/declared-reads.js +131 -0
  122. package/dist/components/deploy-units.d.ts.map +1 -1
  123. package/dist/components/deploy-units.js +4 -0
  124. package/dist/components/driver.d.ts +34 -1
  125. package/dist/components/driver.d.ts.map +1 -1
  126. package/dist/components/driver.js +66 -3
  127. package/dist/components/fan-out-run.d.ts +23 -1
  128. package/dist/components/fan-out-run.d.ts.map +1 -1
  129. package/dist/components/fan-out-run.js +82 -14
  130. package/dist/components/fan-out-support.d.ts +6 -0
  131. package/dist/components/fan-out-support.d.ts.map +1 -1
  132. package/dist/components/fan-out-support.js +4 -1
  133. package/dist/components/fan-out.d.ts +28 -0
  134. package/dist/components/fan-out.d.ts.map +1 -1
  135. package/dist/components/groups.d.ts +229 -0
  136. package/dist/components/groups.d.ts.map +1 -0
  137. package/dist/components/groups.js +760 -0
  138. package/dist/components/index.d.ts +6 -2
  139. package/dist/components/index.d.ts.map +1 -1
  140. package/dist/components/index.js +4 -0
  141. package/dist/components/plan-shape-conformance.d.ts +48 -0
  142. package/dist/components/plan-shape-conformance.d.ts.map +1 -0
  143. package/dist/components/plan-shape-conformance.js +122 -0
  144. package/dist/components/pr-run.d.ts +41 -4
  145. package/dist/components/pr-run.d.ts.map +1 -1
  146. package/dist/components/pr-run.js +209 -39
  147. package/dist/components/promote-rounds.d.ts +9 -0
  148. package/dist/components/promote-rounds.d.ts.map +1 -1
  149. package/dist/components/promote-rounds.js +23 -2
  150. package/dist/components/promote.d.ts +17 -0
  151. package/dist/components/promote.d.ts.map +1 -1
  152. package/dist/components/promote.js +36 -6
  153. package/dist/components/release-gate.d.ts +23 -1
  154. package/dist/components/release-gate.d.ts.map +1 -1
  155. package/dist/components/release-gate.js +97 -33
  156. package/dist/components/run-groups.d.ts +58 -0
  157. package/dist/components/run-groups.d.ts.map +1 -0
  158. package/dist/components/run-groups.js +78 -0
  159. package/dist/components/starter-plugin.d.ts +1 -0
  160. package/dist/components/starter-plugin.d.ts.map +1 -1
  161. package/dist/components/starter-plugin.js +6 -1
  162. package/dist/components/verbs/index.d.ts +1 -0
  163. package/dist/components/verbs/index.d.ts.map +1 -1
  164. package/dist/components/verbs/index.js +1 -0
  165. package/dist/components/verbs/member-outputs.d.ts +187 -0
  166. package/dist/components/verbs/member-outputs.d.ts.map +1 -0
  167. package/dist/components/verbs/member-outputs.js +218 -0
  168. package/dist/config.d.ts +60 -0
  169. package/dist/config.d.ts.map +1 -1
  170. package/dist/config.js +27 -0
  171. package/dist/deep-observation.d.ts +1 -13
  172. package/dist/deep-observation.d.ts.map +1 -1
  173. package/dist/deep-observation.js +5 -22
  174. package/dist/drift-record.d.ts +542 -0
  175. package/dist/drift-record.d.ts.map +1 -0
  176. package/dist/drift-record.js +886 -0
  177. package/dist/engine-facts.d.ts +144 -0
  178. package/dist/engine-facts.d.ts.map +1 -0
  179. package/dist/engine-facts.js +14 -0
  180. package/dist/graph-ir.d.ts +153 -2
  181. package/dist/graph-ir.d.ts.map +1 -1
  182. package/dist/graph-ir.js +224 -6
  183. package/dist/graph-refs.d.ts +145 -0
  184. package/dist/graph-refs.d.ts.map +1 -1
  185. package/dist/graph-refs.js +305 -0
  186. package/dist/graph-schema/fixtures/adopt.json +15 -0
  187. package/dist/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  188. package/dist/graph-schema/fixtures/index.json +68 -0
  189. package/dist/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  190. package/dist/graph-schema/fixtures.d.ts +23 -0
  191. package/dist/graph-schema/fixtures.d.ts.map +1 -0
  192. package/dist/graph-schema/fixtures.js +246 -0
  193. package/dist/graph-schema/generate.d.ts +15 -0
  194. package/dist/graph-schema/generate.d.ts.map +1 -0
  195. package/dist/graph-schema/generate.js +267 -0
  196. package/dist/graph-schema/graph.schema.json +1387 -0
  197. package/dist/health.schema.json +2 -1
  198. package/dist/identity.d.ts.map +1 -1
  199. package/dist/identity.js +2 -0
  200. package/dist/index.d.ts +1 -0
  201. package/dist/index.d.ts.map +1 -1
  202. package/dist/index.js +2 -0
  203. package/dist/instance-nodes.d.ts +159 -0
  204. package/dist/instance-nodes.d.ts.map +1 -0
  205. package/dist/instance-nodes.js +231 -0
  206. package/dist/lexicon.d.ts +72 -0
  207. package/dist/lexicon.d.ts.map +1 -1
  208. package/dist/lifecycle/adoption-file.d.ts +56 -0
  209. package/dist/lifecycle/adoption-file.d.ts.map +1 -0
  210. package/dist/lifecycle/adoption-file.js +123 -0
  211. package/dist/lifecycle/cloud-index.d.ts +186 -0
  212. package/dist/lifecycle/cloud-index.d.ts.map +1 -0
  213. package/dist/lifecycle/cloud-index.js +618 -0
  214. package/dist/lifecycle/derive-edges.d.ts +59 -0
  215. package/dist/lifecycle/derive-edges.d.ts.map +1 -0
  216. package/dist/lifecycle/derive-edges.js +126 -0
  217. package/dist/lifecycle/git.d.ts +10 -9
  218. package/dist/lifecycle/git.d.ts.map +1 -1
  219. package/dist/lifecycle/git.js +7 -1
  220. package/dist/lifecycle/identity-match.d.ts +133 -0
  221. package/dist/lifecycle/identity-match.d.ts.map +1 -0
  222. package/dist/lifecycle/identity-match.js +147 -0
  223. package/dist/lifecycle/index-diff.d.ts +224 -0
  224. package/dist/lifecycle/index-diff.d.ts.map +1 -0
  225. package/dist/lifecycle/index-diff.js +327 -0
  226. package/dist/lifecycle/index-document.d.ts +130 -0
  227. package/dist/lifecycle/index-document.d.ts.map +1 -0
  228. package/dist/lifecycle/index-document.js +189 -0
  229. package/dist/lifecycle/index-drift.d.ts +121 -0
  230. package/dist/lifecycle/index-drift.d.ts.map +1 -0
  231. package/dist/lifecycle/index-drift.js +178 -0
  232. package/dist/lifecycle/index-import.d.ts +168 -0
  233. package/dist/lifecycle/index-import.d.ts.map +1 -0
  234. package/dist/lifecycle/index-import.js +515 -0
  235. package/dist/lifecycle/index-join.d.ts +129 -0
  236. package/dist/lifecycle/index-join.d.ts.map +1 -0
  237. package/dist/lifecycle/index-join.js +248 -0
  238. package/dist/lifecycle/index.d.ts +4 -0
  239. package/dist/lifecycle/index.d.ts.map +1 -1
  240. package/dist/lifecycle/index.js +4 -0
  241. package/dist/lifecycle/observation-baseline.d.ts +61 -21
  242. package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
  243. package/dist/lifecycle/observation-baseline.js +144 -19
  244. package/dist/lifecycle/observe.d.ts.map +1 -1
  245. package/dist/lifecycle/observe.js +6 -1
  246. package/dist/lifecycle/query.d.ts +45 -4
  247. package/dist/lifecycle/query.d.ts.map +1 -1
  248. package/dist/lifecycle/query.js +89 -7
  249. package/dist/lifecycle/replay.d.ts +10 -3
  250. package/dist/lifecycle/replay.d.ts.map +1 -1
  251. package/dist/lifecycle/replay.js +10 -6
  252. package/dist/lifecycle/scenario.d.ts +4 -3
  253. package/dist/lifecycle/scenario.d.ts.map +1 -1
  254. package/dist/lifecycle/snapshot-store-fake.d.ts +9 -0
  255. package/dist/lifecycle/snapshot-store-fake.d.ts.map +1 -0
  256. package/dist/lifecycle/snapshot-store-fake.js +21 -0
  257. package/dist/lifecycle/snapshot-store-s3.d.ts +102 -0
  258. package/dist/lifecycle/snapshot-store-s3.d.ts.map +1 -0
  259. package/dist/lifecycle/snapshot-store-s3.js +254 -0
  260. package/dist/lifecycle/snapshot-store.d.ts +170 -0
  261. package/dist/lifecycle/snapshot-store.d.ts.map +1 -0
  262. package/dist/lifecycle/snapshot-store.js +832 -0
  263. package/dist/lifecycle/snapshot.d.ts +11 -0
  264. package/dist/lifecycle/snapshot.d.ts.map +1 -1
  265. package/dist/lifecycle/snapshot.js +18 -5
  266. package/dist/lifecycle/type-listing.d.ts +148 -0
  267. package/dist/lifecycle/type-listing.d.ts.map +1 -0
  268. package/dist/lifecycle/type-listing.js +166 -0
  269. package/dist/lint/component-checks.d.ts +15 -1
  270. package/dist/lint/component-checks.d.ts.map +1 -1
  271. package/dist/lint/component-checks.js +1 -0
  272. package/dist/lint/presets/relaxed.json +2 -1
  273. package/dist/lint/presets/strict.json +2 -1
  274. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts +4 -0
  275. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts.map +1 -0
  276. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.js +13 -0
  277. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts +4 -0
  278. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts.map +1 -0
  279. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.js +8 -0
  280. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts +33 -0
  281. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts.map +1 -0
  282. package/dist/lint/rules/comp/comp008-applies-signal-only-root.js +123 -0
  283. package/dist/lint/rules/comp/index.d.ts +2 -1
  284. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  285. package/dist/lint/rules/comp/index.js +4 -1
  286. package/dist/observation.d.ts +19 -2
  287. package/dist/observation.d.ts.map +1 -1
  288. package/dist/observation.js +18 -1
  289. package/dist/op/activities/activity-contracts.d.ts +1 -1
  290. package/dist/op/activities/activity-contracts.js +1 -1
  291. package/dist/op/activities/change-set.d.ts +6 -4
  292. package/dist/op/activities/change-set.d.ts.map +1 -1
  293. package/dist/op/activities/change-set.js +4 -2
  294. package/dist/op/activity-failure.d.ts +27 -0
  295. package/dist/op/activity-failure.d.ts.map +1 -1
  296. package/dist/op/activity-failure.js +31 -0
  297. package/dist/op/index.d.ts +2 -1
  298. package/dist/op/index.d.ts.map +1 -1
  299. package/dist/op/index.js +1 -1
  300. package/dist/op/local-executor.d.ts +5 -1
  301. package/dist/op/local-executor.d.ts.map +1 -1
  302. package/dist/op/local-executor.js +22 -8
  303. package/dist/pr-loop.d.ts +56 -1
  304. package/dist/pr-loop.d.ts.map +1 -1
  305. package/dist/pr-loop.js +51 -1
  306. package/dist/pulumi-urn.d.ts +101 -0
  307. package/dist/pulumi-urn.d.ts.map +1 -0
  308. package/dist/pulumi-urn.js +131 -0
  309. package/dist/release-floors.d.ts +23 -0
  310. package/dist/release-floors.d.ts.map +1 -0
  311. package/dist/release-floors.js +22 -0
  312. package/dist/sensitive-key.d.ts +23 -0
  313. package/dist/sensitive-key.d.ts.map +1 -0
  314. package/dist/sensitive-key.js +31 -0
  315. package/dist/wave-runtime.mjs +234 -234
  316. package/dist/workspace/adoption-report.d.ts +53 -0
  317. package/dist/workspace/adoption-report.d.ts.map +1 -0
  318. package/dist/workspace/adoption-report.js +76 -0
  319. package/dist/workspace/capabilities-contract.d.ts +7 -0
  320. package/dist/workspace/capabilities-contract.d.ts.map +1 -1
  321. package/dist/workspace/capabilities-contract.js +2 -1
  322. package/dist/workspace/capabilities.schema.json +98 -0
  323. package/dist/workspace/change-set.schema.json +42 -3
  324. package/dist/workspace/ci-cloud-identity.d.ts +13 -1
  325. package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
  326. package/dist/workspace/ci-cloud-identity.js +30 -1
  327. package/dist/workspace/compose-graph.d.ts +10 -1
  328. package/dist/workspace/compose-graph.d.ts.map +1 -1
  329. package/dist/workspace/compose-graph.js +6 -1
  330. package/dist/workspace/conformance/index.d.ts +1 -1
  331. package/dist/workspace/conformance/index.d.ts.map +1 -1
  332. package/dist/workspace/conformance/index.js +6 -1
  333. package/dist/workspace/drift-cli.d.ts +81 -0
  334. package/dist/workspace/drift-cli.d.ts.map +1 -0
  335. package/dist/workspace/drift-cli.js +317 -0
  336. package/dist/workspace/drift.schema.json +672 -0
  337. package/dist/workspace/graph-cli.d.ts +2 -0
  338. package/dist/workspace/graph-cli.d.ts.map +1 -1
  339. package/dist/workspace/graph-cli.js +3 -0
  340. package/dist/workspace/graph.schema.json +72 -0
  341. package/dist/workspace/init.d.ts +5 -1
  342. package/dist/workspace/init.d.ts.map +1 -1
  343. package/dist/workspace/init.js +55 -9
  344. package/dist/workspace/ledger.schema.json +1 -1
  345. package/dist/workspace/nested-graph.d.ts.map +1 -1
  346. package/dist/workspace/nested-graph.js +2 -0
  347. package/dist/workspace/pr-report.schema.json +51 -2
  348. package/dist/workspace/promote-waves.d.ts +112 -0
  349. package/dist/workspace/promote-waves.d.ts.map +1 -0
  350. package/dist/workspace/promote-waves.js +290 -0
  351. package/dist/workspace/promote.d.ts +84 -2
  352. package/dist/workspace/promote.d.ts.map +1 -1
  353. package/dist/workspace/promote.js +347 -61
  354. package/dist/workspace/reason-codes.d.ts +12 -0
  355. package/dist/workspace/reason-codes.d.ts.map +1 -1
  356. package/dist/workspace/reason-codes.js +14 -0
  357. package/dist/workspace/search-contract.d.ts +3 -3
  358. package/dist/workspace/search-contract.d.ts.map +1 -1
  359. package/dist/workspace/search-contract.js +2 -0
  360. package/dist/workspace/search.schema.json +103 -5
  361. package/package.json +14 -1
  362. package/src/__fixtures__/drift-record/README.md +58 -0
  363. package/src/__fixtures__/drift-record/choudoufu-cone.ndjson +4 -0
  364. package/src/__fixtures__/drift-record/choudoufu-resource.ndjson +3 -0
  365. package/src/__fixtures__/drift-record/component-status-ledger.json +65 -0
  366. package/src/__fixtures__/drift-record/component-status.json +91 -0
  367. package/src/__fixtures__/drift-record/deep-diff.json +259 -0
  368. package/src/__fixtures__/drift-record/lifecycle-diff-live.json +825 -0
  369. package/src/__fixtures__/drift-record/live-diff.json +125 -0
  370. package/src/audit/discover.e2e.test.ts +14 -0
  371. package/src/audit/discover.ts +3 -1
  372. package/src/behaviour.ts +1 -1
  373. package/src/capabilities/templates.json +145 -0
  374. package/src/capabilities/templates.test.ts +212 -0
  375. package/src/capabilities/templates.ts +204 -0
  376. package/src/change-set-bundle.test.ts +83 -0
  377. package/src/change-set-graph.ts +80 -9
  378. package/src/change-set.test.ts +24 -0
  379. package/src/change-set.ts +77 -14
  380. package/src/ci-identity-targets.test.ts +23 -0
  381. package/src/ci-identity.ts +10 -4
  382. package/src/cli/commands/import-index.test.ts +117 -0
  383. package/src/cli/commands/import-index.ts +265 -0
  384. package/src/cli/commands/lint.ts +4 -2
  385. package/src/cli/handlers/components.test.ts +9 -0
  386. package/src/cli/handlers/components.ts +12 -2
  387. package/src/cli/handlers/fan-out.ts +17 -3
  388. package/src/cli/handlers/graph.test.ts +42 -0
  389. package/src/cli/handlers/graph.ts +26 -4
  390. package/src/cli/handlers/index-cloud.ts +32 -0
  391. package/src/cli/handlers/index-diff.test.ts +68 -0
  392. package/src/cli/handlers/index-diff.ts +146 -0
  393. package/src/cli/handlers/ledger-root-member.test.ts +161 -0
  394. package/src/cli/handlers/lifecycle-drift.ts +68 -0
  395. package/src/cli/handlers/lifecycle.test.ts +33 -11
  396. package/src/cli/handlers/lifecycle.ts +205 -30
  397. package/src/cli/handlers/misc.ts +73 -0
  398. package/src/cli/handlers/pr-waves-blocked.test.ts +37 -2
  399. package/src/cli/handlers/pr.ts +14 -2
  400. package/src/cli/handlers/promote.test.ts +64 -0
  401. package/src/cli/handlers/promote.ts +81 -6
  402. package/src/cli/handlers/query.ts +27 -4
  403. package/src/cli/handlers/run-declared-reads-cli.test.ts +187 -0
  404. package/src/cli/handlers/run-groups-cli.test.ts +229 -0
  405. package/src/cli/handlers/scenario.test.ts +13 -0
  406. package/src/cli/handlers/scenario.ts +8 -7
  407. package/src/cli/handlers/search-index.test.ts +255 -0
  408. package/src/cli/handlers/search-json.test.ts +1 -1
  409. package/src/cli/handlers/search-ownership.test.ts +194 -0
  410. package/src/cli/handlers/search.ts +271 -38
  411. package/src/cli/main.test.ts +7 -0
  412. package/src/cli/main.ts +56 -1
  413. package/src/cli/mcp/lifecycle-tools.ts +3 -2
  414. package/src/cli/mcp/resource-handlers.ts +4 -3
  415. package/src/cli/mcp/workspace-tools.ts +1 -1
  416. package/src/cli/parse-args.ts +40 -2
  417. package/src/cli/registry.ts +19 -1
  418. package/src/cloud-lister/aws.test.ts +202 -0
  419. package/src/cloud-lister/aws.ts +226 -0
  420. package/src/cloud-lister/azure.test.ts +132 -0
  421. package/src/cloud-lister/azure.ts +142 -0
  422. package/src/cloud-lister/common.ts +115 -0
  423. package/src/cloud-lister/credentials.ts +110 -0
  424. package/src/cloud-lister/fakes.ts +66 -0
  425. package/src/cloud-lister/gcp.test.ts +121 -0
  426. package/src/cloud-lister/gcp.ts +159 -0
  427. package/src/cloud-lister/guard.test.ts +198 -0
  428. package/src/cloud-lister/guard.ts +111 -0
  429. package/src/cloud-lister/ids.ts +54 -0
  430. package/src/cloud-lister/index.ts +134 -0
  431. package/src/cloud-lister/kubernetes.test.ts +160 -0
  432. package/src/cloud-lister/kubernetes.ts +284 -0
  433. package/src/cloud-lister/markers.ts +74 -0
  434. package/src/cloud-lister/mask.ts +77 -0
  435. package/src/cloud-lister/shape.test.ts +81 -0
  436. package/src/cloud-lister/sigv4.ts +70 -0
  437. package/src/cloud-lister/transport.ts +118 -0
  438. package/src/cloud-lister/types.ts +135 -0
  439. package/src/components/capability-plugin-loader.ts +4 -0
  440. package/src/components/capability-plugin.ts +10 -0
  441. package/src/components/capability.ts +229 -0
  442. package/src/components/cli-support.ts +70 -14
  443. package/src/components/declared-reads.test.ts +103 -0
  444. package/src/components/declared-reads.ts +134 -0
  445. package/src/components/deploy-units.ts +4 -0
  446. package/src/components/driver.ts +89 -4
  447. package/src/components/fan-out-run.ts +95 -15
  448. package/src/components/fan-out-support.ts +10 -1
  449. package/src/components/fan-out.ts +30 -0
  450. package/src/components/groups.test.ts +320 -0
  451. package/src/components/groups.ts +880 -0
  452. package/src/components/index.ts +42 -0
  453. package/src/components/plan-shape-conformance.ts +130 -0
  454. package/src/components/pr-env-run-bundle.test.ts +2 -0
  455. package/src/components/pr-run.test.ts +516 -3
  456. package/src/components/pr-run.ts +231 -41
  457. package/src/components/promote-rounds.ts +25 -2
  458. package/src/components/promote.ts +55 -5
  459. package/src/components/registry.test.ts +1 -1
  460. package/src/components/release-gate.ts +115 -30
  461. package/src/components/release-groups.test.ts +362 -0
  462. package/src/components/run-groups.ts +113 -0
  463. package/src/components/starter-plugin.ts +6 -0
  464. package/src/components/verbs/index.ts +1 -0
  465. package/src/components/verbs/member-outputs.test.ts +205 -0
  466. package/src/components/verbs/member-outputs.ts +308 -0
  467. package/src/config.ts +44 -0
  468. package/src/deep-observation.ts +5 -23
  469. package/src/drift-record.test.ts +596 -0
  470. package/src/drift-record.ts +1206 -0
  471. package/src/engine-facts.guard.test.ts +111 -0
  472. package/src/engine-facts.test.ts +178 -0
  473. package/src/engine-facts.ts +154 -0
  474. package/src/gated-waves-bundle.test.ts +2 -0
  475. package/src/graph-ir-live.test.ts +92 -0
  476. package/src/graph-ir.ts +317 -7
  477. package/src/graph-refs.ts +416 -0
  478. package/src/graph-schema/fixtures/adopt.json +15 -0
  479. package/src/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  480. package/src/graph-schema/fixtures/index.json +68 -0
  481. package/src/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  482. package/src/graph-schema/fixtures.ts +267 -0
  483. package/src/graph-schema/generate.ts +263 -0
  484. package/src/graph-schema/graph-schema.test.ts +153 -0
  485. package/src/graph-schema/graph.schema.json +1387 -0
  486. package/src/health.schema.json +2 -1
  487. package/src/identity.ts +2 -0
  488. package/src/index.ts +2 -0
  489. package/src/instance-nodes.ts +288 -0
  490. package/src/lexicon.ts +76 -0
  491. package/src/lifecycle/__fixtures__/index-diff/20261026T120000Z-aaaaaaaaaaaa.json +149 -0
  492. package/src/lifecycle/__fixtures__/index-diff/20261026T130000Z-bbbbbbbbbbbb.json +127 -0
  493. package/src/lifecycle/adoption-file.test.ts +100 -0
  494. package/src/lifecycle/adoption-file.ts +154 -0
  495. package/src/lifecycle/cloud-index.test.ts +517 -0
  496. package/src/lifecycle/cloud-index.ts +736 -0
  497. package/src/lifecycle/derive-edges.test.ts +193 -0
  498. package/src/lifecycle/derive-edges.ts +182 -0
  499. package/src/lifecycle/git.ts +10 -4
  500. package/src/lifecycle/identity-match.test.ts +308 -0
  501. package/src/lifecycle/identity-match.ts +257 -0
  502. package/src/lifecycle/index-diff.test.ts +198 -0
  503. package/src/lifecycle/index-diff.ts +476 -0
  504. package/src/lifecycle/index-document.test.ts +64 -0
  505. package/src/lifecycle/index-document.ts +299 -0
  506. package/src/lifecycle/index-drift.test.ts +191 -0
  507. package/src/lifecycle/index-drift.ts +304 -0
  508. package/src/lifecycle/index-import.test.ts +255 -0
  509. package/src/lifecycle/index-import.ts +634 -0
  510. package/src/lifecycle/index-join.test.ts +250 -0
  511. package/src/lifecycle/index-join.ts +304 -0
  512. package/src/lifecycle/index-store-load-bearing.test.ts +187 -0
  513. package/src/lifecycle/index.ts +4 -0
  514. package/src/lifecycle/member-ledger.test.ts +25 -7
  515. package/src/lifecycle/observation-baseline.test.ts +72 -1
  516. package/src/lifecycle/observation-baseline.ts +190 -27
  517. package/src/lifecycle/observe.ts +6 -1
  518. package/src/lifecycle/query.test.ts +69 -1
  519. package/src/lifecycle/query.ts +103 -10
  520. package/src/lifecycle/replay.test.ts +9 -5
  521. package/src/lifecycle/replay.ts +9 -5
  522. package/src/lifecycle/scenario.ts +4 -3
  523. package/src/lifecycle/snapshot-store-fake.ts +29 -0
  524. package/src/lifecycle/snapshot-store-s3.ts +316 -0
  525. package/src/lifecycle/snapshot-store.test.ts +385 -0
  526. package/src/lifecycle/snapshot-store.ts +981 -0
  527. package/src/lifecycle/snapshot.test.ts +13 -0
  528. package/src/lifecycle/snapshot.ts +23 -6
  529. package/src/lifecycle/type-listing.test.ts +166 -0
  530. package/src/lifecycle/type-listing.ts +309 -0
  531. package/src/lint/component-checks.ts +17 -1
  532. package/src/lint/config.test.ts +3 -0
  533. package/src/lint/presets/relaxed.json +2 -1
  534. package/src/lint/presets/strict.json +2 -1
  535. package/src/lint/rules/__fixtures__/comp/comp008/fail/dns.component.ts +15 -0
  536. package/src/lint/rules/__fixtures__/comp/comp008/pass/dns.component.ts +10 -0
  537. package/src/lint/rules/comp/comp.test.ts +2 -1
  538. package/src/lint/rules/comp/comp008-applies-signal-only-root.ts +121 -0
  539. package/src/lint/rules/comp/comp008.test.ts +77 -0
  540. package/src/lint/rules/comp/index.ts +4 -1
  541. package/src/observation-edges.test.ts +33 -0
  542. package/src/observation.ts +36 -1
  543. package/src/op/activities/activity-contracts.ts +1 -1
  544. package/src/op/activities/change-set.ts +8 -5
  545. package/src/op/activity-failure.ts +36 -0
  546. package/src/op/index.ts +2 -1
  547. package/src/op/local-executor.test.ts +80 -0
  548. package/src/op/local-executor.ts +27 -9
  549. package/src/pr-loop-bundle.test.ts +5 -2
  550. package/src/pr-loop.test.ts +43 -0
  551. package/src/pr-loop.ts +111 -2
  552. package/src/pulumi-urn.ts +151 -0
  553. package/src/release-floors.ts +22 -0
  554. package/src/sensitive-key.ts +34 -0
  555. package/src/workspace/adoption-report.test.ts +61 -0
  556. package/src/workspace/adoption-report.ts +103 -0
  557. package/src/workspace/capabilities-contract.test.ts +4 -0
  558. package/src/workspace/capabilities-contract.ts +9 -1
  559. package/src/workspace/capabilities.schema.json +98 -0
  560. package/src/workspace/change-set.schema.json +42 -3
  561. package/src/workspace/ci-cloud-identity.ts +31 -1
  562. package/src/workspace/compose-graph.test.ts +12 -0
  563. package/src/workspace/compose-graph.ts +12 -1
  564. package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
  565. package/src/workspace/conformance/index.ts +6 -1
  566. package/src/workspace/drift-cli.test.ts +65 -0
  567. package/src/workspace/drift-cli.ts +365 -0
  568. package/src/workspace/drift.schema.json +672 -0
  569. package/src/workspace/graph-cli.ts +5 -0
  570. package/src/workspace/graph.schema.json +72 -0
  571. package/src/workspace/init.test.ts +38 -1
  572. package/src/workspace/init.ts +50 -8
  573. package/src/workspace/intent-gaps.test.ts +18 -2
  574. package/src/workspace/ledger.schema.json +1 -1
  575. package/src/workspace/nested-graph.ts +1 -0
  576. package/src/workspace/pr-report.schema.json +51 -2
  577. package/src/workspace/promote-waves.test.ts +296 -0
  578. package/src/workspace/promote-waves.ts +340 -0
  579. package/src/workspace/promote.test.ts +158 -4
  580. package/src/workspace/promote.ts +398 -57
  581. package/src/workspace/reason-codes.test.ts +4 -1
  582. package/src/workspace/reason-codes.ts +14 -0
  583. package/src/workspace/search-contract.ts +2 -0
  584. package/src/workspace/search.schema.json +103 -5
@@ -19,6 +19,8 @@ import { parseCountBy, countGroups, countsJson, formatCounts, groupMembers, hasM
19
19
  import { formatError, formatWarning } from "../format.js";
20
20
  import { adjacencyOf, walkBreadthFirst } from "../../graph-walk.js";
21
21
  import { SEARCH_CONTRACT_VERSION, SEARCH_OUTPUT_SCHEMA_ID } from "../../workspace/search-contract.js";
22
+ import { isNoLexiconDetected } from "../../detectLexicon.js";
23
+ import { countJoins, formatIndexRef, indexOnlyGraph, joinCell, joinDeclaredToIndex, parseIndexRef, readIndexRef, } from "../../lifecycle/index-join.js";
22
24
  /**
23
25
  * `chant search <query> [--live --env <name>]` — answer an estate question with
24
26
  * a COMPACT result instead of the whole graph. The point (measured on aws-bench,
@@ -31,11 +33,17 @@ import { SEARCH_CONTRACT_VERSION, SEARCH_OUTPUT_SCHEMA_ID } from "../../workspac
31
33
  * on a terraform resource, its type (kind:aws_instance, kind:aws_iam_)
32
34
  * tag:<key>=<val> a Tags entry with Key=key and Value containing val
33
35
  * attr:<name>=<val> attribute <name> equals/contains <val>
36
+ * id:<cloud id> physicalId or an engine cloudIds value is exactly <cloud id> (#4534)
34
37
  * ->kind:X / ->attr:.. this node has an edge TO a node matching the right side
35
38
  * <-kind:X / <-attr:.. this node has an edge FROM a node matching the right side
36
39
  * ->*X, ->{n}X, ->{m,n}X the far end is any depth / n / m..n hops away (#4359)
37
40
  * ->[via=a]X, ->[to=a]X only edges through consumer attr a / reading producer attr a
38
41
  *
42
+ * `--index <ref>` (#4525) answers from an index version in the store instead
43
+ * of a live read: the declared rows joined to it through each lexicon's index
44
+ * match, each row with its verdict, or, with no project, the index alone.
45
+ * See ../../lifecycle/index-join.ts.
46
+ *
39
47
  * The edge operators are the point of "edge-aware" search (#1139): a small
40
48
  * model shouldn't hand-join instance→subnet→public across many results — one
41
49
  * query does the traversal. `kind:Instance ->attr:MapPublicIpOnLaunch=true`
@@ -82,6 +90,10 @@ export async function runSearch(ctx) {
82
90
  const { config } = await loadChantConfig(projectPath);
83
91
  let ir;
84
92
  let source = { kind: "declared" };
93
+ // Each declared row's join verdict against an index version (#4525).
94
+ let joins;
95
+ // The lexicons a capability term reads an index-only graph through.
96
+ let indexPlugins;
85
97
  // Lexicons whose live read threw (#1263). "Nothing observed" and "could not
86
98
  // observe" are different claims; this is what carries the second one.
87
99
  const liveFailures = [];
@@ -107,7 +119,16 @@ export async function runSearch(ctx) {
107
119
  let driftFailure = false;
108
120
  // Why --check-snapshot had nothing to check against, for --json (#4367).
109
121
  let driftUnavailable;
110
- if (args.live || snapshotRef) {
122
+ if (args.index !== undefined) {
123
+ const answered = await indexAnswer(ctx, String(args.index), projectPath, resolve(args.src ?? config.sourceDir ?? "."), config);
124
+ if ("error" in answered)
125
+ return refuse(answered.error);
126
+ ir = answered.ir;
127
+ source = answered.source;
128
+ joins = answered.joins;
129
+ indexPlugins = answered.plugins;
130
+ }
131
+ else if (args.live || snapshotRef) {
111
132
  // checkSearchArgs refused a live or snapshot read without one.
112
133
  const environment = String(args.env);
113
134
  // Membership via matchesDeclaredEnvironment (#1221): handles `{ name,
@@ -328,7 +349,7 @@ export async function runSearch(ctx) {
328
349
  ir = enrichEffectiveTopology(ir);
329
350
  // Capability terms (#4375) read the graph through the lexicons' mappings.
330
351
  if (terms.some(usesCapability)) {
331
- const refused = await bindCapabilities(ctx, projectPath, ir, terms);
352
+ const refused = await bindCapabilities(ctx, projectPath, ir, terms, indexPlugins);
332
353
  if (refused)
333
354
  return refuse({ code: "query-invalid", ...refused });
334
355
  }
@@ -366,10 +387,10 @@ export async function runSearch(ctx) {
366
387
  const recorded = source.kind === "live" && !matches.some((n) => n.physicalId) && args.env
367
388
  ? (await hasSnapshot(String(args.env))) ? "yes" : undefined
368
389
  : undefined;
369
- const env = args.env && source.kind !== "declared" ? String(args.env) : undefined;
370
- const provenanceText = provenanceLine(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)]).replace(/^— /, "");
390
+ const env = args.env && (source.kind === "live" || source.kind === "snapshot") ? String(args.env) : undefined;
391
+ const provenanceText = provenanceLine(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)], joins).replace(/^— /, "");
371
392
  const capNotes = capabilityNotes(terms, ir, source);
372
- const plannedCreates = source.kind !== "declared" && liveFailures.length === 0 ? plannedCreateCount(matches) : 0;
393
+ const plannedCreates = (source.kind === "live" || source.kind === "snapshot") && liveFailures.length === 0 ? plannedCreateCount(matches) : 0;
373
394
  const driftJson = drift
374
395
  ? searchDriftJson(drift, matches.length, driftAgainst, snapshotDepth)
375
396
  : driftUnavailable !== undefined
@@ -397,6 +418,7 @@ export async function runSearch(ctx) {
397
418
  ...(capNotes.length > 0 ? { capabilities: capNotes } : {}),
398
419
  ...(args.explain ? { explain: explainData(terms, matches, ir, nodeById) } : {}),
399
420
  ...(driftJson ? { drift: driftJson } : {}),
421
+ ...(joins ? { joins } : {}),
400
422
  }),
401
423
  };
402
424
  console.log(JSON.stringify(payload));
@@ -408,6 +430,9 @@ export async function runSearch(ctx) {
408
430
  }
409
431
  if (matches.length === 0) {
410
432
  console.log(countBy ? "(no matches) · 0 total" : "(no matches)");
433
+ // An index answer names the version it read, rows or not (#4525).
434
+ if (source.kind === "index")
435
+ provenance(matches, source, undefined, [], [], joins);
411
436
  availableAttrs(terms, ir);
412
437
  if (args.explain)
413
438
  explain(terms, matches, ir, nodeById, query);
@@ -421,7 +446,7 @@ export async function runSearch(ctx) {
421
446
  }
422
447
  else {
423
448
  for (const n of matches) {
424
- console.log(formatRow(n, show));
449
+ console.log(formatRow(n, show, joins?.[n.id]));
425
450
  }
426
451
  }
427
452
  const backed = source.kind === "declared" || matches.some((n) => n.physicalId);
@@ -430,7 +455,7 @@ export async function runSearch(ctx) {
430
455
  const recorded = source.kind === "live" && !matches.some((n) => n.physicalId) && args.env
431
456
  ? (await hasSnapshot(String(args.env))) ? "yes" : undefined
432
457
  : undefined;
433
- provenance(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)]);
458
+ provenance(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)], joins);
434
459
  for (const c of capabilityNotes(terms, ir, source)) {
435
460
  if (c.notEvaluated.length > 0)
436
461
  console.log(`— ${c.name} does not evaluate: ${c.notEvaluated.join("; ")}`);
@@ -531,6 +556,23 @@ export function checkSearchArgs(args, query, snapshot) {
531
556
  },
532
557
  };
533
558
  }
559
+ // An index version (#4525) is a third observation, so it excludes the other
560
+ // two, and a live read's own flags mean nothing against it.
561
+ if (args.index !== undefined) {
562
+ const other = args.live ? "--live" : snapshot.ref ? flag : args.ambient ? "--ambient" : undefined;
563
+ if (other) {
564
+ return {
565
+ error: {
566
+ code: "usage-invalid",
567
+ message: `chant search takes --index or ${other}, not both`,
568
+ hint: "--index answers from an index version in the store; --live reads the estate now; a snapshot replays a chant recording",
569
+ },
570
+ };
571
+ }
572
+ const ref = parseIndexRef(args.index);
573
+ if ("error" in ref)
574
+ return { error: { code: "usage-invalid", message: ref.error, hint: ref.hint } };
575
+ }
534
576
  if ((args.live || snapshot.ref) && !args.env) {
535
577
  const needs = snapshot.ref ? flag : "--live";
536
578
  return { error: { code: "usage-invalid", message: `chant search ${needs} needs an environment: ${needs} --env <name>` } };
@@ -554,6 +596,69 @@ const BUILD_ROOT_FAILED = {
554
596
  message: "chant search: a build root failed to render, so the graph it would answer over is incomplete",
555
597
  hint: "fix the error above; `chant graph . --format ir` reports the same one",
556
598
  };
599
+ /**
600
+ * Read the index version `--index` names from the project's store and build
601
+ * the graph the query runs over (#4525). With a project: the declared canvas
602
+ * `--live` would use (per stack when the config declares stacks, so ids
603
+ * match), every node joined to the index through its lexicon's index match.
604
+ * With no project (no lexicon in a config or in source): the index alone.
605
+ * No cloud is read either way.
606
+ */
607
+ async function indexAnswer(ctx, refText, projectPath, srcDir, config) {
608
+ const ref = parseIndexRef(refText);
609
+ if ("error" in ref)
610
+ return { error: { code: "usage-invalid", message: ref.error, hint: ref.hint } };
611
+ const { resolveSnapshotStore } = await import("../../lifecycle/snapshot-store.js");
612
+ const store = await resolveSnapshotStore({ cwd: projectPath, config: config });
613
+ await store.fetch();
614
+ const read = await readIndexRef(store, ref);
615
+ if ("error" in read)
616
+ return { error: { code: "index-unavailable", message: read.error, ...(read.hint ? { hint: read.hint } : {}) } };
617
+ const { doc } = read;
618
+ const { stamp } = doc;
619
+ const base = {
620
+ kind: "index",
621
+ index: formatIndexRef(stamp.scopeKey, read.version),
622
+ scopeKey: stamp.scopeKey,
623
+ version: read.version.replace(/\.json$/, ""),
624
+ observedAt: stamp.observedAt,
625
+ ...(stamp.completedAt ? { completedAt: stamp.completedAt } : {}),
626
+ digest: stamp.digest,
627
+ by: stamp.source.version ? `${stamp.source.name} ${stamp.source.version}` : stamp.source.name,
628
+ };
629
+ let lexicons;
630
+ try {
631
+ lexicons = await resolveProjectLexicons(projectPath);
632
+ }
633
+ catch (err) {
634
+ if (!isNoLexiconDetected(err))
635
+ throw err;
636
+ }
637
+ if (!lexicons) {
638
+ // No project: the index is the graph. Its nodes' lexicons, where they are
639
+ // installed, still map capability terms onto it.
640
+ const named = [...new Set(doc.graph.nodes.filter((n) => !n.unmappedKind).map((n) => n.lexicon))].sort();
641
+ let plugins = [];
642
+ try {
643
+ plugins = named.length > 0 ? await loadPlugins(named) : [];
644
+ }
645
+ catch {
646
+ plugins = [];
647
+ }
648
+ return { ir: indexOnlyGraph(doc), source: { ...base, project: false }, plugins };
649
+ }
650
+ const plugins = ctx.plugins.length > 0 ? ctx.plugins : await loadPlugins(lexicons);
651
+ const stacks = (config.stacks ?? []).map((s) => ({ name: s.name, region: s.region, src: s.src }));
652
+ const declared = stacks.length > 0
653
+ ? await buildDeclaredPerStack(stacks, projectPath, (g, entities) => withLexiconEdges(g, plugins, entities))
654
+ : await declaredGraph(ctx, projectPath, srcDir, plugins);
655
+ if (!declared)
656
+ return { error: BUILD_ROOT_FAILED };
657
+ const joined = joinDeclaredToIndex(declared, doc, plugins, {
658
+ regionOf: (id) => stacks.find((st) => id.startsWith(`${st.name}::`))?.region,
659
+ });
660
+ return { ir: joined.ir, source: { ...base, project: true }, joins: joined.joins };
661
+ }
557
662
  /**
558
663
  * The declared graph a search answers over (#4362, #4365, #4368): discovery,
559
664
  * plus the build-root entities (a terraform root's blocks, a rendered
@@ -594,7 +699,7 @@ export async function printCapabilities(args, query, lexicons) {
594
699
  const extra = [
595
700
  // `args.path` is "." when no query was given.
596
701
  ...(query && query !== "." ? [`the query "${query}"`] : []),
597
- ...["live", "env", "snapshot", "at", "countBy", "explain", "show"]
702
+ ...["live", "env", "snapshot", "at", "index", "countBy", "explain", "show"]
598
703
  .filter((k) => args[k] !== undefined && args[k] !== false)
599
704
  .map((k) => `--${k.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`),
600
705
  ];
@@ -690,8 +795,8 @@ export function usesCapability(t) {
690
795
  * the query names (#4375): an unknown name, a set used as an edge or the
691
796
  * wrong arguments is a refusal, never an empty answer.
692
797
  */
693
- async function bindCapabilities(ctx, projectPath, ir, terms) {
694
- let plugins = ctx.plugins;
798
+ async function bindCapabilities(ctx, projectPath, ir, terms, given) {
799
+ let plugins = given ?? ctx.plugins;
695
800
  if (plugins.length === 0) {
696
801
  try {
697
802
  plugins = await loadPlugins(await resolveProjectLexicons(projectPath));
@@ -877,7 +982,9 @@ function ambientHint(matches, ambientKinds, asked, replay) {
877
982
  * already done. That is a fact about the query, printed for every query, and it
878
983
  * encodes no expected answer.
879
984
  */
880
- function provenanceLine(matches, source, recorded, liveFailures = [], derived = []) {
985
+ function provenanceLine(matches, source, recorded, liveFailures = [], derived = [], joins) {
986
+ if (source.kind === "index")
987
+ return indexProvenance(matches, source, joins);
881
988
  const line = provenanceBase(matches, source, recorded, liveFailures, derived);
882
989
  // The plan read fell back (#4384): say to what, on whichever line this is.
883
990
  return source.kind === "live" ? line + fellBackText(source) : line;
@@ -890,6 +997,22 @@ function fellBackText(source) {
890
997
  const to = source.planFellBackTo === "live" ? "live-plan alone" : source.planFellBackTo;
891
998
  return ` · the plan read fell back to ${to}`;
892
999
  }
1000
+ /**
1001
+ * The provenance line of an `--index` answer (#4525): the version read and
1002
+ * when, then how the declared rows joined, every verdict counted, so a row
1003
+ * that did not bind is never read as one that did.
1004
+ */
1005
+ function indexProvenance(matches, source, joins) {
1006
+ const taken = `taken ${source.observedAt}`;
1007
+ if (!source.project) {
1008
+ return `— index only, no project · ${source.index} ${taken} by ${source.by} · ${matches.length} ${matches.length === 1 ? "row" : "rows"}`;
1009
+ }
1010
+ const counts = countJoins(joins ?? {}, matches.map((n) => n.id));
1011
+ const rest = ["absent", "not-observed", "no-binding", "ambiguous"]
1012
+ .filter((v) => counts[v] > 0)
1013
+ .map((v) => `${v === "not-observed" ? "not observed" : v} ${counts[v]}`);
1014
+ return `— observed from index ${source.index} ${taken} · bound ${counts.bound}/${matches.length}${rest.length > 0 ? ` · ${rest.join(" · ")}` : ""}`;
1015
+ }
893
1016
  function provenanceBase(matches, source, recorded, liveFailures = [], derived = []) {
894
1017
  if (source.kind === "declared") {
895
1018
  // A derived fact the query relied on (#4362) was folded from declared
@@ -897,6 +1020,8 @@ function provenanceBase(matches, source, recorded, liveFailures = [], derived =
897
1020
  const from = derived.length > 0 ? ` · ${derived.join(", ")} derived from declared references` : "";
898
1021
  return `— declared only · no observation · physical ids unavailable${from}`;
899
1022
  }
1023
+ if (source.kind === "index")
1024
+ return indexProvenance(matches, source);
900
1025
  const bound = matches.filter((n) => n.physicalId).length;
901
1026
  const what = source.kind === "live" ? "live read" : "snapshot";
902
1027
  if (liveFailures.length > 0) {
@@ -952,8 +1077,8 @@ function plannedCreateCount(matches) {
952
1077
  return all ? matches.length : 0;
953
1078
  }
954
1079
  /** Print {@link provenanceLine}: the text footer. */
955
- function provenance(matches, source, recorded, liveFailures = [], derived = []) {
956
- console.log(provenanceLine(matches, source, recorded, liveFailures, derived));
1080
+ function provenance(matches, source, recorded, liveFailures = [], derived = [], joins) {
1081
+ console.log(provenanceLine(matches, source, recorded, liveFailures, derived, joins));
957
1082
  }
958
1083
  /** Union `LiveObservation.resources` across lexicons into one name-keyed map. */
959
1084
  function mergeResources(observations) {
@@ -1218,7 +1343,7 @@ function leafText(x) {
1218
1343
  if (x.kind === "cap")
1219
1344
  return `cap:${x.a}`;
1220
1345
  return x.kind === "kind" ? `kind:${x.a}` : x.kind === "attr" ? `attr:${x.a}${x.b !== undefined ? "=" + x.b : ""}`
1221
- : x.kind === "tag" ? `tag:${x.a}${x.b !== undefined ? "=" + x.b : ""}` : `"${x.a}"`;
1346
+ : x.kind === "tag" ? `tag:${x.a}${x.b !== undefined ? "=" + x.b : ""}` : x.kind === "id" ? `id:${x.a}` : `"${x.a}"`;
1222
1347
  }
1223
1348
  function searchErrorJson(query, error) {
1224
1349
  return { ...searchHead(), query, error: { code: error.code, message: error.message, ...(error.hint ? { hint: error.hint } : {}) } };
@@ -1264,6 +1389,7 @@ function searchJson(query, source, matches, terms, ir, byId, liveFailures = [],
1264
1389
  hops: p.hops,
1265
1390
  ...(p.because ? { because: p.because } : {}),
1266
1391
  })),
1392
+ ...(extra.joins?.[n.id] ? { join: extra.joins[n.id] } : {}),
1267
1393
  };
1268
1394
  }),
1269
1395
  ...(extra.provenance !== undefined ? { provenance: extra.provenance } : {}),
@@ -1365,23 +1491,46 @@ function resolveTerraformTypes(term, present) {
1365
1491
  function displayKind(n) {
1366
1492
  return terraformType(n) ?? n.kind;
1367
1493
  }
1368
- function parseLeaf(tok) {
1369
- const cap = /^cap:(.*)$/i.exec(tok);
1370
- if (cap) {
1371
- if (!parseCapabilityCall(cap[1])) {
1372
- throw new QueryError(`"${tok}" is not a capability term`, "name a capability, with arguments in parentheses when it takes any: cap:internet-reachable, cap:open-ingress(22); chant search --capabilities lists them");
1373
- }
1374
- return { kind: "cap", a: cap[1] };
1375
- }
1376
- const m = /^(kind|tag|attr):(.*)$/i.exec(tok);
1377
- if (m) {
1378
- const key = m[1].toLowerCase();
1379
- const rest = m[2];
1494
+ /** `name` or `name=value` after a prefix. */
1495
+ function keyValueLeaf(kind) {
1496
+ return (rest) => {
1380
1497
  const eq = rest.indexOf("=");
1381
- if (eq >= 0)
1382
- return { kind: key, a: rest.slice(0, eq), b: rest.slice(eq + 1) };
1383
- return { kind: key, a: rest };
1384
- }
1498
+ return eq >= 0 ? { kind, a: rest.slice(0, eq), b: rest.slice(eq + 1) } : { kind, a: rest };
1499
+ };
1500
+ }
1501
+ const LEAF_PREFIXES = [
1502
+ { prefix: "kind", listed: true, parse: keyValueLeaf("kind") },
1503
+ { prefix: "attr", listed: true, parse: keyValueLeaf("attr") },
1504
+ { prefix: "tag", listed: true, parse: keyValueLeaf("tag") },
1505
+ {
1506
+ // `id:<cloud id>` (#4534, behold#906 Q3): the whole rest is the id, colons
1507
+ // and `=` included, since an ARN has both.
1508
+ prefix: "id",
1509
+ listed: true,
1510
+ parse: (rest, tok) => {
1511
+ if (rest === "") {
1512
+ throw new QueryError(`"${tok}" needs a cloud id`, "name the id exactly as the cloud prints it: id:i-0abc123, id:arn:aws:s3:::my-bucket");
1513
+ }
1514
+ return { kind: "id", a: rest };
1515
+ },
1516
+ },
1517
+ {
1518
+ prefix: "cap",
1519
+ listed: false,
1520
+ parse: (rest, tok) => {
1521
+ if (!parseCapabilityCall(rest)) {
1522
+ throw new QueryError(`"${tok}" is not a capability term`, "name a capability, with arguments in parentheses when it takes any: cap:internet-reachable, cap:open-ingress(22); chant search --capabilities lists them");
1523
+ }
1524
+ return { kind: "cap", a: rest };
1525
+ },
1526
+ },
1527
+ ];
1528
+ function parseLeaf(tok) {
1529
+ // A prefix is matched case-insensitively, as it always was.
1530
+ const prefixed = /^([A-Za-z][A-Za-z0-9_]*):(.*)$/.exec(tok);
1531
+ const known = prefixed ? LEAF_PREFIXES.find((p) => p.prefix === prefixed[1].toLowerCase()) : undefined;
1532
+ if (prefixed && known)
1533
+ return known.parse(prefixed[2], tok);
1385
1534
  // `name:value` with a prefix the grammar does not have. This parsed as a
1386
1535
  // free-text word and matched nothing, which is the worst available outcome:
1387
1536
  // an agent looking for SSH reachability wrote
@@ -1396,7 +1545,8 @@ function parseLeaf(tok) {
1396
1545
  if (bad) {
1397
1546
  const name = bad[1];
1398
1547
  const value = tok.slice(name.length + 1);
1399
- throw new QueryError(`"${tok}" is not a term — there is no "${name}:" prefix`, `for an attribute, say attr:${name}=${value || "<value>"}; the prefixes are kind:, attr:, tag:, and ->/<- for edges`);
1548
+ const prefixes = LEAF_PREFIXES.filter((p) => p.listed).map((p) => `${p.prefix}:`).join(", ");
1549
+ throw new QueryError(`"${tok}" is not a term — there is no "${name}:" prefix`, `for an attribute, say attr:${name}=${value || "<value>"}; the prefixes are ${prefixes}, and ->/<- for edges`);
1400
1550
  }
1401
1551
  return { kind: "word", a: tok };
1402
1552
  }
@@ -1575,10 +1725,14 @@ function matchTerm(n, t, ir, byId) {
1575
1725
  const val = attrString(attrs[t.a]);
1576
1726
  return t.b === undefined ? t.a in attrs : val.toLowerCase().includes(t.b.toLowerCase());
1577
1727
  }
1728
+ if (t.kind === "id")
1729
+ return hasCloudId(n, t.a);
1578
1730
  if (t.kind === "tag") {
1579
1731
  const tags = attrs["Tags"];
1580
- if (!Array.isArray(tags))
1581
- return false;
1732
+ if (!Array.isArray(tags)) {
1733
+ // An indexed node keeps its tags as a map (#4521), not a Tags list.
1734
+ return Object.entries(n.tags ?? {}).some(([key, val]) => key.toLowerCase() === t.a.toLowerCase() && (t.b === undefined || String(val).toLowerCase().includes(t.b.toLowerCase())));
1735
+ }
1582
1736
  return tags.some((tag) => {
1583
1737
  const key = attrString(tag?.Key);
1584
1738
  const val = attrString(tag?.Value);
@@ -1594,6 +1748,18 @@ function matchTerm(n, t, ir, byId) {
1594
1748
  const hay = [n.id, n.kind, ...values].join(" ").toLowerCase();
1595
1749
  return hay.includes(t.a.toLowerCase());
1596
1750
  }
1751
+ /**
1752
+ * Whether a node carries `id` as one of its cloud ids (#4534): its observed
1753
+ * `physicalId`, or any value in its engine facts' `cloudIds` (an ARN, an
1754
+ * import id, a self-link). The match is exact, case included: a cloud id is
1755
+ * an identifier, and a substring of one names another object. A bare word
1756
+ * never reads either field.
1757
+ */
1758
+ function hasCloudId(n, id) {
1759
+ if (n.physicalId === id)
1760
+ return true;
1761
+ return (n.facts?.cloudIds ?? []).some((c) => c.value === id);
1762
+ }
1597
1763
  const adjacency = new WeakMap();
1598
1764
  function edgeIndex(ir) {
1599
1765
  let idx = adjacency.get(ir);
@@ -1644,7 +1810,15 @@ function findPath(n, t, ir, byId) {
1644
1810
  });
1645
1811
  return found ? found.hops : null;
1646
1812
  }
1813
+ /**
1814
+ * A cloud-listed node's path-style id (behold#1025 Q2,
1815
+ * `<substrate>/<scopeId>/<location>/<listedType>/<nativeId>`), printed whole:
1816
+ * its listed type holds `::`, which is not a stack qualification.
1817
+ */
1818
+ const INDEX_NODE_ID = /^(aws|azure|gcp|kubernetes)\/[^/]+\/[^/]+\/[^/]+\/./;
1647
1819
  function bareId(id) {
1820
+ if (INDEX_NODE_ID.test(id))
1821
+ return id;
1648
1822
  return id.includes("::") ? id.slice(id.lastIndexOf("::") + 2) : id;
1649
1823
  }
1650
1824
  /**
@@ -1759,16 +1933,22 @@ function formatHops(hops, start) {
1759
1933
  })
1760
1934
  .join("; ");
1761
1935
  }
1762
- function formatRow(n, show) {
1936
+ function formatRow(n, show, join) {
1763
1937
  const attrs = (n.attrs ?? {});
1764
1938
  // Display the bare logical id, not the `${stack}::` qualification (#1162).
1765
- const displayId = n.id.includes("::") ? n.id.slice(n.id.lastIndexOf("::") + 2) : n.id;
1939
+ const displayId = bareId(n.id);
1766
1940
  // A terraform resource shows its type (#4366); its IR kind is `Terraform::Resource` for all of them.
1767
1941
  const parts = [displayId, displayKind(n) ?? ""];
1768
1942
  // Prefer the node-level live physicalId (set by the overlay), then attrs;
1769
1943
  // skip source-mode AttrRef placeholders (objects).
1770
1944
  const physical = n.physicalId ?? attrs["physicalId"] ?? attrs["InstanceId"] ?? attrs["Id"];
1771
- if (physical != null && typeof physical !== "object")
1945
+ // A row joined to an index (#4525) that did not bind says which verdict it
1946
+ // got where the physical id would go: a declared InstanceId is not one the
1947
+ // index confirmed.
1948
+ const cell = join ? joinCell(join) : undefined;
1949
+ if (cell)
1950
+ parts.push(cell);
1951
+ else if (physical != null && typeof physical !== "object")
1772
1952
  parts.push(String(physical));
1773
1953
  // A row nobody could read says so where its physical id would go (#1263). A
1774
1954
  // blank there reads as "declared, not provisioned", which the read never
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAKA,OAAO,EAAkB,KAAK,UAAU,EAAmB,MAAM,YAAY,CAAC;AAa9E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAgB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;AA88CzC;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBzE;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,UAAU,EAkOvC,CAAC"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAKA,OAAO,EAAkB,KAAK,UAAU,EAAmB,MAAM,YAAY,CAAC;AAa9E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAgB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;AA++CzC;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBzE;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,UAAU,EAwOvC,CAAC"}
package/dist/cli/main.js CHANGED
@@ -160,7 +160,9 @@ Commands:
160
160
  terms, ->* / ->{1,3} for depth, ->[via=attr] / [to=attr]
161
161
  by attribute; --live or --snapshot <ref> (also --at
162
162
  <ref>) with --env <name> reads the estate or a
163
- recorded snapshot; --show <attr>,
163
+ recorded snapshot; --index <scope key>[@<version>]
164
+ answers from an index version, joined to the
165
+ declared rows, or alone with no project; --show <attr>,
164
166
  --count-by kind|module|attr:<name>, --explain prints
165
167
  paths, --json, --check-live,
166
168
  --check-snapshot, --fail-on-drift; cap:<name> and
@@ -178,6 +180,16 @@ Commands:
178
180
  --where <field><op><value> (= != < <= > >= ~,
179
181
  repeatable), --since <time|7d>, --at <rev> of
180
182
  chant/lifecycle, --member <name>, --json
183
+ index <substrate> Read one aws account, azure subscription, gcp project
184
+ or kubernetes cluster through its inventory API, type
185
+ it, derive its edges and write one index version to
186
+ the index store. Read-only: refuses action flags.
187
+ --account|--subscription|--project|--cluster, --regions,
188
+ --types, --tag k=v, --endpoint, --store <spec>, --json
189
+ (chant index --help for the rest)
190
+ index diff <a> [<b>] What changed between two index versions of one scope:
191
+ <scopeKey>/<version>, or <scopeKey> for its last two.
192
+ --store <spec>, --json (chant index diff --help)
181
193
  generate Generate typed code from sources chant.config declares
182
194
  (k8s.crds, helm.charts) into src/generated/<lexicon>/
183
195
  (codegen.outDir); --check exits 1 when the committed
@@ -611,6 +623,12 @@ Workspace (level 1, #2524):
611
623
  choudoufu runs live-check and the adoption report;
612
624
  choudoufu or other to chant runs chant import), staged
613
625
  in a worktree and gated on the patch digest like upgrade
626
+ workspace promote --all [--state-dir <dir>] [--state <member>=<tfstate>]... [--canary <member>] [--wave-size <n>] [--dry-run] [--json]
627
+ Adopt every terraform member into choudoufu in waves:
628
+ the canary first (default the first member), then
629
+ --wave-size roots a wave (default 5), one gate per
630
+ root bound to its live-import report digest. A wave
631
+ that does not land stops the later ones (#4461)
614
632
  workspace ls [dir] List the declaration's members and example groups.
615
633
  A member that can't be read is listed with a reason
616
634
  code and still exits 0. --at <rev> reads a commit's
@@ -968,6 +986,15 @@ Workspace (level 1, #2524):
968
986
  --no-cache reads every member
969
987
  --capability-view: each member's chant adds its
970
988
  capability view, mapped by its own lexicons
989
+ workspace drift --member <name> [--read <state|plan|refresh|live-read|ownership>] [--resource <addr>] [--env <name>] [--stream] [-o <file>]
990
+ One member's drift, read by its own engine: a chant
991
+ member through lifecycle diff --live (needs --env), a
992
+ terraform member through its state or a plan, a
993
+ choudoufu member through live-plan (and a plan for
994
+ --read plan), one resource through choudoufu
995
+ live-plan -resource. One drift document, or with
996
+ --stream the NDJSON stream (drift-start, records,
997
+ drift-settle)
971
998
  workspace search "<query>" [--member <name>] [--env <name>] [--snapshot <ref> | --live] [--at <rev>] [--explain] [--count-by ...] [--json]
972
999
  chant search in every chant member, each under its own
973
1000
  chant, as one read-contract document: ids are
@@ -1025,6 +1052,8 @@ Lifecycle (alias: lc):
1025
1052
  (lexicons with a deep reader also report
1026
1053
  property-level drift; --update-baseline records
1027
1054
  what it reports as accepted so it stops alerting)
1055
+ --index <ref>: compare source with an index version
1056
+ in the store, no deploy and no cloud read (#4526)
1028
1057
  lifecycle plan <env> Typed change set (create/update/delete/adopt) vs live
1029
1058
  --deep: also report properties declared
1030
1059
  heldElsewhere(). Never changes what the plan
@@ -1037,6 +1066,9 @@ Lifecycle (alias: lc):
1037
1066
  drift: ECS running vs desired, Route 53 health
1038
1067
  checks, Container Apps revisions, Cloud Run Ready.
1039
1068
  A failed read is "not read", never unhealthy (--json)
1069
+ lifecycle drift Each lexicon's own drift read, as drift-record
1070
+ NDJSON (--member, --read, --resource); what
1071
+ workspace drift runs in a member's reader project
1040
1072
  lifecycle whoami <env> Who chant would act as in each configured lexicon,
1041
1073
  and what that principal is scoped to — read-only,
1042
1074
  before anything acts (--json, --strict)
@@ -1341,6 +1373,7 @@ Examples:
1341
1373
  chant import manifest.yaml --lexicon k8s --output ./infra/
1342
1374
  chant import dash.json --lexicon grafana --parser-option acceptLossyV1
1343
1375
  chant import --from prod --name my-bucket --output src/
1376
+ chant import --index index.json --type AWS::S3::Bucket --output src/imported/
1344
1377
  chant lint ./infra/
1345
1378
  chant lint ./infra/ --format sarif
1346
1379
  chant lint ./infra/ --watch
@@ -1547,6 +1580,10 @@ export const commandRegistry = [
1547
1580
  // #4297 — SQL over the snapshots, runs, gates, deploys and releases on chant/lifecycle. Imported on first use.
1548
1581
  { name: "query", runsNoConfig: true, handler: async (ctx) => (await import("./handlers/query.js")).runQueryCommand(ctx) },
1549
1582
  { name: "ledger", runsNoConfig: true, handler: async (ctx) => (await import("./handlers/ledger.js")).runLedgerCommand(ctx) },
1583
+ // chant#4532 — a read-only cloud index. main() hands `index`'s raw argv to
1584
+ // its own parser before parseArgs; this entry answers "is it a verb" and
1585
+ // runs the words a caller already parsed (substrate, --json, --help).
1586
+ { name: "index", runsNoConfig: true, handler: async (ctx) => (await import("./handlers/index-cloud.js")).runIndexCommand(ctx) },
1550
1587
  // chant#2591 — `import --agents` and `audit` read chant.config statically
1551
1588
  // and never evaluate it (chant#2589 for audit, which audits code it must not run).
1552
1589
  { name: "import", handler: runImport, runsNoConfig: (args) => args.agents === true },
@@ -1680,6 +1717,7 @@ export const commandRegistry = [
1680
1717
  { name: "workspace run", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/workspace-run.js")).runWorkspaceRun(ctx) },
1681
1718
  // #2554 — a release train: one release of every chant member, pinned in the workspace ledger.
1682
1719
  { name: "workspace train", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/release-train.js")).runWorkspaceTrain(ctx) },
1720
+ { name: "workspace drift", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/drift-cli.js")).runWorkspaceDrift(ctx) },
1683
1721
  { name: "workspace search", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/search-cli.js")).runWorkspaceSearch(ctx) },
1684
1722
  // Each unit decides for itself whether its config is loaded (runCommandInProcess).
1685
1723
  { name: "workspace member-run", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/member-run.js")).runWorkspaceMemberRun(ctx, runCommandInProcess) },
@@ -1707,6 +1745,7 @@ export const commandRegistry = [
1707
1745
  { name: "lifecycle rollback", handler: runLifecycleRollback },
1708
1746
  { name: "lifecycle plan", requiresPlugins: true, handler: runLifecyclePlan },
1709
1747
  { name: "lifecycle affected", requiresPlugins: true, handler: runLifecycleAffected },
1748
+ { name: "lifecycle drift", requiresPlugins: true, handler: async (ctx) => (await import("./handlers/lifecycle-drift.js")).runLifecycleDrift(ctx) },
1710
1749
  { name: "lifecycle whoami", requiresPlugins: true, handler: runLifecycleWhoami },
1711
1750
  // #4177 — runtime health, separate from drift. Imported on first use.
1712
1751
  { name: "lifecycle health", requiresPlugins: true, handler: async (ctx) => (await import("./handlers/lifecycle-health.js")).runLifecycleHealth(ctx) },
@@ -1760,6 +1799,21 @@ async function main() {
1760
1799
  // something imports it. A no-op from source.
1761
1800
  installCompiledCli();
1762
1801
  const rawArgv = process.argv.slice(2);
1802
+ // chant#4532 — `chant index <substrate>` takes its own flags (--account,
1803
+ // --regions, --endpoint, ...) that core's one flat parser does not know, and
1804
+ // must refuse an action flag (--apply, --yes, ...) that the parser would
1805
+ // accept. So its argv goes to its own parser, before parseArgs.
1806
+ if (rawArgv[0] === "index" && rawArgv[1] === "diff") {
1807
+ // #4533 — `chant index diff <a> [<b>]`: two stored versions of one scope.
1808
+ const { runIndexDiff } = await import("./handlers/index-diff.js");
1809
+ await flushAndExit(await runIndexDiff(rawArgv.slice(2)));
1810
+ return;
1811
+ }
1812
+ if (rawArgv[0] === "index") {
1813
+ const { runCloudIndex } = await import("../lifecycle/cloud-index.js");
1814
+ await flushAndExit(await runCloudIndex(rawArgv.slice(1)));
1815
+ return;
1816
+ }
1763
1817
  let args;
1764
1818
  try {
1765
1819
  args = parseArgs(rawArgv);
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-tools.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/lifecycle-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAM3D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,gBAAgB,CA6B7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,gBAAgB,CAmCzE"}
1
+ {"version":3,"file":"lifecycle-tools.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/lifecycle-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAM3D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,gBAAgB,CA6B7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,gBAAgB,CAoCzE"}
@@ -1,5 +1,5 @@
1
1
  import { resolve } from "node:path";
2
- import { readSnapshot } from "../../lifecycle/git.js";
2
+ import { resolveSnapshotStore } from "../../lifecycle/snapshot-store.js";
3
3
  import { build } from "../../build.js";
4
4
  import { computeBuildDigest, diffDigests } from "../../lifecycle/digest.js";
5
5
  import { takeSnapshot } from "../../lifecycle/snapshot.js";
@@ -65,8 +65,9 @@ export function createDiffTool(plugins) {
65
65
  const currentDigest = computeBuildDigest(buildResult);
66
66
  const lexicons = lexiconFilter ? [lexiconFilter] : buildResult.manifest.lexicons;
67
67
  const results = {};
68
+ const store = await resolveSnapshotStore();
68
69
  for (const lex of lexicons) {
69
- const content = await readSnapshot(env, lex);
70
+ const content = await store.readLatest(env, lex);
70
71
  let previousDigest = undefined;
71
72
  if (content) {
72
73
  const snapshot = JSON.parse(content);
@@ -1 +1 @@
1
- {"version":3,"file":"resource-handlers.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/resource-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AASnD,KAAK,mBAAmB,GAAG;IAAE,UAAU,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAE9F;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,EAuDvD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAChD;IAAE,SAAS,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAMrC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAChD,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAS9C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACjD,OAAO,GAAE,aAAa,EAAO,GAC5B,OAAO,CAAC,OAAO,CAAC,CA0KlB"}
1
+ {"version":3,"file":"resource-handlers.d.ts","sourceRoot":"","sources":["../../../src/cli/mcp/resource-handlers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AASnD,KAAK,mBAAmB,GAAG;IAAE,UAAU,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAE9F;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,kBAAkB,EAuDvD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAChD;IAAE,SAAS,EAAE,kBAAkB,EAAE,CAAA;CAAE,CAMrC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAChD,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAS9C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACjD,OAAO,GAAE,aAAa,EAAO,GAC5B,OAAO,CAAC,OAAO,CAAC,CA2KlB"}
@@ -2,7 +2,7 @@ import { resolve, join, dirname } from "node:path";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { collectComposites } from "./tools/composites.js";
4
4
  import { getContext } from "./resources/context.js";
5
- import { readSnapshot, readEnvironmentSnapshots } from "../../lifecycle/git.js";
5
+ import { readEnvironmentSnapshotsFrom, resolveSnapshotStore } from "../../lifecycle/snapshot-store.js";
6
6
  import { discoverOps } from "../../op/discover.js";
7
7
  import { createLocalOpRuntime } from "../../op/runtimes/local.js";
8
8
  import { loadOkfBundle } from "../../okf-read.js";
@@ -202,8 +202,9 @@ export async function handleResourcesRead(params, pluginResources, plugins = [])
202
202
  const parts = uri.replace("chant://state/", "").split("/");
203
203
  const environment = parts[0];
204
204
  const lexicon = parts[1];
205
+ const store = await resolveSnapshotStore();
205
206
  if (lexicon) {
206
- const content = await readSnapshot(environment, lexicon);
207
+ const content = await store.readLatest(environment, lexicon);
207
208
  if (!content)
208
209
  throw new Error(`No snapshot found for ${environment}/${lexicon}`);
209
210
  return {
@@ -211,7 +212,7 @@ export async function handleResourcesRead(params, pluginResources, plugins = [])
211
212
  };
212
213
  }
213
214
  else {
214
- const snapshots = await readEnvironmentSnapshots(environment);
215
+ const snapshots = await readEnvironmentSnapshotsFrom(store, environment);
215
216
  const result = {};
216
217
  for (const [lex, content] of snapshots) {
217
218
  result[lex] = JSON.parse(content);