@intentius/chant 0.124.51 → 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 (593) 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 +17 -3
  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 +224 -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/covered-round.d.ts +173 -0
  120. package/dist/components/covered-round.d.ts.map +1 -0
  121. package/dist/components/covered-round.js +200 -0
  122. package/dist/components/declared-reads.d.ts +38 -0
  123. package/dist/components/declared-reads.d.ts.map +1 -0
  124. package/dist/components/declared-reads.js +131 -0
  125. package/dist/components/deploy-units.d.ts.map +1 -1
  126. package/dist/components/deploy-units.js +4 -0
  127. package/dist/components/driver.d.ts +42 -1
  128. package/dist/components/driver.d.ts.map +1 -1
  129. package/dist/components/driver.js +74 -3
  130. package/dist/components/fan-out-run.d.ts +23 -1
  131. package/dist/components/fan-out-run.d.ts.map +1 -1
  132. package/dist/components/fan-out-run.js +82 -14
  133. package/dist/components/fan-out-support.d.ts +6 -0
  134. package/dist/components/fan-out-support.d.ts.map +1 -1
  135. package/dist/components/fan-out-support.js +4 -1
  136. package/dist/components/fan-out.d.ts +28 -0
  137. package/dist/components/fan-out.d.ts.map +1 -1
  138. package/dist/components/groups.d.ts +229 -0
  139. package/dist/components/groups.d.ts.map +1 -0
  140. package/dist/components/groups.js +760 -0
  141. package/dist/components/index.d.ts +7 -2
  142. package/dist/components/index.d.ts.map +1 -1
  143. package/dist/components/index.js +5 -0
  144. package/dist/components/plan-shape-conformance.d.ts +48 -0
  145. package/dist/components/plan-shape-conformance.d.ts.map +1 -0
  146. package/dist/components/plan-shape-conformance.js +122 -0
  147. package/dist/components/pr-run.d.ts +62 -7
  148. package/dist/components/pr-run.d.ts.map +1 -1
  149. package/dist/components/pr-run.js +354 -53
  150. package/dist/components/promote-rounds.d.ts +9 -0
  151. package/dist/components/promote-rounds.d.ts.map +1 -1
  152. package/dist/components/promote-rounds.js +23 -2
  153. package/dist/components/promote.d.ts +17 -0
  154. package/dist/components/promote.d.ts.map +1 -1
  155. package/dist/components/promote.js +36 -6
  156. package/dist/components/release-gate.d.ts +23 -1
  157. package/dist/components/release-gate.d.ts.map +1 -1
  158. package/dist/components/release-gate.js +97 -33
  159. package/dist/components/run-groups.d.ts +58 -0
  160. package/dist/components/run-groups.d.ts.map +1 -0
  161. package/dist/components/run-groups.js +78 -0
  162. package/dist/components/starter-plugin.d.ts +1 -0
  163. package/dist/components/starter-plugin.d.ts.map +1 -1
  164. package/dist/components/starter-plugin.js +6 -1
  165. package/dist/components/verbs/index.d.ts +1 -0
  166. package/dist/components/verbs/index.d.ts.map +1 -1
  167. package/dist/components/verbs/index.js +1 -0
  168. package/dist/components/verbs/member-outputs.d.ts +187 -0
  169. package/dist/components/verbs/member-outputs.d.ts.map +1 -0
  170. package/dist/components/verbs/member-outputs.js +218 -0
  171. package/dist/components/wave-plan.d.ts +2 -0
  172. package/dist/components/wave-plan.d.ts.map +1 -1
  173. package/dist/components/wave-plan.js +4 -1
  174. package/dist/config.d.ts +60 -0
  175. package/dist/config.d.ts.map +1 -1
  176. package/dist/config.js +27 -0
  177. package/dist/deep-observation.d.ts +1 -13
  178. package/dist/deep-observation.d.ts.map +1 -1
  179. package/dist/deep-observation.js +5 -22
  180. package/dist/drift-record.d.ts +542 -0
  181. package/dist/drift-record.d.ts.map +1 -0
  182. package/dist/drift-record.js +886 -0
  183. package/dist/engine-facts.d.ts +144 -0
  184. package/dist/engine-facts.d.ts.map +1 -0
  185. package/dist/engine-facts.js +14 -0
  186. package/dist/graph-ir.d.ts +153 -2
  187. package/dist/graph-ir.d.ts.map +1 -1
  188. package/dist/graph-ir.js +224 -6
  189. package/dist/graph-refs.d.ts +145 -0
  190. package/dist/graph-refs.d.ts.map +1 -1
  191. package/dist/graph-refs.js +305 -0
  192. package/dist/graph-schema/fixtures/adopt.json +15 -0
  193. package/dist/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  194. package/dist/graph-schema/fixtures/index.json +68 -0
  195. package/dist/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  196. package/dist/graph-schema/fixtures.d.ts +23 -0
  197. package/dist/graph-schema/fixtures.d.ts.map +1 -0
  198. package/dist/graph-schema/fixtures.js +246 -0
  199. package/dist/graph-schema/generate.d.ts +15 -0
  200. package/dist/graph-schema/generate.d.ts.map +1 -0
  201. package/dist/graph-schema/generate.js +267 -0
  202. package/dist/graph-schema/graph.schema.json +1387 -0
  203. package/dist/health.schema.json +2 -1
  204. package/dist/identity.d.ts.map +1 -1
  205. package/dist/identity.js +2 -0
  206. package/dist/index.d.ts +1 -0
  207. package/dist/index.d.ts.map +1 -1
  208. package/dist/index.js +2 -0
  209. package/dist/instance-nodes.d.ts +159 -0
  210. package/dist/instance-nodes.d.ts.map +1 -0
  211. package/dist/instance-nodes.js +231 -0
  212. package/dist/lexicon.d.ts +72 -0
  213. package/dist/lexicon.d.ts.map +1 -1
  214. package/dist/lifecycle/adoption-file.d.ts +56 -0
  215. package/dist/lifecycle/adoption-file.d.ts.map +1 -0
  216. package/dist/lifecycle/adoption-file.js +123 -0
  217. package/dist/lifecycle/cloud-index.d.ts +186 -0
  218. package/dist/lifecycle/cloud-index.d.ts.map +1 -0
  219. package/dist/lifecycle/cloud-index.js +618 -0
  220. package/dist/lifecycle/derive-edges.d.ts +59 -0
  221. package/dist/lifecycle/derive-edges.d.ts.map +1 -0
  222. package/dist/lifecycle/derive-edges.js +126 -0
  223. package/dist/lifecycle/git.d.ts +10 -9
  224. package/dist/lifecycle/git.d.ts.map +1 -1
  225. package/dist/lifecycle/git.js +7 -1
  226. package/dist/lifecycle/identity-match.d.ts +133 -0
  227. package/dist/lifecycle/identity-match.d.ts.map +1 -0
  228. package/dist/lifecycle/identity-match.js +147 -0
  229. package/dist/lifecycle/index-diff.d.ts +224 -0
  230. package/dist/lifecycle/index-diff.d.ts.map +1 -0
  231. package/dist/lifecycle/index-diff.js +327 -0
  232. package/dist/lifecycle/index-document.d.ts +130 -0
  233. package/dist/lifecycle/index-document.d.ts.map +1 -0
  234. package/dist/lifecycle/index-document.js +189 -0
  235. package/dist/lifecycle/index-drift.d.ts +121 -0
  236. package/dist/lifecycle/index-drift.d.ts.map +1 -0
  237. package/dist/lifecycle/index-drift.js +178 -0
  238. package/dist/lifecycle/index-import.d.ts +168 -0
  239. package/dist/lifecycle/index-import.d.ts.map +1 -0
  240. package/dist/lifecycle/index-import.js +515 -0
  241. package/dist/lifecycle/index-join.d.ts +129 -0
  242. package/dist/lifecycle/index-join.d.ts.map +1 -0
  243. package/dist/lifecycle/index-join.js +248 -0
  244. package/dist/lifecycle/index.d.ts +4 -0
  245. package/dist/lifecycle/index.d.ts.map +1 -1
  246. package/dist/lifecycle/index.js +4 -0
  247. package/dist/lifecycle/observation-baseline.d.ts +61 -21
  248. package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
  249. package/dist/lifecycle/observation-baseline.js +144 -19
  250. package/dist/lifecycle/observe.d.ts.map +1 -1
  251. package/dist/lifecycle/observe.js +6 -1
  252. package/dist/lifecycle/query.d.ts +45 -4
  253. package/dist/lifecycle/query.d.ts.map +1 -1
  254. package/dist/lifecycle/query.js +89 -7
  255. package/dist/lifecycle/replay.d.ts +10 -3
  256. package/dist/lifecycle/replay.d.ts.map +1 -1
  257. package/dist/lifecycle/replay.js +10 -6
  258. package/dist/lifecycle/scenario.d.ts +4 -3
  259. package/dist/lifecycle/scenario.d.ts.map +1 -1
  260. package/dist/lifecycle/snapshot-store-fake.d.ts +9 -0
  261. package/dist/lifecycle/snapshot-store-fake.d.ts.map +1 -0
  262. package/dist/lifecycle/snapshot-store-fake.js +21 -0
  263. package/dist/lifecycle/snapshot-store-s3.d.ts +102 -0
  264. package/dist/lifecycle/snapshot-store-s3.d.ts.map +1 -0
  265. package/dist/lifecycle/snapshot-store-s3.js +254 -0
  266. package/dist/lifecycle/snapshot-store.d.ts +170 -0
  267. package/dist/lifecycle/snapshot-store.d.ts.map +1 -0
  268. package/dist/lifecycle/snapshot-store.js +832 -0
  269. package/dist/lifecycle/snapshot.d.ts +11 -0
  270. package/dist/lifecycle/snapshot.d.ts.map +1 -1
  271. package/dist/lifecycle/snapshot.js +18 -5
  272. package/dist/lifecycle/type-listing.d.ts +148 -0
  273. package/dist/lifecycle/type-listing.d.ts.map +1 -0
  274. package/dist/lifecycle/type-listing.js +166 -0
  275. package/dist/lint/component-checks.d.ts +15 -1
  276. package/dist/lint/component-checks.d.ts.map +1 -1
  277. package/dist/lint/component-checks.js +1 -0
  278. package/dist/lint/presets/relaxed.json +2 -1
  279. package/dist/lint/presets/strict.json +2 -1
  280. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts +4 -0
  281. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts.map +1 -0
  282. package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.js +13 -0
  283. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts +4 -0
  284. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts.map +1 -0
  285. package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.js +8 -0
  286. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts +33 -0
  287. package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts.map +1 -0
  288. package/dist/lint/rules/comp/comp008-applies-signal-only-root.js +123 -0
  289. package/dist/lint/rules/comp/index.d.ts +2 -1
  290. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  291. package/dist/lint/rules/comp/index.js +4 -1
  292. package/dist/observation.d.ts +19 -2
  293. package/dist/observation.d.ts.map +1 -1
  294. package/dist/observation.js +18 -1
  295. package/dist/op/activities/activity-contracts.d.ts +1 -1
  296. package/dist/op/activities/activity-contracts.js +1 -1
  297. package/dist/op/activities/change-set.d.ts +6 -4
  298. package/dist/op/activities/change-set.d.ts.map +1 -1
  299. package/dist/op/activities/change-set.js +4 -2
  300. package/dist/op/activity-failure.d.ts +27 -0
  301. package/dist/op/activity-failure.d.ts.map +1 -1
  302. package/dist/op/activity-failure.js +31 -0
  303. package/dist/op/index.d.ts +2 -1
  304. package/dist/op/index.d.ts.map +1 -1
  305. package/dist/op/index.js +1 -1
  306. package/dist/op/local-executor.d.ts +5 -1
  307. package/dist/op/local-executor.d.ts.map +1 -1
  308. package/dist/op/local-executor.js +22 -8
  309. package/dist/pr-loop.d.ts +92 -3
  310. package/dist/pr-loop.d.ts.map +1 -1
  311. package/dist/pr-loop.js +62 -3
  312. package/dist/pulumi-urn.d.ts +101 -0
  313. package/dist/pulumi-urn.d.ts.map +1 -0
  314. package/dist/pulumi-urn.js +131 -0
  315. package/dist/release-floors.d.ts +23 -0
  316. package/dist/release-floors.d.ts.map +1 -0
  317. package/dist/release-floors.js +22 -0
  318. package/dist/sensitive-key.d.ts +23 -0
  319. package/dist/sensitive-key.d.ts.map +1 -0
  320. package/dist/sensitive-key.js +31 -0
  321. package/dist/wave-runtime.mjs +234 -234
  322. package/dist/workspace/adoption-report.d.ts +53 -0
  323. package/dist/workspace/adoption-report.d.ts.map +1 -0
  324. package/dist/workspace/adoption-report.js +76 -0
  325. package/dist/workspace/capabilities-contract.d.ts +7 -0
  326. package/dist/workspace/capabilities-contract.d.ts.map +1 -1
  327. package/dist/workspace/capabilities-contract.js +2 -1
  328. package/dist/workspace/capabilities.schema.json +98 -0
  329. package/dist/workspace/change-set.schema.json +42 -3
  330. package/dist/workspace/ci-cloud-identity.d.ts +13 -1
  331. package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
  332. package/dist/workspace/ci-cloud-identity.js +30 -1
  333. package/dist/workspace/compose-graph.d.ts +10 -1
  334. package/dist/workspace/compose-graph.d.ts.map +1 -1
  335. package/dist/workspace/compose-graph.js +6 -1
  336. package/dist/workspace/conformance/index.d.ts +1 -1
  337. package/dist/workspace/conformance/index.d.ts.map +1 -1
  338. package/dist/workspace/conformance/index.js +6 -1
  339. package/dist/workspace/drift-cli.d.ts +81 -0
  340. package/dist/workspace/drift-cli.d.ts.map +1 -0
  341. package/dist/workspace/drift-cli.js +317 -0
  342. package/dist/workspace/drift.schema.json +672 -0
  343. package/dist/workspace/graph-cli.d.ts +2 -0
  344. package/dist/workspace/graph-cli.d.ts.map +1 -1
  345. package/dist/workspace/graph-cli.js +3 -0
  346. package/dist/workspace/graph.schema.json +72 -0
  347. package/dist/workspace/init.d.ts +5 -1
  348. package/dist/workspace/init.d.ts.map +1 -1
  349. package/dist/workspace/init.js +55 -9
  350. package/dist/workspace/ledger.schema.json +1 -1
  351. package/dist/workspace/nested-graph.d.ts.map +1 -1
  352. package/dist/workspace/nested-graph.js +2 -0
  353. package/dist/workspace/pr-report.schema.json +76 -3
  354. package/dist/workspace/promote-waves.d.ts +112 -0
  355. package/dist/workspace/promote-waves.d.ts.map +1 -0
  356. package/dist/workspace/promote-waves.js +290 -0
  357. package/dist/workspace/promote.d.ts +84 -2
  358. package/dist/workspace/promote.d.ts.map +1 -1
  359. package/dist/workspace/promote.js +347 -61
  360. package/dist/workspace/reason-codes.d.ts +12 -0
  361. package/dist/workspace/reason-codes.d.ts.map +1 -1
  362. package/dist/workspace/reason-codes.js +14 -0
  363. package/dist/workspace/search-contract.d.ts +3 -3
  364. package/dist/workspace/search-contract.d.ts.map +1 -1
  365. package/dist/workspace/search-contract.js +2 -0
  366. package/dist/workspace/search.schema.json +103 -5
  367. package/package.json +14 -1
  368. package/src/__fixtures__/drift-record/README.md +58 -0
  369. package/src/__fixtures__/drift-record/choudoufu-cone.ndjson +4 -0
  370. package/src/__fixtures__/drift-record/choudoufu-resource.ndjson +3 -0
  371. package/src/__fixtures__/drift-record/component-status-ledger.json +65 -0
  372. package/src/__fixtures__/drift-record/component-status.json +91 -0
  373. package/src/__fixtures__/drift-record/deep-diff.json +259 -0
  374. package/src/__fixtures__/drift-record/lifecycle-diff-live.json +825 -0
  375. package/src/__fixtures__/drift-record/live-diff.json +125 -0
  376. package/src/audit/discover.e2e.test.ts +14 -0
  377. package/src/audit/discover.ts +3 -1
  378. package/src/behaviour.ts +1 -1
  379. package/src/capabilities/templates.json +145 -0
  380. package/src/capabilities/templates.test.ts +212 -0
  381. package/src/capabilities/templates.ts +204 -0
  382. package/src/change-set-bundle.test.ts +83 -0
  383. package/src/change-set-graph.ts +80 -9
  384. package/src/change-set.test.ts +24 -0
  385. package/src/change-set.ts +77 -14
  386. package/src/ci-identity-targets.test.ts +23 -0
  387. package/src/ci-identity.ts +10 -4
  388. package/src/cli/commands/import-index.test.ts +117 -0
  389. package/src/cli/commands/import-index.ts +265 -0
  390. package/src/cli/commands/lint.ts +4 -2
  391. package/src/cli/handlers/components.test.ts +9 -0
  392. package/src/cli/handlers/components.ts +12 -2
  393. package/src/cli/handlers/fan-out.ts +17 -3
  394. package/src/cli/handlers/graph.test.ts +42 -0
  395. package/src/cli/handlers/graph.ts +26 -4
  396. package/src/cli/handlers/index-cloud.ts +32 -0
  397. package/src/cli/handlers/index-diff.test.ts +68 -0
  398. package/src/cli/handlers/index-diff.ts +146 -0
  399. package/src/cli/handlers/ledger-root-member.test.ts +161 -0
  400. package/src/cli/handlers/lifecycle-drift.ts +68 -0
  401. package/src/cli/handlers/lifecycle.test.ts +33 -11
  402. package/src/cli/handlers/lifecycle.ts +205 -30
  403. package/src/cli/handlers/misc.ts +73 -0
  404. package/src/cli/handlers/pr-waves-blocked.test.ts +37 -2
  405. package/src/cli/handlers/pr.ts +16 -3
  406. package/src/cli/handlers/promote.test.ts +64 -0
  407. package/src/cli/handlers/promote.ts +81 -6
  408. package/src/cli/handlers/query.ts +27 -4
  409. package/src/cli/handlers/run-declared-reads-cli.test.ts +187 -0
  410. package/src/cli/handlers/run-groups-cli.test.ts +229 -0
  411. package/src/cli/handlers/scenario.test.ts +13 -0
  412. package/src/cli/handlers/scenario.ts +8 -7
  413. package/src/cli/handlers/search-index.test.ts +255 -0
  414. package/src/cli/handlers/search-json.test.ts +1 -1
  415. package/src/cli/handlers/search-ownership.test.ts +194 -0
  416. package/src/cli/handlers/search.ts +271 -38
  417. package/src/cli/main.test.ts +7 -0
  418. package/src/cli/main.ts +56 -1
  419. package/src/cli/mcp/lifecycle-tools.ts +3 -2
  420. package/src/cli/mcp/resource-handlers.ts +4 -3
  421. package/src/cli/mcp/workspace-tools.ts +1 -1
  422. package/src/cli/parse-args.ts +40 -2
  423. package/src/cli/registry.ts +19 -1
  424. package/src/cloud-lister/aws.test.ts +202 -0
  425. package/src/cloud-lister/aws.ts +226 -0
  426. package/src/cloud-lister/azure.test.ts +132 -0
  427. package/src/cloud-lister/azure.ts +142 -0
  428. package/src/cloud-lister/common.ts +115 -0
  429. package/src/cloud-lister/credentials.ts +110 -0
  430. package/src/cloud-lister/fakes.ts +66 -0
  431. package/src/cloud-lister/gcp.test.ts +121 -0
  432. package/src/cloud-lister/gcp.ts +159 -0
  433. package/src/cloud-lister/guard.test.ts +198 -0
  434. package/src/cloud-lister/guard.ts +111 -0
  435. package/src/cloud-lister/ids.ts +54 -0
  436. package/src/cloud-lister/index.ts +134 -0
  437. package/src/cloud-lister/kubernetes.test.ts +160 -0
  438. package/src/cloud-lister/kubernetes.ts +284 -0
  439. package/src/cloud-lister/markers.ts +74 -0
  440. package/src/cloud-lister/mask.ts +77 -0
  441. package/src/cloud-lister/shape.test.ts +81 -0
  442. package/src/cloud-lister/sigv4.ts +70 -0
  443. package/src/cloud-lister/transport.ts +118 -0
  444. package/src/cloud-lister/types.ts +135 -0
  445. package/src/components/capability-plugin-loader.ts +4 -0
  446. package/src/components/capability-plugin.ts +10 -0
  447. package/src/components/capability.ts +238 -0
  448. package/src/components/cli-support.ts +70 -14
  449. package/src/components/covered-round.test.ts +166 -0
  450. package/src/components/covered-round.ts +293 -0
  451. package/src/components/declared-reads.test.ts +103 -0
  452. package/src/components/declared-reads.ts +134 -0
  453. package/src/components/deploy-units.ts +4 -0
  454. package/src/components/driver.ts +101 -4
  455. package/src/components/fan-out-run.ts +95 -15
  456. package/src/components/fan-out-support.ts +10 -1
  457. package/src/components/fan-out.ts +30 -0
  458. package/src/components/groups.test.ts +320 -0
  459. package/src/components/groups.ts +880 -0
  460. package/src/components/index.ts +59 -0
  461. package/src/components/plan-shape-conformance.ts +130 -0
  462. package/src/components/pr-env-run-bundle.test.ts +2 -0
  463. package/src/components/pr-run.test.ts +728 -4
  464. package/src/components/pr-run.ts +395 -55
  465. package/src/components/promote-rounds.ts +25 -2
  466. package/src/components/promote.ts +55 -5
  467. package/src/components/registry.test.ts +1 -1
  468. package/src/components/release-gate.ts +115 -30
  469. package/src/components/release-groups.test.ts +362 -0
  470. package/src/components/run-groups.ts +113 -0
  471. package/src/components/starter-plugin.ts +6 -0
  472. package/src/components/verbs/index.ts +1 -0
  473. package/src/components/verbs/member-outputs.test.ts +205 -0
  474. package/src/components/verbs/member-outputs.ts +308 -0
  475. package/src/components/wave-plan.ts +5 -2
  476. package/src/config.ts +44 -0
  477. package/src/deep-observation.ts +5 -23
  478. package/src/drift-record.test.ts +596 -0
  479. package/src/drift-record.ts +1206 -0
  480. package/src/engine-facts.guard.test.ts +111 -0
  481. package/src/engine-facts.test.ts +178 -0
  482. package/src/engine-facts.ts +154 -0
  483. package/src/gated-waves-bundle.test.ts +2 -0
  484. package/src/graph-ir-live.test.ts +92 -0
  485. package/src/graph-ir.ts +317 -7
  486. package/src/graph-refs.ts +416 -0
  487. package/src/graph-schema/fixtures/adopt.json +15 -0
  488. package/src/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
  489. package/src/graph-schema/fixtures/index.json +68 -0
  490. package/src/graph-schema/fixtures/plunge.engine-graph.json +158 -0
  491. package/src/graph-schema/fixtures.ts +267 -0
  492. package/src/graph-schema/generate.ts +263 -0
  493. package/src/graph-schema/graph-schema.test.ts +153 -0
  494. package/src/graph-schema/graph.schema.json +1387 -0
  495. package/src/health.schema.json +2 -1
  496. package/src/identity.ts +2 -0
  497. package/src/index.ts +2 -0
  498. package/src/instance-nodes.ts +288 -0
  499. package/src/lexicon.ts +76 -0
  500. package/src/lifecycle/__fixtures__/index-diff/20261026T120000Z-aaaaaaaaaaaa.json +149 -0
  501. package/src/lifecycle/__fixtures__/index-diff/20261026T130000Z-bbbbbbbbbbbb.json +127 -0
  502. package/src/lifecycle/adoption-file.test.ts +100 -0
  503. package/src/lifecycle/adoption-file.ts +154 -0
  504. package/src/lifecycle/cloud-index.test.ts +517 -0
  505. package/src/lifecycle/cloud-index.ts +736 -0
  506. package/src/lifecycle/derive-edges.test.ts +193 -0
  507. package/src/lifecycle/derive-edges.ts +182 -0
  508. package/src/lifecycle/git.ts +10 -4
  509. package/src/lifecycle/identity-match.test.ts +308 -0
  510. package/src/lifecycle/identity-match.ts +257 -0
  511. package/src/lifecycle/index-diff.test.ts +198 -0
  512. package/src/lifecycle/index-diff.ts +476 -0
  513. package/src/lifecycle/index-document.test.ts +64 -0
  514. package/src/lifecycle/index-document.ts +299 -0
  515. package/src/lifecycle/index-drift.test.ts +191 -0
  516. package/src/lifecycle/index-drift.ts +304 -0
  517. package/src/lifecycle/index-import.test.ts +255 -0
  518. package/src/lifecycle/index-import.ts +634 -0
  519. package/src/lifecycle/index-join.test.ts +250 -0
  520. package/src/lifecycle/index-join.ts +304 -0
  521. package/src/lifecycle/index-store-load-bearing.test.ts +187 -0
  522. package/src/lifecycle/index.ts +4 -0
  523. package/src/lifecycle/member-ledger.test.ts +25 -7
  524. package/src/lifecycle/observation-baseline.test.ts +72 -1
  525. package/src/lifecycle/observation-baseline.ts +190 -27
  526. package/src/lifecycle/observe.ts +6 -1
  527. package/src/lifecycle/query.test.ts +69 -1
  528. package/src/lifecycle/query.ts +103 -10
  529. package/src/lifecycle/replay.test.ts +9 -5
  530. package/src/lifecycle/replay.ts +9 -5
  531. package/src/lifecycle/scenario.ts +4 -3
  532. package/src/lifecycle/snapshot-store-fake.ts +29 -0
  533. package/src/lifecycle/snapshot-store-s3.ts +316 -0
  534. package/src/lifecycle/snapshot-store.test.ts +385 -0
  535. package/src/lifecycle/snapshot-store.ts +981 -0
  536. package/src/lifecycle/snapshot.test.ts +13 -0
  537. package/src/lifecycle/snapshot.ts +23 -6
  538. package/src/lifecycle/type-listing.test.ts +166 -0
  539. package/src/lifecycle/type-listing.ts +309 -0
  540. package/src/lint/component-checks.ts +17 -1
  541. package/src/lint/config.test.ts +3 -0
  542. package/src/lint/presets/relaxed.json +2 -1
  543. package/src/lint/presets/strict.json +2 -1
  544. package/src/lint/rules/__fixtures__/comp/comp008/fail/dns.component.ts +15 -0
  545. package/src/lint/rules/__fixtures__/comp/comp008/pass/dns.component.ts +10 -0
  546. package/src/lint/rules/comp/comp.test.ts +2 -1
  547. package/src/lint/rules/comp/comp008-applies-signal-only-root.ts +121 -0
  548. package/src/lint/rules/comp/comp008.test.ts +77 -0
  549. package/src/lint/rules/comp/index.ts +4 -1
  550. package/src/observation-edges.test.ts +33 -0
  551. package/src/observation.ts +36 -1
  552. package/src/op/activities/activity-contracts.ts +1 -1
  553. package/src/op/activities/change-set.ts +8 -5
  554. package/src/op/activity-failure.ts +36 -0
  555. package/src/op/index.ts +2 -1
  556. package/src/op/local-executor.test.ts +80 -0
  557. package/src/op/local-executor.ts +27 -9
  558. package/src/pr-loop-bundle.test.ts +5 -2
  559. package/src/pr-loop.test.ts +57 -1
  560. package/src/pr-loop.ts +154 -6
  561. package/src/pulumi-urn.ts +151 -0
  562. package/src/release-floors.ts +22 -0
  563. package/src/sensitive-key.ts +34 -0
  564. package/src/workspace/adoption-report.test.ts +61 -0
  565. package/src/workspace/adoption-report.ts +103 -0
  566. package/src/workspace/capabilities-contract.test.ts +4 -0
  567. package/src/workspace/capabilities-contract.ts +9 -1
  568. package/src/workspace/capabilities.schema.json +98 -0
  569. package/src/workspace/change-set.schema.json +42 -3
  570. package/src/workspace/ci-cloud-identity.ts +31 -1
  571. package/src/workspace/compose-graph.test.ts +12 -0
  572. package/src/workspace/compose-graph.ts +12 -1
  573. package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
  574. package/src/workspace/conformance/index.ts +6 -1
  575. package/src/workspace/drift-cli.test.ts +65 -0
  576. package/src/workspace/drift-cli.ts +365 -0
  577. package/src/workspace/drift.schema.json +672 -0
  578. package/src/workspace/graph-cli.ts +5 -0
  579. package/src/workspace/graph.schema.json +72 -0
  580. package/src/workspace/init.test.ts +38 -1
  581. package/src/workspace/init.ts +50 -8
  582. package/src/workspace/intent-gaps.test.ts +18 -2
  583. package/src/workspace/ledger.schema.json +1 -1
  584. package/src/workspace/nested-graph.ts +1 -0
  585. package/src/workspace/pr-report.schema.json +76 -3
  586. package/src/workspace/promote-waves.test.ts +296 -0
  587. package/src/workspace/promote-waves.ts +340 -0
  588. package/src/workspace/promote.test.ts +158 -4
  589. package/src/workspace/promote.ts +398 -57
  590. package/src/workspace/reason-codes.test.ts +4 -1
  591. package/src/workspace/reason-codes.ts +14 -0
  592. package/src/workspace/search-contract.ts +2 -0
  593. package/src/workspace/search.schema.json +103 -5
@@ -25,6 +25,17 @@ import { formatError, formatWarning } from "../format";
25
25
  import { adjacencyOf, walkBreadthFirst } from "../../graph-walk";
26
26
  import type { CommandContext } from "../registry";
27
27
  import { SEARCH_CONTRACT_VERSION, SEARCH_OUTPUT_SCHEMA_ID, type SearchErrorCode, type SearchFailure, type SearchHead } from "../../workspace/search-contract";
28
+ import { isNoLexiconDetected } from "../../detectLexicon";
29
+ import {
30
+ countJoins,
31
+ formatIndexRef,
32
+ indexOnlyGraph,
33
+ joinCell,
34
+ joinDeclaredToIndex,
35
+ parseIndexRef,
36
+ readIndexRef,
37
+ type IndexJoin,
38
+ } from "../../lifecycle/index-join";
28
39
 
29
40
  /**
30
41
  * `chant search <query> [--live --env <name>]` — answer an estate question with
@@ -38,11 +49,17 @@ import { SEARCH_CONTRACT_VERSION, SEARCH_OUTPUT_SCHEMA_ID, type SearchErrorCode,
38
49
  * on a terraform resource, its type (kind:aws_instance, kind:aws_iam_)
39
50
  * tag:<key>=<val> a Tags entry with Key=key and Value containing val
40
51
  * attr:<name>=<val> attribute <name> equals/contains <val>
52
+ * id:<cloud id> physicalId or an engine cloudIds value is exactly <cloud id> (#4534)
41
53
  * ->kind:X / ->attr:.. this node has an edge TO a node matching the right side
42
54
  * <-kind:X / <-attr:.. this node has an edge FROM a node matching the right side
43
55
  * ->*X, ->{n}X, ->{m,n}X the far end is any depth / n / m..n hops away (#4359)
44
56
  * ->[via=a]X, ->[to=a]X only edges through consumer attr a / reading producer attr a
45
57
  *
58
+ * `--index <ref>` (#4525) answers from an index version in the store instead
59
+ * of a live read: the declared rows joined to it through each lexicon's index
60
+ * match, each row with its verdict, or, with no project, the index alone.
61
+ * See ../../lifecycle/index-join.ts.
62
+ *
46
63
  * The edge operators are the point of "edge-aware" search (#1139): a small
47
64
  * model shouldn't hand-join instance→subnet→public across many results — one
48
65
  * query does the traversal. `kind:Instance ->attr:MapPublicIpOnLaunch=true`
@@ -88,6 +105,10 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
88
105
 
89
106
  let ir: GraphIR;
90
107
  let source: AnswerSource = { kind: "declared" };
108
+ // Each declared row's join verdict against an index version (#4525).
109
+ let joins: Record<string, IndexJoin> | undefined;
110
+ // The lexicons a capability term reads an index-only graph through.
111
+ let indexPlugins: readonly LexiconPlugin[] | undefined;
91
112
  // Lexicons whose live read threw (#1263). "Nothing observed" and "could not
92
113
  // observe" are different claims; this is what carries the second one.
93
114
  const liveFailures: string[] = [];
@@ -113,7 +134,14 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
113
134
  let driftFailure = false;
114
135
  // Why --check-snapshot had nothing to check against, for --json (#4367).
115
136
  let driftUnavailable: string | undefined;
116
- if (args.live || snapshotRef) {
137
+ if (args.index !== undefined) {
138
+ const answered = await indexAnswer(ctx, String(args.index), projectPath, resolve(args.src ?? config.sourceDir ?? "."), config);
139
+ if ("error" in answered) return refuse(answered.error);
140
+ ir = answered.ir;
141
+ source = answered.source;
142
+ joins = answered.joins;
143
+ indexPlugins = answered.plugins;
144
+ } else if (args.live || snapshotRef) {
117
145
  // checkSearchArgs refused a live or snapshot read without one.
118
146
  const environment = String(args.env);
119
147
  // Membership via matchesDeclaredEnvironment (#1221): handles `{ name,
@@ -334,7 +362,7 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
334
362
  ir = enrichEffectiveTopology(ir);
335
363
  // Capability terms (#4375) read the graph through the lexicons' mappings.
336
364
  if (terms.some(usesCapability)) {
337
- const refused = await bindCapabilities(ctx, projectPath, ir, terms);
365
+ const refused = await bindCapabilities(ctx, projectPath, ir, terms, indexPlugins);
338
366
  if (refused) return refuse({ code: "query-invalid", ...refused });
339
367
  }
340
368
  // Resolve `kind:` terms against what is actually in this graph, before any
@@ -371,10 +399,10 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
371
399
  source.kind === "live" && !matches.some((n) => n.physicalId) && args.env
372
400
  ? (await hasSnapshot(String(args.env))) ? "yes" : undefined
373
401
  : undefined;
374
- const env = args.env && source.kind !== "declared" ? String(args.env) : undefined;
375
- const provenanceText = provenanceLine(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)]).replace(/^— /, "");
402
+ const env = args.env && (source.kind === "live" || source.kind === "snapshot") ? String(args.env) : undefined;
403
+ const provenanceText = provenanceLine(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)], joins).replace(/^— /, "");
376
404
  const capNotes = capabilityNotes(terms, ir, source);
377
- const plannedCreates = source.kind !== "declared" && liveFailures.length === 0 ? plannedCreateCount(matches) : 0;
405
+ const plannedCreates = (source.kind === "live" || source.kind === "snapshot") && liveFailures.length === 0 ? plannedCreateCount(matches) : 0;
378
406
  const driftJson = drift
379
407
  ? searchDriftJson(drift, matches.length, driftAgainst, snapshotDepth)
380
408
  : driftUnavailable !== undefined
@@ -402,6 +430,7 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
402
430
  ...(capNotes.length > 0 ? { capabilities: capNotes } : {}),
403
431
  ...(args.explain ? { explain: explainData(terms, matches, ir, nodeById) } : {}),
404
432
  ...(driftJson ? { drift: driftJson } : {}),
433
+ ...(joins ? { joins } : {}),
405
434
  }),
406
435
  };
407
436
  console.log(JSON.stringify(payload));
@@ -411,6 +440,8 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
411
440
  }
412
441
  if (matches.length === 0) {
413
442
  console.log(countBy ? "(no matches) · 0 total" : "(no matches)");
443
+ // An index answer names the version it read, rows or not (#4525).
444
+ if (source.kind === "index") provenance(matches, source, undefined, [], [], joins);
414
445
  availableAttrs(terms, ir);
415
446
  if (args.explain) explain(terms, matches, ir, nodeById, query);
416
447
  for (const n of liveNotes) console.error(formatWarning({ message: n }));
@@ -420,7 +451,7 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
420
451
  for (const line of formatCounts(countGroups(matches, countBy, hasManyTerraformRoots(ir)), countBy)) console.log(line);
421
452
  } else {
422
453
  for (const n of matches) {
423
- console.log(formatRow(n, show));
454
+ console.log(formatRow(n, show, joins?.[n.id]));
424
455
  }
425
456
  }
426
457
  const backed = source.kind === "declared" || matches.some((n) => n.physicalId);
@@ -430,7 +461,7 @@ export async function runSearch(ctx: CommandContext): Promise<number> {
430
461
  source.kind === "live" && !matches.some((n) => n.physicalId) && args.env
431
462
  ? (await hasSnapshot(String(args.env))) ? "yes" : undefined
432
463
  : undefined;
433
- provenance(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)]);
464
+ provenance(matches, source, recorded, liveFailures, [...derivedUsed(terms, matches, ir), ...capabilitiesUsed(terms)], joins);
434
465
  for (const c of capabilityNotes(terms, ir, source)) {
435
466
  if (c.notEvaluated.length > 0) console.log(`— ${c.name} does not evaluate: ${c.notEvaluated.join("; ")}`);
436
467
  }
@@ -481,7 +512,7 @@ export type SearchArgsCheck =
481
512
  * `--snapshot`, or plain search's `--at`.
482
513
  */
483
514
  export function checkSearchArgs(
484
- args: { countBy?: string; checkLive?: boolean; checkSnapshot?: boolean; failOnDrift?: boolean; live?: boolean; env?: string },
515
+ args: { countBy?: string; checkLive?: boolean; checkSnapshot?: boolean; failOnDrift?: boolean; live?: boolean; env?: string; index?: string; ambient?: boolean },
485
516
  query: string,
486
517
  snapshot: { ref?: string; flag: string },
487
518
  ): SearchArgsCheck {
@@ -534,6 +565,22 @@ export function checkSearchArgs(
534
565
  },
535
566
  };
536
567
  }
568
+ // An index version (#4525) is a third observation, so it excludes the other
569
+ // two, and a live read's own flags mean nothing against it.
570
+ if (args.index !== undefined) {
571
+ const other = args.live ? "--live" : snapshot.ref ? flag : args.ambient ? "--ambient" : undefined;
572
+ if (other) {
573
+ return {
574
+ error: {
575
+ code: "usage-invalid",
576
+ message: `chant search takes --index or ${other}, not both`,
577
+ hint: "--index answers from an index version in the store; --live reads the estate now; a snapshot replays a chant recording",
578
+ },
579
+ };
580
+ }
581
+ const ref = parseIndexRef(args.index);
582
+ if ("error" in ref) return { error: { code: "usage-invalid", message: ref.error, hint: ref.hint } };
583
+ }
537
584
  if ((args.live || snapshot.ref) && !args.env) {
538
585
  const needs = snapshot.ref ? flag : "--live";
539
586
  return { error: { code: "usage-invalid", message: `chant search ${needs} needs an environment: ${needs} --env <name>` } };
@@ -559,6 +606,78 @@ const BUILD_ROOT_FAILED = {
559
606
  hint: "fix the error above; `chant graph . --format ir` reports the same one",
560
607
  } as const;
561
608
 
609
+ /** What `--index` answers over (#4525), or why it can't. */
610
+ type IndexAnswer =
611
+ | { ir: GraphIR; source: AnswerSource & { kind: "index" }; joins?: Record<string, IndexJoin>; plugins?: readonly LexiconPlugin[] }
612
+ | { error: { code: SearchErrorCode; message: string; hint?: string } };
613
+
614
+ /**
615
+ * Read the index version `--index` names from the project's store and build
616
+ * the graph the query runs over (#4525). With a project: the declared canvas
617
+ * `--live` would use (per stack when the config declares stacks, so ids
618
+ * match), every node joined to the index through its lexicon's index match.
619
+ * With no project (no lexicon in a config or in source): the index alone.
620
+ * No cloud is read either way.
621
+ */
622
+ async function indexAnswer(
623
+ ctx: CommandContext,
624
+ refText: string,
625
+ projectPath: string,
626
+ srcDir: string,
627
+ config: Awaited<ReturnType<typeof loadChantConfig>>["config"],
628
+ ): Promise<IndexAnswer> {
629
+ const ref = parseIndexRef(refText);
630
+ if ("error" in ref) return { error: { code: "usage-invalid", message: ref.error, hint: ref.hint } };
631
+ const { resolveSnapshotStore } = await import("../../lifecycle/snapshot-store");
632
+ const store = await resolveSnapshotStore({ cwd: projectPath, config: config as unknown as { snapshots?: unknown } });
633
+ await store.fetch();
634
+ const read = await readIndexRef(store, ref);
635
+ if ("error" in read) return { error: { code: "index-unavailable", message: read.error, ...(read.hint ? { hint: read.hint } : {}) } };
636
+ const { doc } = read;
637
+ const { stamp } = doc;
638
+ const base = {
639
+ kind: "index" as const,
640
+ index: formatIndexRef(stamp.scopeKey, read.version),
641
+ scopeKey: stamp.scopeKey,
642
+ version: read.version.replace(/\.json$/, ""),
643
+ observedAt: stamp.observedAt,
644
+ ...(stamp.completedAt ? { completedAt: stamp.completedAt } : {}),
645
+ digest: stamp.digest,
646
+ by: stamp.source.version ? `${stamp.source.name} ${stamp.source.version}` : stamp.source.name,
647
+ };
648
+
649
+ let lexicons: string[] | undefined;
650
+ try {
651
+ lexicons = await resolveProjectLexicons(projectPath);
652
+ } catch (err) {
653
+ if (!isNoLexiconDetected(err)) throw err;
654
+ }
655
+ if (!lexicons) {
656
+ // No project: the index is the graph. Its nodes' lexicons, where they are
657
+ // installed, still map capability terms onto it.
658
+ const named = [...new Set(doc.graph.nodes.filter((n) => !n.unmappedKind).map((n) => n.lexicon))].sort();
659
+ let plugins: LexiconPlugin[] = [];
660
+ try {
661
+ plugins = named.length > 0 ? await loadPlugins(named) : [];
662
+ } catch {
663
+ plugins = [];
664
+ }
665
+ return { ir: indexOnlyGraph(doc), source: { ...base, project: false }, plugins };
666
+ }
667
+
668
+ const plugins = ctx.plugins.length > 0 ? ctx.plugins : await loadPlugins(lexicons);
669
+ const stacks = (config.stacks ?? []).map((s) => ({ name: s.name, region: s.region, src: s.src }));
670
+ const declared =
671
+ stacks.length > 0
672
+ ? await buildDeclaredPerStack(stacks, projectPath, (g, entities) => withLexiconEdges(g, plugins, entities))
673
+ : await declaredGraph(ctx, projectPath, srcDir, plugins);
674
+ if (!declared) return { error: BUILD_ROOT_FAILED };
675
+ const joined = joinDeclaredToIndex(declared, doc, plugins, {
676
+ regionOf: (id) => stacks.find((st) => id.startsWith(`${st.name}::`))?.region,
677
+ });
678
+ return { ir: joined.ir, source: { ...base, project: true }, joins: joined.joins };
679
+ }
680
+
562
681
  /**
563
682
  * The declared graph a search answers over (#4362, #4365, #4368): discovery,
564
683
  * plus the build-root entities (a terraform root's blocks, a rendered
@@ -599,7 +718,7 @@ async function declaredGraph(
599
718
  * they report on.
600
719
  */
601
720
  export async function printCapabilities(
602
- args: { json?: boolean; live?: boolean; env?: string; snapshot?: string; at?: string; countBy?: string; explain?: boolean; show?: string },
721
+ args: { json?: boolean; live?: boolean; env?: string; snapshot?: string; at?: string; index?: string; countBy?: string; explain?: boolean; show?: string },
603
722
  query: string,
604
723
  lexicons: string[],
605
724
  ): Promise<number> {
@@ -607,7 +726,7 @@ export async function printCapabilities(
607
726
  const extra = [
608
727
  // `args.path` is "." when no query was given.
609
728
  ...(query && query !== "." ? [`the query "${query}"`] : []),
610
- ...(["live", "env", "snapshot", "at", "countBy", "explain", "show"] as const)
729
+ ...(["live", "env", "snapshot", "at", "index", "countBy", "explain", "show"] as const)
611
730
  .filter((k) => args[k] !== undefined && args[k] !== false)
612
731
  .map((k) => `--${k.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`),
613
732
  ];
@@ -709,8 +828,9 @@ async function bindCapabilities(
709
828
  projectPath: string,
710
829
  ir: GraphIR,
711
830
  terms: Term[],
831
+ given?: readonly LexiconPlugin[],
712
832
  ): Promise<{ message: string; hint?: string } | undefined> {
713
- let plugins: readonly LexiconPlugin[] = ctx.plugins;
833
+ let plugins: readonly LexiconPlugin[] = given ?? ctx.plugins;
714
834
  if (plugins.length === 0) {
715
835
  try {
716
836
  plugins = await loadPlugins(await resolveProjectLexicons(projectPath));
@@ -819,7 +939,24 @@ export type AnswerSource =
819
939
  | { kind: "declared" }
820
940
  | ({ kind: "live" } & ReadDepth)
821
941
  /** `snapshot` is the ref asked for (`latest`), `commit` the snapshot commit it named (#4374). */
822
- | { kind: "snapshot"; snapshot?: string; commit: string; timestamp: string };
942
+ | { kind: "snapshot"; snapshot?: string; commit: string; timestamp: string }
943
+ /**
944
+ * `--index <ref>` (#4525): the index version answered from and its stamp.
945
+ * `index` is the ref resolved (`<scope key>@<version>`); `by` the source
946
+ * that wrote it; `project` false when there was no project, so every row
947
+ * is an indexed node.
948
+ */
949
+ | {
950
+ kind: "index";
951
+ index: string;
952
+ scopeKey: string;
953
+ version: string;
954
+ observedAt: string;
955
+ completedAt?: string;
956
+ digest: string;
957
+ by: string;
958
+ project: boolean;
959
+ };
823
960
 
824
961
 
825
962
 
@@ -936,7 +1073,9 @@ function provenanceLine(
936
1073
  recorded?: string,
937
1074
  liveFailures: string[] = [],
938
1075
  derived: string[] = [],
1076
+ joins?: Record<string, IndexJoin>,
939
1077
  ): string {
1078
+ if (source.kind === "index") return indexProvenance(matches, source, joins);
940
1079
  const line = provenanceBase(matches, source, recorded, liveFailures, derived);
941
1080
  // The plan read fell back (#4384): say to what, on whichever line this is.
942
1081
  return source.kind === "live" ? line + fellBackText(source) : line;
@@ -950,6 +1089,23 @@ function fellBackText(source: ReadDepth): string {
950
1089
  return ` · the plan read fell back to ${to}`;
951
1090
  }
952
1091
 
1092
+ /**
1093
+ * The provenance line of an `--index` answer (#4525): the version read and
1094
+ * when, then how the declared rows joined, every verdict counted, so a row
1095
+ * that did not bind is never read as one that did.
1096
+ */
1097
+ function indexProvenance(matches: IRNode[], source: AnswerSource & { kind: "index" }, joins?: Record<string, IndexJoin>): string {
1098
+ const taken = `taken ${source.observedAt}`;
1099
+ if (!source.project) {
1100
+ return `— index only, no project · ${source.index} ${taken} by ${source.by} · ${matches.length} ${matches.length === 1 ? "row" : "rows"}`;
1101
+ }
1102
+ const counts = countJoins(joins ?? {}, matches.map((n) => n.id));
1103
+ const rest = (["absent", "not-observed", "no-binding", "ambiguous"] as const)
1104
+ .filter((v) => counts[v] > 0)
1105
+ .map((v) => `${v === "not-observed" ? "not observed" : v} ${counts[v]}`);
1106
+ return `— observed from index ${source.index} ${taken} · bound ${counts.bound}/${matches.length}${rest.length > 0 ? ` · ${rest.join(" · ")}` : ""}`;
1107
+ }
1108
+
953
1109
  function provenanceBase(
954
1110
  matches: IRNode[],
955
1111
  source: AnswerSource,
@@ -963,6 +1119,7 @@ function provenanceBase(
963
1119
  const from = derived.length > 0 ? ` · ${derived.join(", ")} derived from declared references` : "";
964
1120
  return `— declared only · no observation · physical ids unavailable${from}`;
965
1121
  }
1122
+ if (source.kind === "index") return indexProvenance(matches, source);
966
1123
  const bound = matches.filter((n) => n.physicalId).length;
967
1124
  const what = source.kind === "live" ? "live read" : "snapshot";
968
1125
  if (liveFailures.length > 0) {
@@ -1031,8 +1188,9 @@ function provenance(
1031
1188
  recorded?: string,
1032
1189
  liveFailures: string[] = [],
1033
1190
  derived: string[] = [],
1191
+ joins?: Record<string, IndexJoin>,
1034
1192
  ): void {
1035
- console.log(provenanceLine(matches, source, recorded, liveFailures, derived));
1193
+ console.log(provenanceLine(matches, source, recorded, liveFailures, derived, joins));
1036
1194
  }
1037
1195
 
1038
1196
  /** Union `LiveObservation.resources` across lexicons into one name-keyed map. */
@@ -1321,7 +1479,7 @@ function describeTerm(t: Term): string {
1321
1479
  function leafText(x: Term): string {
1322
1480
  if (x.kind === "cap") return `cap:${x.a}`;
1323
1481
  return x.kind === "kind" ? `kind:${x.a}` : x.kind === "attr" ? `attr:${x.a}${x.b !== undefined ? "=" + x.b : ""}`
1324
- : x.kind === "tag" ? `tag:${x.a}${x.b !== undefined ? "=" + x.b : ""}` : `"${x.a}"`;
1482
+ : x.kind === "tag" ? `tag:${x.a}${x.b !== undefined ? "=" + x.b : ""}` : x.kind === "id" ? `id:${x.a}` : `"${x.a}"`;
1325
1483
  }
1326
1484
 
1327
1485
  /**
@@ -1380,6 +1538,8 @@ export interface SearchJson {
1380
1538
  unobserved?: string;
1381
1539
  show?: Record<string, unknown>;
1382
1540
  paths: { term: string; dir: "out" | "in"; hops: PathHop[]; because?: { capability: string; id: string; hops: PathHop[] }[] }[];
1541
+ /** `--index` with a project (#4525): how the declared row joined to the index version. */
1542
+ join?: IndexJoin;
1383
1543
  }[];
1384
1544
  provenance?: string;
1385
1545
  /** Present when every match is a planned create (#4372): how many. See the schema. */
@@ -1446,6 +1606,7 @@ function searchJson(
1446
1606
  capabilities?: SearchJson["capabilities"];
1447
1607
  explain?: ReturnType<typeof explainData>;
1448
1608
  drift?: SearchDriftJson;
1609
+ joins?: Record<string, IndexJoin>;
1449
1610
  } = {},
1450
1611
  ): SearchJson {
1451
1612
  const show = extra.show ?? [];
@@ -1468,6 +1629,7 @@ function searchJson(
1468
1629
  hops: p.hops,
1469
1630
  ...(p.because ? { because: p.because } : {}),
1470
1631
  })),
1632
+ ...(extra.joins?.[n.id] ? { join: extra.joins[n.id] } : {}),
1471
1633
  };
1472
1634
  }),
1473
1635
  ...(extra.provenance !== undefined ? { provenance: extra.provenance } : {}),
@@ -1496,7 +1658,7 @@ function termText(t: Term): string {
1496
1658
  }
1497
1659
 
1498
1660
  export interface Term {
1499
- kind: "word" | "kind" | "tag" | "attr" | "edge" | "cap";
1661
+ kind: "word" | "kind" | "tag" | "attr" | "edge" | "cap" | "id";
1500
1662
  /** `!term` — the node must NOT satisfy this (#1280). */
1501
1663
  negated?: boolean;
1502
1664
  a: string;
@@ -1602,25 +1764,64 @@ function displayKind(n: IRNode): string | undefined {
1602
1764
  return terraformType(n) ?? n.kind;
1603
1765
  }
1604
1766
 
1605
- function parseLeaf(tok: string): Term {
1606
- const cap = /^cap:(.*)$/i.exec(tok);
1607
- if (cap) {
1608
- if (!parseCapabilityCall(cap[1])) {
1609
- throw new QueryError(
1610
- `"${tok}" is not a capability term`,
1611
- "name a capability, with arguments in parentheses when it takes any: cap:internet-reachable, cap:open-ingress(22); chant search --capabilities lists them",
1612
- );
1613
- }
1614
- return { kind: "cap", a: cap[1] };
1615
- }
1616
- const m = /^(kind|tag|attr):(.*)$/i.exec(tok);
1617
- if (m) {
1618
- const key = m[1].toLowerCase() as Term["kind"];
1619
- const rest = m[2];
1767
+ /**
1768
+ * The leaf prefixes the grammar reads (`kind:`, `attr:`, `tag:`, `id:`, `cap:`),
1769
+ * each with its parser. A new prefix is one entry here, one `Term` kind, and
1770
+ * its case in {@link matchTerm}; the unknown-prefix refusal lists the
1771
+ * entries marked `listed`, in this order.
1772
+ */
1773
+ interface LeafPrefix {
1774
+ prefix: string;
1775
+ /** Named in the unknown-prefix hint. */
1776
+ listed: boolean;
1777
+ /** `rest` is what follows the colon; `tok` the whole token, for messages. */
1778
+ parse(rest: string, tok: string): Term;
1779
+ }
1780
+
1781
+ /** `name` or `name=value` after a prefix. */
1782
+ function keyValueLeaf(kind: "kind" | "tag" | "attr"): LeafPrefix["parse"] {
1783
+ return (rest) => {
1620
1784
  const eq = rest.indexOf("=");
1621
- if (eq >= 0) return { kind: key, a: rest.slice(0, eq), b: rest.slice(eq + 1) };
1622
- return { kind: key, a: rest };
1623
- }
1785
+ return eq >= 0 ? { kind, a: rest.slice(0, eq), b: rest.slice(eq + 1) } : { kind, a: rest };
1786
+ };
1787
+ }
1788
+
1789
+ const LEAF_PREFIXES: readonly LeafPrefix[] = [
1790
+ { prefix: "kind", listed: true, parse: keyValueLeaf("kind") },
1791
+ { prefix: "attr", listed: true, parse: keyValueLeaf("attr") },
1792
+ { prefix: "tag", listed: true, parse: keyValueLeaf("tag") },
1793
+ {
1794
+ // `id:<cloud id>` (#4534, behold#906 Q3): the whole rest is the id, colons
1795
+ // and `=` included, since an ARN has both.
1796
+ prefix: "id",
1797
+ listed: true,
1798
+ parse: (rest, tok) => {
1799
+ if (rest === "") {
1800
+ 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");
1801
+ }
1802
+ return { kind: "id", a: rest };
1803
+ },
1804
+ },
1805
+ {
1806
+ prefix: "cap",
1807
+ listed: false,
1808
+ parse: (rest, tok) => {
1809
+ if (!parseCapabilityCall(rest)) {
1810
+ throw new QueryError(
1811
+ `"${tok}" is not a capability term`,
1812
+ "name a capability, with arguments in parentheses when it takes any: cap:internet-reachable, cap:open-ingress(22); chant search --capabilities lists them",
1813
+ );
1814
+ }
1815
+ return { kind: "cap", a: rest };
1816
+ },
1817
+ },
1818
+ ];
1819
+
1820
+ function parseLeaf(tok: string): Term {
1821
+ // A prefix is matched case-insensitively, as it always was.
1822
+ const prefixed = /^([A-Za-z][A-Za-z0-9_]*):(.*)$/.exec(tok);
1823
+ const known = prefixed ? LEAF_PREFIXES.find((p) => p.prefix === prefixed[1].toLowerCase()) : undefined;
1824
+ if (prefixed && known) return known.parse(prefixed[2], tok);
1624
1825
  // `name:value` with a prefix the grammar does not have. This parsed as a
1625
1826
  // free-text word and matched nothing, which is the worst available outcome:
1626
1827
  // an agent looking for SSH reachability wrote
@@ -1635,9 +1836,10 @@ function parseLeaf(tok: string): Term {
1635
1836
  if (bad) {
1636
1837
  const name = bad[1];
1637
1838
  const value = tok.slice(name.length + 1);
1839
+ const prefixes = LEAF_PREFIXES.filter((p) => p.listed).map((p) => `${p.prefix}:`).join(", ");
1638
1840
  throw new QueryError(
1639
1841
  `"${tok}" is not a term — there is no "${name}:" prefix`,
1640
- `for an attribute, say attr:${name}=${value || "<value>"}; the prefixes are kind:, attr:, tag:, and ->/<- for edges`,
1842
+ `for an attribute, say attr:${name}=${value || "<value>"}; the prefixes are ${prefixes}, and ->/<- for edges`,
1641
1843
  );
1642
1844
  }
1643
1845
  return { kind: "word", a: tok };
@@ -1825,9 +2027,15 @@ function matchTerm(n: IRNode, t: Term, ir?: GraphIR, byId?: Map<string, IRNode>)
1825
2027
  const val = attrString((attrs as Record<string, unknown>)[t.a]);
1826
2028
  return t.b === undefined ? t.a in attrs : val.toLowerCase().includes(t.b.toLowerCase());
1827
2029
  }
2030
+ if (t.kind === "id") return hasCloudId(n, t.a);
1828
2031
  if (t.kind === "tag") {
1829
2032
  const tags = (attrs as Record<string, unknown>)["Tags"];
1830
- if (!Array.isArray(tags)) return false;
2033
+ if (!Array.isArray(tags)) {
2034
+ // An indexed node keeps its tags as a map (#4521), not a Tags list.
2035
+ return Object.entries(n.tags ?? {}).some(
2036
+ ([key, val]) => key.toLowerCase() === t.a.toLowerCase() && (t.b === undefined || String(val).toLowerCase().includes(t.b.toLowerCase())),
2037
+ );
2038
+ }
1831
2039
  return tags.some((tag) => {
1832
2040
  const key = attrString((tag as Record<string, unknown>)?.Key);
1833
2041
  const val = attrString((tag as Record<string, unknown>)?.Value);
@@ -1844,6 +2052,18 @@ function matchTerm(n: IRNode, t: Term, ir?: GraphIR, byId?: Map<string, IRNode>)
1844
2052
  return hay.includes(t.a.toLowerCase());
1845
2053
  }
1846
2054
 
2055
+ /**
2056
+ * Whether a node carries `id` as one of its cloud ids (#4534): its observed
2057
+ * `physicalId`, or any value in its engine facts' `cloudIds` (an ARN, an
2058
+ * import id, a self-link). The match is exact, case included: a cloud id is
2059
+ * an identifier, and a substring of one names another object. A bare word
2060
+ * never reads either field.
2061
+ */
2062
+ function hasCloudId(n: IRNode, id: string): boolean {
2063
+ if (n.physicalId === id) return true;
2064
+ return (n.facts?.cloudIds ?? []).some((c) => c.value === id);
2065
+ }
2066
+
1847
2067
  /**
1848
2068
  * One edge on the path a match was reached by (#4359), in walk order from the
1849
2069
  * match outward. `from` and `to` keep the edge's own direction (`from` holds
@@ -1918,7 +2138,15 @@ function findPath(n: IRNode, t: Term, ir: GraphIR, byId: Map<string, IRNode>): P
1918
2138
  return found ? found.hops : null;
1919
2139
  }
1920
2140
 
2141
+ /**
2142
+ * A cloud-listed node's path-style id (behold#1025 Q2,
2143
+ * `<substrate>/<scopeId>/<location>/<listedType>/<nativeId>`), printed whole:
2144
+ * its listed type holds `::`, which is not a stack qualification.
2145
+ */
2146
+ const INDEX_NODE_ID = /^(aws|azure|gcp|kubernetes)\/[^/]+\/[^/]+\/[^/]+\/./;
2147
+
1921
2148
  function bareId(id: string): string {
2149
+ if (INDEX_NODE_ID.test(id)) return id;
1922
2150
  return id.includes("::") ? id.slice(id.lastIndexOf("::") + 2) : id;
1923
2151
  }
1924
2152
 
@@ -2044,16 +2272,21 @@ function formatHops(hops: PathHop[], start: string): string {
2044
2272
  .join("; ");
2045
2273
  }
2046
2274
 
2047
- function formatRow(n: IRNode, show: string[]): string {
2275
+ function formatRow(n: IRNode, show: string[], join?: IndexJoin): string {
2048
2276
  const attrs = (n.attrs ?? {}) as Record<string, unknown>;
2049
2277
  // Display the bare logical id, not the `${stack}::` qualification (#1162).
2050
- const displayId = n.id.includes("::") ? n.id.slice(n.id.lastIndexOf("::") + 2) : n.id;
2278
+ const displayId = bareId(n.id);
2051
2279
  // A terraform resource shows its type (#4366); its IR kind is `Terraform::Resource` for all of them.
2052
2280
  const parts: string[] = [displayId, displayKind(n) ?? ""];
2053
2281
  // Prefer the node-level live physicalId (set by the overlay), then attrs;
2054
2282
  // skip source-mode AttrRef placeholders (objects).
2055
2283
  const physical = (n as { physicalId?: unknown }).physicalId ?? attrs["physicalId"] ?? attrs["InstanceId"] ?? attrs["Id"];
2056
- if (physical != null && typeof physical !== "object") parts.push(String(physical));
2284
+ // A row joined to an index (#4525) that did not bind says which verdict it
2285
+ // got where the physical id would go: a declared InstanceId is not one the
2286
+ // index confirmed.
2287
+ const cell = join ? joinCell(join) : undefined;
2288
+ if (cell) parts.push(cell);
2289
+ else if (physical != null && typeof physical !== "object") parts.push(String(physical));
2057
2290
  // A row nobody could read says so where its physical id would go (#1263). A
2058
2291
  // blank there reads as "declared, not provisioned", which the read never
2059
2292
  // established; the reason is the tri-state's (#1089).
@@ -28,6 +28,12 @@ describe("parseArgs", () => {
28
28
  expect(parseArgs(["import", "--from", "prod", "--skip-undeclarable"]).skipUndeclarable).toBe(true);
29
29
  });
30
30
 
31
+ test("import --index takes a selection: --type, --name, repeatable --tag, --select, --all (#4524)", () => {
32
+ const args = parseArgs(["import", "--index", "i.json", "--type", "AWS::S3::Bucket,AWS::IAM::Role", "--tag", "team=a", "--tag", "env=prod", "--select", "ids.json", "--all"]);
33
+ expect(args).toMatchObject({ command: "import", index: "i.json", selectType: "AWS::S3::Bucket,AWS::IAM::Role", selectTags: ["team=a", "env=prod"], selectAddress: "ids.json", all: true });
34
+ expect(() => parseArgs(["import", "--index", "i.json", "--tag", "team"])).toThrow(/--tag needs key=value/);
35
+ });
36
+
31
37
  test("--fold and --no-fold set the tri-state fold option (#1134)", () => {
32
38
  expect(parseArgs(["build", "src"]).fold).toBeUndefined();
33
39
  expect(parseArgs(["build", "src", "--fold"]).fold).toBe(true);
@@ -851,6 +857,7 @@ describe("workspace init and ls (#2534)", () => {
851
857
  "workspace box",
852
858
  "workspace build",
853
859
  "workspace check",
860
+ "workspace drift",
854
861
  "workspace evidence",
855
862
  "workspace exit",
856
863
  "workspace export",