@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
package/src/cli/main.ts CHANGED
@@ -173,7 +173,9 @@ Commands:
173
173
  terms, ->* / ->{1,3} for depth, ->[via=attr] / [to=attr]
174
174
  by attribute; --live or --snapshot <ref> (also --at
175
175
  <ref>) with --env <name> reads the estate or a
176
- recorded snapshot; --show <attr>,
176
+ recorded snapshot; --index <scope key>[@<version>]
177
+ answers from an index version, joined to the
178
+ declared rows, or alone with no project; --show <attr>,
177
179
  --count-by kind|module|attr:<name>, --explain prints
178
180
  paths, --json, --check-live,
179
181
  --check-snapshot, --fail-on-drift; cap:<name> and
@@ -191,6 +193,16 @@ Commands:
191
193
  --where <field><op><value> (= != < <= > >= ~,
192
194
  repeatable), --since <time|7d>, --at <rev> of
193
195
  chant/lifecycle, --member <name>, --json
196
+ index <substrate> Read one aws account, azure subscription, gcp project
197
+ or kubernetes cluster through its inventory API, type
198
+ it, derive its edges and write one index version to
199
+ the index store. Read-only: refuses action flags.
200
+ --account|--subscription|--project|--cluster, --regions,
201
+ --types, --tag k=v, --endpoint, --store <spec>, --json
202
+ (chant index --help for the rest)
203
+ index diff <a> [<b>] What changed between two index versions of one scope:
204
+ <scopeKey>/<version>, or <scopeKey> for its last two.
205
+ --store <spec>, --json (chant index diff --help)
194
206
  generate Generate typed code from sources chant.config declares
195
207
  (k8s.crds, helm.charts) into src/generated/<lexicon>/
196
208
  (codegen.outDir); --check exits 1 when the committed
@@ -624,6 +636,12 @@ Workspace (level 1, #2524):
624
636
  choudoufu runs live-check and the adoption report;
625
637
  choudoufu or other to chant runs chant import), staged
626
638
  in a worktree and gated on the patch digest like upgrade
639
+ workspace promote --all [--state-dir <dir>] [--state <member>=<tfstate>]... [--canary <member>] [--wave-size <n>] [--dry-run] [--json]
640
+ Adopt every terraform member into choudoufu in waves:
641
+ the canary first (default the first member), then
642
+ --wave-size roots a wave (default 5), one gate per
643
+ root bound to its live-import report digest. A wave
644
+ that does not land stops the later ones (#4461)
627
645
  workspace ls [dir] List the declaration's members and example groups.
628
646
  A member that can't be read is listed with a reason
629
647
  code and still exits 0. --at <rev> reads a commit's
@@ -981,6 +999,15 @@ Workspace (level 1, #2524):
981
999
  --no-cache reads every member
982
1000
  --capability-view: each member's chant adds its
983
1001
  capability view, mapped by its own lexicons
1002
+ workspace drift --member <name> [--read <state|plan|refresh|live-read|ownership>] [--resource <addr>] [--env <name>] [--stream] [-o <file>]
1003
+ One member's drift, read by its own engine: a chant
1004
+ member through lifecycle diff --live (needs --env), a
1005
+ terraform member through its state or a plan, a
1006
+ choudoufu member through live-plan (and a plan for
1007
+ --read plan), one resource through choudoufu
1008
+ live-plan -resource. One drift document, or with
1009
+ --stream the NDJSON stream (drift-start, records,
1010
+ drift-settle)
984
1011
  workspace search "<query>" [--member <name>] [--env <name>] [--snapshot <ref> | --live] [--at <rev>] [--explain] [--count-by ...] [--json]
985
1012
  chant search in every chant member, each under its own
986
1013
  chant, as one read-contract document: ids are
@@ -1038,6 +1065,8 @@ Lifecycle (alias: lc):
1038
1065
  (lexicons with a deep reader also report
1039
1066
  property-level drift; --update-baseline records
1040
1067
  what it reports as accepted so it stops alerting)
1068
+ --index <ref>: compare source with an index version
1069
+ in the store, no deploy and no cloud read (#4526)
1041
1070
  lifecycle plan <env> Typed change set (create/update/delete/adopt) vs live
1042
1071
  --deep: also report properties declared
1043
1072
  heldElsewhere(). Never changes what the plan
@@ -1050,6 +1079,9 @@ Lifecycle (alias: lc):
1050
1079
  drift: ECS running vs desired, Route 53 health
1051
1080
  checks, Container Apps revisions, Cloud Run Ready.
1052
1081
  A failed read is "not read", never unhealthy (--json)
1082
+ lifecycle drift Each lexicon's own drift read, as drift-record
1083
+ NDJSON (--member, --read, --resource); what
1084
+ workspace drift runs in a member's reader project
1053
1085
  lifecycle whoami <env> Who chant would act as in each configured lexicon,
1054
1086
  and what that principal is scoped to — read-only,
1055
1087
  before anything acts (--json, --strict)
@@ -1354,6 +1386,7 @@ Examples:
1354
1386
  chant import manifest.yaml --lexicon k8s --output ./infra/
1355
1387
  chant import dash.json --lexicon grafana --parser-option acceptLossyV1
1356
1388
  chant import --from prod --name my-bucket --output src/
1389
+ chant import --index index.json --type AWS::S3::Bucket --output src/imported/
1357
1390
  chant lint ./infra/
1358
1391
  chant lint ./infra/ --format sarif
1359
1392
  chant lint ./infra/ --watch
@@ -1564,6 +1597,10 @@ export const commandRegistry: CommandDef[] = [
1564
1597
  // #4297 — SQL over the snapshots, runs, gates, deploys and releases on chant/lifecycle. Imported on first use.
1565
1598
  { name: "query", runsNoConfig: true, handler: async (ctx) => (await import("./handlers/query")).runQueryCommand(ctx) },
1566
1599
  { name: "ledger", runsNoConfig: true, handler: async (ctx) => (await import("./handlers/ledger")).runLedgerCommand(ctx) },
1600
+ // chant#4532 — a read-only cloud index. main() hands `index`'s raw argv to
1601
+ // its own parser before parseArgs; this entry answers "is it a verb" and
1602
+ // runs the words a caller already parsed (substrate, --json, --help).
1603
+ { name: "index", runsNoConfig: true, handler: async (ctx) => (await import("./handlers/index-cloud")).runIndexCommand(ctx) },
1567
1604
  // chant#2591 — `import --agents` and `audit` read chant.config statically
1568
1605
  // and never evaluate it (chant#2589 for audit, which audits code it must not run).
1569
1606
  { name: "import", handler: runImport, runsNoConfig: (args) => args.agents === true },
@@ -1702,6 +1739,7 @@ export const commandRegistry: CommandDef[] = [
1702
1739
  { name: "workspace run", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/workspace-run")).runWorkspaceRun(ctx) },
1703
1740
  // #2554 — a release train: one release of every chant member, pinned in the workspace ledger.
1704
1741
  { name: "workspace train", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/release-train")).runWorkspaceTrain(ctx) },
1742
+ { name: "workspace drift", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/drift-cli")).runWorkspaceDrift(ctx) },
1705
1743
  { name: "workspace search", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/search-cli")).runWorkspaceSearch(ctx) },
1706
1744
  // Each unit decides for itself whether its config is loaded (runCommandInProcess).
1707
1745
  { name: "workspace member-run", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/member-run")).runWorkspaceMemberRun(ctx, runCommandInProcess) },
@@ -1730,6 +1768,7 @@ export const commandRegistry: CommandDef[] = [
1730
1768
  { name: "lifecycle rollback", handler: runLifecycleRollback },
1731
1769
  { name: "lifecycle plan", requiresPlugins: true, handler: runLifecyclePlan },
1732
1770
  { name: "lifecycle affected", requiresPlugins: true, handler: runLifecycleAffected },
1771
+ { name: "lifecycle drift", requiresPlugins: true, handler: async (ctx) => (await import("./handlers/lifecycle-drift")).runLifecycleDrift(ctx) },
1733
1772
  { name: "lifecycle whoami", requiresPlugins: true, handler: runLifecycleWhoami },
1734
1773
  // #4177 — runtime health, separate from drift. Imported on first use.
1735
1774
  { name: "lifecycle health", requiresPlugins: true, handler: async (ctx) => (await import("./handlers/lifecycle-health")).runLifecycleHealth(ctx) },
@@ -1790,6 +1829,22 @@ async function main(): Promise<void> {
1790
1829
  installCompiledCli();
1791
1830
  const rawArgv = process.argv.slice(2);
1792
1831
 
1832
+ // chant#4532 — `chant index <substrate>` takes its own flags (--account,
1833
+ // --regions, --endpoint, ...) that core's one flat parser does not know, and
1834
+ // must refuse an action flag (--apply, --yes, ...) that the parser would
1835
+ // accept. So its argv goes to its own parser, before parseArgs.
1836
+ if (rawArgv[0] === "index" && rawArgv[1] === "diff") {
1837
+ // #4533 — `chant index diff <a> [<b>]`: two stored versions of one scope.
1838
+ const { runIndexDiff } = await import("./handlers/index-diff");
1839
+ await flushAndExit(await runIndexDiff(rawArgv.slice(2)));
1840
+ return;
1841
+ }
1842
+ if (rawArgv[0] === "index") {
1843
+ const { runCloudIndex } = await import("../lifecycle/cloud-index");
1844
+ await flushAndExit(await runCloudIndex(rawArgv.slice(1)));
1845
+ return;
1846
+ }
1847
+
1793
1848
  let args: ParsedArgs;
1794
1849
  try {
1795
1850
  args = parseArgs(rawArgv);
@@ -1,7 +1,7 @@
1
1
  import { resolve } from "node:path";
2
2
  import type { LexiconPlugin } from "../../lexicon";
3
3
  import type { ToolDefinition, ToolHandler } from "./types";
4
- import { readSnapshot } from "../../lifecycle/git";
4
+ import { resolveSnapshotStore } from "../../lifecycle/snapshot-store";
5
5
  import { build } from "../../build";
6
6
  import { computeBuildDigest, diffDigests } from "../../lifecycle/digest";
7
7
  import { takeSnapshot } from "../../lifecycle/snapshot";
@@ -71,8 +71,9 @@ export function createDiffTool(plugins: LexiconPlugin[]): ToolRegistration {
71
71
  const currentDigest = computeBuildDigest(buildResult);
72
72
  const lexicons = lexiconFilter ? [lexiconFilter] : buildResult.manifest.lexicons;
73
73
  const results: Record<string, unknown> = {};
74
+ const store = await resolveSnapshotStore();
74
75
  for (const lex of lexicons) {
75
- const content = await readSnapshot(env, lex);
76
+ const content = await store.readLatest(env, lex);
76
77
  let previousDigest = undefined;
77
78
  if (content) {
78
79
  const snapshot: LifecycleSnapshot = JSON.parse(content);
@@ -4,7 +4,7 @@ import type { ResourceDefinition } from "./types";
4
4
  import type { LexiconPlugin } from "../../lexicon";
5
5
  import { collectComposites } from "./tools/composites";
6
6
  import { getContext } from "./resources/context";
7
- import { readSnapshot, readEnvironmentSnapshots } from "../../lifecycle/git";
7
+ import { readEnvironmentSnapshotsFrom, resolveSnapshotStore } from "../../lifecycle/snapshot-store";
8
8
  import { discoverOps } from "../../op/discover";
9
9
  import { createLocalOpRuntime } from "../../op/runtimes/local";
10
10
  import { loadOkfBundle } from "../../okf-read";
@@ -224,14 +224,15 @@ export async function handleResourcesRead(
224
224
  const environment = parts[0];
225
225
  const lexicon = parts[1];
226
226
 
227
+ const store = await resolveSnapshotStore();
227
228
  if (lexicon) {
228
- const content = await readSnapshot(environment, lexicon);
229
+ const content = await store.readLatest(environment, lexicon);
229
230
  if (!content) throw new Error(`No snapshot found for ${environment}/${lexicon}`);
230
231
  return {
231
232
  contents: [{ uri, mimeType: "application/json", text: content }],
232
233
  };
233
234
  } else {
234
- const snapshots = await readEnvironmentSnapshots(environment);
235
+ const snapshots = await readEnvironmentSnapshotsFrom(store, environment);
235
236
  const result: Record<string, unknown> = {};
236
237
  for (const [lex, content] of snapshots) {
237
238
  result[lex] = JSON.parse(content);
@@ -127,7 +127,7 @@ export const workspaceReadTools: ToolDefinition[] = [
127
127
  name: "workspace-search",
128
128
  description:
129
129
  "Answer an estate question over every chant member of the workspace with a few rows instead of the whole graph: chant workspace search <query> --json (search.schema.json, #4374). Returns that document unchanged. Each member is searched under its own chant and alone, ids are <member>/<id> as workspace-graph names the same nodes, and a member that can't be searched is listed with a reason code, never as zero matches. " +
130
- "The query is space-separated terms that must all match: a bare word (substring of id, kind or attributes), kind:<substr> (a Terraform resource matches its type, kind:aws_instance), attr:<name>=<value>, tag:<key>=<value>, and edge terms ->X (this node references a node matching X) and <-X (referenced by one); ->*X is any depth, ->{2}X or ->{1,3}X a number of hops, ->[via=attr]X and ->[to=attr]X pick the edge by attribute, and !term negates. " +
130
+ "The query is space-separated terms that must all match: a bare word (substring of id, kind or attributes), kind:<substr> (a Terraform resource matches its type, kind:aws_instance), attr:<name>=<value>, tag:<key>=<value>, id:<cloud id> (exact, over physical and cloud ids), and edge terms ->X (this node references a node matching X) and <-X (referenced by one); ->*X is any depth, ->{2}X or ->{1,3}X a number of hops, ->[via=attr]X and ->[to=attr]X pick the edge by attribute, and !term negates. " +
131
131
  "at is the git revision of the source; snapshot (with env) answers from a recorded lifecycle snapshot such as latest. They are two different times, and at refuses a snapshot ref.",
132
132
  inputSchema: {
133
133
  type: "object",
@@ -24,6 +24,7 @@ const BOOLEAN_FLAGS = new Set([
24
24
  "--agents",
25
25
  "--agent",
26
26
  "--all-projects",
27
+ "--all",
27
28
  "--force",
28
29
  "--fix",
29
30
  "--watch",
@@ -78,6 +79,7 @@ const BOOLEAN_FLAGS = new Set([
78
79
  "--no-require-review",
79
80
  "--expire",
80
81
  "--check-live",
82
+ "--stream",
81
83
  "--check-snapshot",
82
84
  "--fail-on-drift",
83
85
  "--durable-requests",
@@ -247,6 +249,11 @@ export function parseArgs(args: string[]): ParsedArgs {
247
249
  const v = args[++i];
248
250
  if (!v || v.startsWith("-")) throw new Error("--parser-option needs key or key=value: --parser-option acceptLossyV1");
249
251
  (result.parserOption ??= []).push(v);
252
+ } else if (arg === "--tag") {
253
+ // `chant import --index <ref> --tag key=value` (#4524), repeatable: every tag must match.
254
+ const v = args[++i];
255
+ if (!v || v.startsWith("-") || !v.includes("=")) throw new Error("--tag needs key=value: --tag team=payments");
256
+ (result.selectTags ??= []).push(v);
250
257
  } else if (arg === "--type") {
251
258
  result.selectType = args[++i];
252
259
  } else if (arg === "--name") {
@@ -266,6 +273,20 @@ export function parseArgs(args: string[]): ParsedArgs {
266
273
  result.skipUndeclarable = true;
267
274
  } else if (arg === "--state") {
268
275
  result.statePath = args[++i];
276
+ // `chant workspace promote --all --state <member>=<path>` (#4461), repeatable.
277
+ if (result.statePath !== undefined) (result.statePaths ??= []).push(result.statePath);
278
+ } else if (arg === "--state-dir") {
279
+ // `chant workspace promote --all --state-dir <dir>` (#4461): <dir>/<member>.tfstate.
280
+ result.stateDir = args[++i];
281
+ if (!result.stateDir || result.stateDir.startsWith("-")) throw new Error("--state-dir needs a directory: --state-dir <dir>");
282
+ } else if (arg === "--wave-size") {
283
+ const raw = args[++i];
284
+ const size = Number(raw);
285
+ if (!Number.isInteger(size) || size < 1) throw new Error(`--wave-size needs a whole number from 1: got "${raw ?? ""}"`);
286
+ result.waveSize = size;
287
+ } else if (arg === "--all") {
288
+ // `chant workspace promote --all` (#4461): every terraform member.
289
+ result.all = true;
269
290
  } else if (arg === "--select") {
270
291
  result.selectAddress = args[++i];
271
292
  } else if (arg === "--live-name") {
@@ -980,9 +1001,14 @@ export function parseArgs(args: string[]): ParsedArgs {
980
1001
  result.tags = args[++i];
981
1002
  if (!result.tags || result.tags.startsWith("-")) throw new Error("--tags needs a tag glob: --tags 'v*'");
982
1003
  } else if (arg === "--index") {
983
- // #2551 — `chant workspace adopt-lineage --index <file>`.
1004
+ // #2551 — `chant workspace adopt-lineage --index <file>`; #4525 — `chant search --index <ref>`;
1005
+ // #4526 — `chant lifecycle diff <env> --index <ref>`.
984
1006
  result.index = args[++i];
985
- if (!result.index || result.index.startsWith("-")) throw new Error("--index needs a hash index file: --index <file>");
1007
+ if (!result.index || result.index.startsWith("-")) throw new Error("--index needs a value: --index <file> for workspace adopt-lineage, --index <scope key>[@<version>] for search and lifecycle diff");
1008
+ } else if (arg === "--adopt-out") {
1009
+ // #4536 — `chant import --index <ref> --adopt-out <file>`: write the adoption file (`adopt: v1`) for what was imported.
1010
+ result.adoptOut = args[++i];
1011
+ if (!result.adoptOut || result.adoptOut.startsWith("-")) throw new Error("--adopt-out needs a file: --adopt-out <file>");
986
1012
  } else if (arg === "--remove") {
987
1013
  // #2552 — `chant workspace import --remove` removes the export member instead of writing it again.
988
1014
  result.remove = true;
@@ -1024,6 +1050,18 @@ export function parseArgs(args: string[]): ParsedArgs {
1024
1050
  const value = args[++i];
1025
1051
  if (value === undefined || value.startsWith("--")) throw new Error("--where needs a clause: --where <field><op><value>");
1026
1052
  result.where = [...(result.where ?? []), value];
1053
+ } else if (arg === "--read") {
1054
+ // behold#995 - `chant workspace drift --read <read>`: which read the member's engine answers with.
1055
+ const value = args[++i];
1056
+ if (!value || value.startsWith("-")) throw new Error("--read needs a read: --read <state|plan|refresh|live-read|ownership>");
1057
+ result.driftRead = value;
1058
+ } else if (arg === "--stream") {
1059
+ result.stream = true;
1060
+ } else if (arg === "--resource") {
1061
+ // behold#995 - `chant workspace drift --resource <addr>`: one resource's drift.
1062
+ const value = args[++i];
1063
+ if (!value || value.startsWith("--")) throw new Error("--resource needs an address: --resource <addr>");
1064
+ result.resource = value;
1027
1065
  } else if (arg === "--since") {
1028
1066
  result.since = args[++i];
1029
1067
  } else if (arg === "--limit") {
@@ -91,6 +91,14 @@ export interface ParsedArgs {
91
91
  parserOption?: string[];
92
92
  /** `chant carve advise --state <path>` — opt-in .tfstate for accurate instance counts */
93
93
  statePath?: string;
94
+ /** Every `--state` value in order (#4461): `chant workspace promote --all --state <member>=<path>`, repeatable. */
95
+ statePaths?: string[];
96
+ /** `chant workspace promote --all --state-dir <dir>` (#4461): a member's state is `<dir>/<member>.tfstate`. */
97
+ stateDir?: string;
98
+ /** `chant workspace promote --all --wave-size <n>` (#4461): roots per wave after the canary. */
99
+ waveSize?: number;
100
+ /** `chant workspace promote --all` (#4461): promote every terraform member, in waves. */
101
+ all?: boolean;
94
102
  /** `chant carve emit --select <tf-address>` — the Terraform resource to carve */
95
103
  selectAddress?: string;
96
104
  /** `chant carve emit --live-name <logicalId>` — CFN logical ID for live adoption */
@@ -127,6 +135,8 @@ export interface ParsedArgs {
127
135
  selectType?: string;
128
136
  /** `chant import --name <name>` selector */
129
137
  selectName?: string;
138
+ /** `chant import --index <ref> --tag key=value` (#4524), repeatable */
139
+ selectTags?: string[];
130
140
  /** `chant import --owned` — restrict live import to chant-owned resources */
131
141
  owned?: boolean;
132
142
  /**
@@ -157,7 +167,9 @@ export interface ParsedArgs {
157
167
  source?: string;
158
168
  /** `chant workspace adopt-lineage --tags <glob>` and `hash-index --tags` (#2551): the tags to compare. */
159
169
  tags?: string;
160
- /** `chant workspace adopt-lineage --index <file>` (#2551): a cached hash index. */
170
+ /** `chant workspace adopt-lineage --index <file>` (#2551): a cached hash index. `chant search --index <ref>` (#4525) and `chant lifecycle diff <env> --index <ref>` (#4526): an index version. */
171
+ /** `chant import --index <ref> --adopt-out <file>` (#4536): where to write the adoption file. */
172
+ adoptOut?: string;
161
173
  index?: string;
162
174
  /** `chant workspace versions --available` (#2551): list each git template's version tags. */
163
175
  available?: boolean;
@@ -496,6 +508,12 @@ export interface ParsedArgs {
496
508
  store?: "tree" | "ledger";
497
509
  /** `chant workspace points answer <id> --answer <value>` (#2739): the people's answer. */
498
510
  answer?: string;
511
+ /** `chant workspace drift --read <state|plan|refresh|live-read|ownership>` and `chant lifecycle drift --read` (behold#995): the read to ask the member's engine for. Unset, the member kind's default read. */
512
+ driftRead?: string;
513
+ /** `chant workspace drift --stream` (behold#995): print the drift stream (drift-start, records, drift-settle) as NDJSON instead of one document. */
514
+ stream?: boolean;
515
+ /** `chant workspace drift --resource <addr>` and `chant lifecycle drift --resource` (behold#995): read one resource, through `choudoufu live-plan -resource` on a choudoufu member. */
516
+ resource?: string;
499
517
  /** `chant workspace graph --no-cache` (#2876): read every member, bypassing the per-member cache. */
500
518
  noCache?: boolean;
501
519
  /** `chant workspace graph --composites` (#2662): print each composite instance with the components that can deploy it. */
@@ -0,0 +1,202 @@
1
+ /**
2
+ * behold#1029: the AWS lister against a fake Cloud Control. Response shapes
3
+ * follow the pinned floci's CloudControlJsonHandler (source c688f52ee):
4
+ * `{ TypeName, ResourceDescriptions: [{ Identifier, Properties }] }`, with
5
+ * `Properties` a JSON string.
6
+ */
7
+ import { describe, expect, it } from "vitest";
8
+ import { listCloud } from "./index";
9
+ import { ListerConfigError } from "./credentials";
10
+ import { MASKED } from "./mask";
11
+ import { signV4 } from "./sigv4";
12
+ import { fakeFetcher, json, refusingChains, steppingClock } from "./fakes";
13
+ import type { WireCall } from "./guard";
14
+
15
+ const ENDPOINT = "http://localhost:4566";
16
+ const CREDS = { accessKeyId: "test", secretAccessKey: "test" };
17
+
18
+ function target() {
19
+ return { substrate: "aws" as const, aws: { endpoint: ENDPOINT, credentials: CREDS } };
20
+ }
21
+
22
+ function typeOf(call: WireCall): { TypeName: string; NextToken?: string } {
23
+ return JSON.parse(call.body ?? "{}");
24
+ }
25
+
26
+ describe("signV4", () => {
27
+ // AWS's published SigV4 test suite, case get-vanilla.
28
+ it("matches the get-vanilla known answer", () => {
29
+ const headers = signV4({
30
+ method: "GET",
31
+ url: "https://example.amazonaws.com/",
32
+ headers: {},
33
+ body: "",
34
+ region: "us-east-1",
35
+ service: "service",
36
+ credentials: { accessKeyId: "AKIDEXAMPLE", secretAccessKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" },
37
+ now: new Date("2015-08-30T12:36:00Z"),
38
+ });
39
+ expect(headers.authorization).toBe(
40
+ "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31",
41
+ );
42
+ });
43
+ });
44
+
45
+ describe("listing aws", () => {
46
+ it("lists each type per region, pages, and fills the listing-result shape", async () => {
47
+ const fake = fakeFetcher((call) => {
48
+ const { TypeName, NextToken } = typeOf(call);
49
+ if (TypeName === "AWS::S3::Bucket" && !NextToken) {
50
+ return json(200, {
51
+ TypeName,
52
+ ResourceDescriptions: [
53
+ { Identifier: "web-assets", Properties: JSON.stringify({ BucketName: "web-assets", Arn: "arn:aws:s3:::web-assets", Tags: [{ Key: "tofu-estate", Value: "web" }, { Key: "tofu-address", Value: "aws_s3_bucket.assets" }] }) },
54
+ ],
55
+ NextToken: "page2",
56
+ });
57
+ }
58
+ if (TypeName === "AWS::S3::Bucket" && NextToken === "page2") {
59
+ return json(200, { TypeName, ResourceDescriptions: [{ Identifier: "logs", Properties: JSON.stringify({ BucketName: "logs" }) }] });
60
+ }
61
+ if (TypeName === "AWS::RDS::DBInstance") {
62
+ return json(200, {
63
+ TypeName,
64
+ ResourceDescriptions: [{ Identifier: "db1", Properties: JSON.stringify({ DBInstanceIdentifier: "db1", MasterUserPassword: "hunter2", Tags: [{ Key: "api-token", Value: "abc" }] }) }],
65
+ });
66
+ }
67
+ return undefined;
68
+ });
69
+ const result = await listCloud(
70
+ { substrate: "aws", scopeId: "000000000000", locations: ["us-east-1"], types: ["AWS::S3::Bucket", "AWS::RDS::DBInstance"] },
71
+ target(),
72
+ { fetcher: fake.fetcher, chains: refusingChains(), now: steppingClock(), retryDelays: [], version: "0.30.2" },
73
+ );
74
+
75
+ expect(result.listing).toBe("v1");
76
+ expect(result.source).toEqual({ name: "chant-lister", version: "0.30.2" });
77
+ expect(result.scope.types).toEqual(["AWS::RDS::DBInstance", "AWS::S3::Bucket"]);
78
+ expect(fake.calls.every((c) => c.url === `${ENDPOINT}/`)).toBe(true);
79
+ expect(fake.calls[0].headers.authorization).toMatch(/^AWS4-HMAC-SHA256 Credential=test\/\d{8}\/us-east-1\/cloudcontrolapi\/aws4_request/);
80
+ expect(fake.calls[0].headers["x-amz-target"]).toBe("CloudApiService.ListResources");
81
+
82
+ const bucket = result.resources.find((r) => r.nativeId === "web-assets")!;
83
+ expect(bucket.id).toBe("aws/000000000000/us-east-1/AWS::S3::Bucket/web-assets");
84
+ expect(bucket.listedType).toBe("AWS::S3::Bucket");
85
+ expect(bucket.location).toBe("us-east-1");
86
+ expect(bucket.cloudIds).toEqual([
87
+ { kind: "arn", value: "arn:aws:s3:::web-assets" },
88
+ { kind: "import-id", value: "web-assets" },
89
+ ]);
90
+ expect(bucket.tags).toEqual({ "tofu-estate": "web", "tofu-address": "aws_s3_bucket.assets" });
91
+ expect(bucket.facts).toEqual({
92
+ markers: { owner: "web", address: "aws_s3_bucket.assets", encoding: "escaped", source: "live" },
93
+ cloudIds: bucket.cloudIds,
94
+ observedAt: bucket.observedAt,
95
+ });
96
+ expect(Object.keys(bucket.facts).sort()).toEqual(["cloudIds", "markers", "observedAt"]);
97
+ expect(result.resources.map((r) => r.nativeId)).toContain("logs");
98
+
99
+ const db = result.resources.find((r) => r.nativeId === "db1")!;
100
+ expect(db.properties.MasterUserPassword).toBe(MASKED);
101
+ expect(db.tags["api-token"]).toBe(MASKED);
102
+ expect(JSON.stringify(result)).not.toContain("hunter2");
103
+ expect(JSON.stringify(result)).not.toContain('"abc"');
104
+
105
+ expect(result.coverage).toEqual([
106
+ { listedType: "AWS::RDS::DBInstance", location: "us-east-1", verdict: "listed" },
107
+ { listedType: "AWS::S3::Bucket", location: "us-east-1", verdict: "listed" },
108
+ ]);
109
+ expect(result.notes).toEqual([]);
110
+ });
111
+
112
+ it("lists a global type once, as location global", async () => {
113
+ const fake = fakeFetcher(() => json(200, { ResourceDescriptions: [{ Identifier: "app-role", Properties: JSON.stringify({ RoleName: "app-role", Arn: "arn:aws:iam::000000000000:role/app-role" }) }] }));
114
+ const result = await listCloud(
115
+ { substrate: "aws", scopeId: "000000000000", locations: ["us-east-1", "eu-west-1"], types: ["AWS::IAM::Role"] },
116
+ target(),
117
+ { fetcher: fake.fetcher, chains: refusingChains(), now: steppingClock(), retryDelays: [] },
118
+ );
119
+ expect(fake.calls.length).toBe(1);
120
+ expect(result.resources[0].id).toBe("aws/000000000000/global/AWS::IAM::Role/app-role");
121
+ expect(result.coverage).toEqual([{ listedType: "AWS::IAM::Role", location: "global", verdict: "listed" }]);
122
+ });
123
+
124
+ it("puts a type it cannot list in the notes, with its reason", async () => {
125
+ const fake = fakeFetcher((call) => {
126
+ const { TypeName } = typeOf(call);
127
+ if (TypeName === "AWS::Foo::Bar") return json(400, { __type: "com.amazon.cloudapiservice#UnsupportedActionException", message: "Resource type AWS::Foo::Bar does not support LIST action" });
128
+ if (TypeName === "AWS::EC2::SubnetRouteTableAssociation") return json(400, { __type: "InvalidRequestException", message: "Missing Or Invalid ResourceModel property in AWS::EC2::SubnetRouteTableAssociation list handler request input" });
129
+ if (TypeName === "AWS::S3::Bucket") return json(400, { __type: "AccessDeniedException", message: "not authorized" });
130
+ return undefined;
131
+ });
132
+ const result = await listCloud(
133
+ { substrate: "aws", scopeId: "000000000000", locations: ["us-east-1"], types: ["AWS::Foo::Bar", "AWS::EC2::SubnetRouteTableAssociation", "AWS::S3::Bucket"] },
134
+ target(),
135
+ { fetcher: fake.fetcher, chains: refusingChains(), now: steppingClock(), retryDelays: [] },
136
+ );
137
+ expect(result.resources).toEqual([]);
138
+ expect(result.coverage.map((c) => [c.listedType, c.verdict])).toEqual([
139
+ ["AWS::EC2::SubnetRouteTableAssociation", "unsupported-kind"],
140
+ ["AWS::Foo::Bar", "unsupported-kind"],
141
+ ["AWS::S3::Bucket", "no-credentials"],
142
+ ]);
143
+ expect(result.notes.map((n) => [n.code, n.listedType])).toEqual([
144
+ ["needs-parent", "AWS::EC2::SubnetRouteTableAssociation"],
145
+ ["no-lister", "AWS::Foo::Bar"],
146
+ ["no-credentials", "AWS::S3::Bucket"],
147
+ ]);
148
+ expect(result.notes[1].message).toContain("does not support LIST");
149
+ });
150
+
151
+ it("filters by tag after listing, and marks coverage filtered", async () => {
152
+ const fake = fakeFetcher(() =>
153
+ json(200, {
154
+ ResourceDescriptions: [
155
+ { Identifier: "a", Properties: JSON.stringify({ Tags: [{ Key: "env", Value: "prod" }] }) },
156
+ { Identifier: "b", Properties: JSON.stringify({ Tags: [{ Key: "env", Value: "dev" }] }) },
157
+ ],
158
+ }),
159
+ );
160
+ const result = await listCloud(
161
+ { substrate: "aws", scopeId: "000000000000", locations: ["us-east-1"], types: ["AWS::SQS::Queue"], tagFilter: { env: "prod" } },
162
+ target(),
163
+ { fetcher: fake.fetcher, chains: refusingChains(), now: steppingClock(), retryDelays: [] },
164
+ );
165
+ expect(result.resources.map((r) => r.nativeId)).toEqual(["a"]);
166
+ expect(result.coverage[0].verdict).toBe("filtered");
167
+ expect(result.notes.map((n) => n.code)).toEqual(["tag-filter"]);
168
+ });
169
+
170
+ it('lists the default types for types "*" and says so', async () => {
171
+ const fake = fakeFetcher(() => json(200, { ResourceDescriptions: [] }));
172
+ const result = await listCloud(
173
+ { substrate: "aws", scopeId: "000000000000", locations: ["us-east-1"], types: "*" },
174
+ target(),
175
+ { fetcher: fake.fetcher, chains: refusingChains(), now: steppingClock(), retryDelays: [] },
176
+ );
177
+ expect(result.notes[0].code).toBe("default-types");
178
+ expect(fake.calls.length).toBeGreaterThan(20);
179
+ });
180
+
181
+ it("refuses every region, which would need a call off the allowlist", async () => {
182
+ const fake = fakeFetcher(() => undefined);
183
+ await expect(
184
+ listCloud({ substrate: "aws", scopeId: "0", locations: "*", types: ["AWS::S3::Bucket"] }, target(), { fetcher: fake.fetcher, chains: refusingChains() }),
185
+ ).rejects.toThrow(ListerConfigError);
186
+ expect(fake.calls).toEqual([]);
187
+ });
188
+
189
+ it("never asks the default provider chain when an endpoint is given", async () => {
190
+ const chains = refusingChains();
191
+ const fake = fakeFetcher(() => undefined);
192
+ await expect(
193
+ listCloud(
194
+ { substrate: "aws", scopeId: "0", locations: ["us-east-1"], types: ["AWS::S3::Bucket"] },
195
+ { substrate: "aws", aws: { endpoint: ENDPOINT } },
196
+ { fetcher: fake.fetcher, chains },
197
+ ),
198
+ ).rejects.toThrow(/needs static credentials/);
199
+ expect(chains.count.aws).toBe(0);
200
+ expect(fake.calls).toEqual([]);
201
+ });
202
+ });