@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
@@ -0,0 +1,517 @@
1
+ // chant#4532: `chant index <substrate>` and `indexCloud`, moved from behold#1026.
2
+ // The refusal of every action flag, the default store location, the pipeline
3
+ // (typeListing, deriveEdges, a stamped write) over a fake lister, and that
4
+ // nothing is written outside the store. Nothing here opens a socket: the lister
5
+ // is faked, or the real one runs over a fake fetcher.
6
+ import { mkdirSync, mkdtempSync, readdirSync, statSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join, relative, sep } from "node:path";
9
+ import { describe, expect, it } from "vitest";
10
+ import { fakeFetcher, json, refusingChains } from "../cloud-lister/fakes";
11
+ import type { ParsedArgs } from "../cli/registry";
12
+ import {
13
+ ACTION_FLAGS,
14
+ CLOUD_INDEX_FLOOR,
15
+ chantUserStoreDir,
16
+ findChantProject,
17
+ indexCloud,
18
+ IndexUsageError,
19
+ listCloud,
20
+ parseIndexArgs,
21
+ planIndexStore,
22
+ runCloudIndex,
23
+ scopeAndTarget,
24
+ type CloudScope,
25
+ type IndexStore,
26
+ type ListingResult,
27
+ type RunCloudIndexOptions,
28
+ type StorePlan,
29
+ type SubstrateTarget,
30
+ } from "./cloud-index";
31
+ import type { IndexDocument } from "./index-document";
32
+ import { NEXT_RELEASE } from "../release-floors";
33
+ import { createSnapshotStore } from "./snapshot-store";
34
+
35
+ const ACCOUNT = "000000000000";
36
+ const ENDPOINT = "http://localhost:4566";
37
+ const EMULATOR_ENV = { AWS_ACCESS_KEY_ID: "test", AWS_SECRET_ACCESS_KEY: "test" };
38
+
39
+ function listing(scope: CloudScope, startedAt: string): ListingResult {
40
+ const at = startedAt;
41
+ const res = (listedType: string, nativeId: string, properties: Record<string, unknown>) => {
42
+ const location = listedType.startsWith("AWS::IAM::") ? "global" : "us-east-1";
43
+ return {
44
+ id: `aws/${scope.scopeId}/${location}/${listedType}/${nativeId}`,
45
+ listedType,
46
+ location,
47
+ nativeId,
48
+ cloudIds: [{ kind: "import-id" as const, value: nativeId }],
49
+ tags: {},
50
+ properties,
51
+ observedAt: at,
52
+ facts: { cloudIds: [{ kind: "import-id" as const, value: nativeId }], observedAt: at },
53
+ };
54
+ };
55
+ return {
56
+ listing: "v1",
57
+ source: { name: "chant-lister", version: "test" },
58
+ scope,
59
+ startedAt: at,
60
+ completedAt: at,
61
+ resources: [
62
+ res("AWS::S3::Bucket", "web-assets", { BucketName: "web-assets", Arn: "arn:aws:s3:::web-assets" }),
63
+ res("AWS::IAM::Role", "app-role", { RoleName: "app-role", Arn: `arn:aws:iam::${scope.scopeId}:role/app-role` }),
64
+ ],
65
+ coverage: [
66
+ { listedType: "AWS::IAM::Role", location: "global", verdict: "listed" },
67
+ { listedType: "AWS::S3::Bucket", location: "us-east-1", verdict: "listed" },
68
+ ],
69
+ notes: [],
70
+ };
71
+ }
72
+
73
+ /** A lister that records what it was asked and answers {@link listing}, one second later each call. */
74
+ function fakeLister(start = "2026-10-26T12:00:00.000Z") {
75
+ const calls: Array<{ scope: CloudScope; target: SubstrateTarget }> = [];
76
+ let t = Date.parse(start);
77
+ return {
78
+ calls,
79
+ list: async (scope: CloudScope, target: SubstrateTarget) => {
80
+ calls.push({ scope, target });
81
+ const at = new Date(t).toISOString();
82
+ t += 1000;
83
+ return listing(scope, at);
84
+ },
85
+ };
86
+ }
87
+
88
+ /** A store that keeps writes in memory, and records each plan it was opened for. */
89
+ function fakeStore() {
90
+ const writes: IndexDocument[] = [];
91
+ const opened: StorePlan[] = [];
92
+ const store: IndexStore = {
93
+ kind: "local",
94
+ where: "fake-store",
95
+ writable: true,
96
+ async writeIndex(doc) {
97
+ writes.push(doc);
98
+ const name = `${doc.stamp.observedAt.replace(/[-:]|\.\d{3}/g, "")}-${doc.stamp.digest.slice(0, 12)}.json`;
99
+ return { written: true, path: `${doc.stamp.scopeKey}/${name}` };
100
+ },
101
+ async listIndex() {
102
+ return [];
103
+ },
104
+ };
105
+ return {
106
+ writes,
107
+ opened,
108
+ openStore: async (plan: StorePlan) => {
109
+ opened.push(plan);
110
+ return store;
111
+ },
112
+ };
113
+ }
114
+
115
+ function tempTree() {
116
+ const root = mkdtempSync(join(tmpdir(), "chant-index-"));
117
+ const cwd = join(root, "cwd");
118
+ const home = join(root, "home");
119
+ const xdg = join(root, "xdg");
120
+ for (const d of [cwd, home, xdg]) mkdirSync(d, { recursive: true });
121
+ return { root, cwd, home, xdg };
122
+ }
123
+
124
+ /** Every file under `root`, relative and sorted. */
125
+ function files(root: string, rel = ""): string[] {
126
+ const out: string[] = [];
127
+ for (const n of readdirSync(join(root, rel)).sort()) {
128
+ const r = rel ? join(rel, n) : n;
129
+ if (statSync(join(root, r)).isDirectory()) out.push(...files(root, r));
130
+ else out.push(r);
131
+ }
132
+ return out;
133
+ }
134
+
135
+ function capture() {
136
+ const out: string[] = [];
137
+ const err: string[] = [];
138
+ return { out, err, stdout: (s: string) => void out.push(s), stderr: (s: string) => void err.push(s) };
139
+ }
140
+
141
+ const noLexicons: RunCloudIndexOptions["lexicons"] = async () => ({ lexicons: [] });
142
+
143
+ describe("the floor", () => {
144
+ it("names the next release", () => {
145
+ expect(CLOUD_INDEX_FLOOR).toBe(NEXT_RELEASE);
146
+ });
147
+ });
148
+
149
+ describe("chant index refuses every action flag", () => {
150
+ it("names the flag, wherever it sits and in either form", () => {
151
+ for (const flag of ACTION_FLAGS) {
152
+ for (const argv of [["aws", flag], [flag, "aws"], ["aws", "--account", ACCOUNT, `${flag}=1`]]) {
153
+ let caught: unknown;
154
+ try {
155
+ parseIndexArgs(argv);
156
+ } catch (e) {
157
+ caught = e;
158
+ }
159
+ expect(caught, `${argv.join(" ")}`).toBeInstanceOf(IndexUsageError);
160
+ expect((caught as IndexUsageError).actionFlag).toBe(flag);
161
+ expect((caught as Error).message).toMatch(/read-only/);
162
+ }
163
+ }
164
+ });
165
+
166
+ it("the action flags include every action verb", () => {
167
+ for (const f of ["--apply", "--deploy", "--destroy", "--rollback", "--op", "--approve", "--enable-api", "--yes"]) expect(ACTION_FLAGS).toContain(f);
168
+ });
169
+
170
+ it("stops before the lister or the store is touched", async () => {
171
+ const t = tempTree();
172
+ const store = fakeStore();
173
+ const lister = fakeLister();
174
+ const io = capture();
175
+ let lexiconLookups = 0;
176
+ for (const flag of ACTION_FLAGS) {
177
+ const code = await runCloudIndex(["aws", "--account", ACCOUNT, "--regions", "us-east-1", flag], {
178
+ cwd: t.cwd,
179
+ home: t.home,
180
+ env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg },
181
+ stdout: io.stdout,
182
+ stderr: io.stderr,
183
+ list: lister.list,
184
+ openStore: store.openStore,
185
+ lexicons: async () => {
186
+ lexiconLookups++;
187
+ return { lexicons: [] };
188
+ },
189
+ });
190
+ expect(code, flag).toBe(2);
191
+ }
192
+ expect(store.opened).toEqual([]);
193
+ expect(lexiconLookups).toBe(0);
194
+ expect(lister.calls).toEqual([]);
195
+ expect(store.writes).toEqual([]);
196
+ expect(io.out).toEqual([]);
197
+ expect(io.err.join("")).toMatch(/chant index is read-only and refuses --apply/);
198
+ expect(files(t.root)).toEqual([]);
199
+ });
200
+
201
+ it("the registry entry refuses an action flag core's parser kept", async () => {
202
+ const { runIndexCommand } = await import("../cli/handlers/index-cloud");
203
+ const args = { command: "index", path: "aws", positionals: ["aws"], format: "", fix: false, watch: false, verbose: false, help: false, live: false, yes: true } as unknown as ParsedArgs;
204
+ const code = await runIndexCommand({ args, plugins: [], serializers: [] });
205
+ expect(code).toBe(2);
206
+ });
207
+
208
+ it("an unknown flag is a usage error, not a pass", () => {
209
+ expect(() => parseIndexArgs(["aws", "--frobnicate"])).toThrow(/unknown argument/);
210
+ expect(() => parseIndexArgs(["--account", ACCOUNT])).toThrow(/needs a substrate/);
211
+ expect(() => parseIndexArgs(["cloudflare"])).toThrow(/unknown substrate/);
212
+ });
213
+
214
+ it("names the caller's command", () => {
215
+ expect(() => parseIndexArgs(["aws", "--apply"], "behold index")).toThrow(/^behold index is read-only and refuses --apply/);
216
+ });
217
+ });
218
+
219
+ describe("chant index over a fake lister", () => {
220
+ it("lists the scope asked for, types it, derives edges and writes one version", async () => {
221
+ const t = tempTree();
222
+ const store = fakeStore();
223
+ const lister = fakeLister();
224
+ const io = capture();
225
+ const code = await runCloudIndex(
226
+ ["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1,eu-west-1", "--types", "AWS::S3::Bucket,AWS::IAM::Role", "--tag", "team=web"],
227
+ { cwd: t.cwd, home: t.home, env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg }, stdout: io.stdout, stderr: io.stderr, list: lister.list, openStore: store.openStore, lexicons: noLexicons },
228
+ );
229
+ expect(io.err).toEqual([]);
230
+ expect(code).toBe(0);
231
+ expect(lister.calls).toHaveLength(1);
232
+ expect(lister.calls[0].scope).toEqual({
233
+ substrate: "aws",
234
+ scopeId: ACCOUNT,
235
+ locations: ["us-east-1", "eu-west-1"],
236
+ types: ["AWS::S3::Bucket", "AWS::IAM::Role"],
237
+ tagFilter: { team: "web" },
238
+ });
239
+ expect(lister.calls[0].target).toEqual({ substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } });
240
+ // The default store is the per-user one (no project, no --store).
241
+ expect(store.opened).toEqual([{ kind: "user", dir: join(t.xdg, "chant") }]);
242
+ expect(store.writes).toHaveLength(1);
243
+ const doc = store.writes[0];
244
+ // chant's typeListing ran: path-style ids, kept as unknown kind with no lexicon.
245
+ expect(doc.graph.nodes.map((n) => n.id).sort()).toEqual([`aws/${ACCOUNT}/global/AWS::IAM::Role/app-role`, `aws/${ACCOUNT}/us-east-1/AWS::S3::Bucket/web-assets`]);
246
+ expect(doc.graph.nodes.every((n) => n.unmappedKind === true)).toBe(true);
247
+ expect(doc.stamp.source).toMatchObject({ kind: "cloud", name: "chant-lister" });
248
+ const text = io.out.join("");
249
+ expect(text).toMatch(/2 nodes \(0 typed, 2 of unknown kind\), 0 derived edges/);
250
+ expect(text).toMatch(/^chant index: wrote \d{8}T\d{6}Z-[0-9a-f]{12}\.json under cloud\/aws\/000000000000\/\S+ in fake-store$/m);
251
+ });
252
+
253
+ it("a second run writes a second version", async () => {
254
+ const t = tempTree();
255
+ const store = fakeStore();
256
+ const lister = fakeLister();
257
+ const opts: RunCloudIndexOptions = { cwd: t.cwd, home: t.home, env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg }, stdout: () => {}, stderr: () => {}, list: lister.list, openStore: store.openStore, lexicons: noLexicons };
258
+ expect(await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], opts)).toBe(0);
259
+ expect(await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], opts)).toBe(0);
260
+ expect(store.writes.map((d) => d.stamp.observedAt)).toEqual(["2026-10-26T12:00:00.000Z", "2026-10-26T12:00:01.000Z"]);
261
+ });
262
+
263
+ it("--json prints one object with the verdict fields", async () => {
264
+ const t = tempTree();
265
+ const store = fakeStore();
266
+ const io = capture();
267
+ const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1", "--json"], {
268
+ cwd: t.cwd,
269
+ home: t.home,
270
+ env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg },
271
+ stdout: io.stdout,
272
+ stderr: io.stderr,
273
+ list: fakeLister().list,
274
+ openStore: store.openStore,
275
+ lexicons: noLexicons,
276
+ });
277
+ expect(code).toBe(0);
278
+ const summary = JSON.parse(io.out.join(""));
279
+ expect(summary).toMatchObject({ substrate: "aws", scopeId: ACCOUNT, written: true, nodes: 2, coverage: { listed: 2, notObserved: 0 } });
280
+ });
281
+
282
+ it("with an endpoint and no static credentials it is refused, and no SDK chain is asked", async () => {
283
+ const t = tempTree();
284
+ const store = fakeStore();
285
+ const chains = refusingChains();
286
+ const fake = fakeFetcher(() => undefined);
287
+ const io = capture();
288
+ const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
289
+ cwd: t.cwd,
290
+ home: t.home,
291
+ env: { XDG_DATA_HOME: t.xdg },
292
+ stdout: io.stdout,
293
+ stderr: io.stderr,
294
+ listOptions: { fetcher: fake.fetcher, chains, retryDelays: [] },
295
+ openStore: store.openStore,
296
+ lexicons: noLexicons,
297
+ });
298
+ expect(code).toBe(2);
299
+ expect(io.err.join("")).toMatch(/needs static credentials/);
300
+ expect(chains.count).toEqual({ aws: 0, azure: 0, gcp: 0 });
301
+ expect(fake.calls).toEqual([]);
302
+ expect(store.writes).toEqual([]);
303
+ });
304
+
305
+ it("the command itself writes nothing: with a fake store the tree is unchanged", async () => {
306
+ const t = tempTree();
307
+ const store = fakeStore();
308
+ await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
309
+ cwd: t.cwd,
310
+ home: t.home,
311
+ env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg },
312
+ stdout: () => {},
313
+ stderr: () => {},
314
+ list: fakeLister().list,
315
+ openStore: store.openStore,
316
+ lexicons: noLexicons,
317
+ });
318
+ expect(store.writes).toHaveLength(1);
319
+ expect(files(t.root)).toEqual([]);
320
+ });
321
+
322
+ it("a read-only store is refused before anything is listed", async () => {
323
+ const lister = fakeLister();
324
+ const io = capture();
325
+ const ro: IndexStore = { kind: "orphan-branch", where: "chant/lifecycle", writable: false, writeIndex: async () => ({ written: false }), listIndex: async () => [] };
326
+ const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
327
+ env: EMULATOR_ENV,
328
+ stdout: io.stdout,
329
+ stderr: io.stderr,
330
+ list: lister.list,
331
+ openStore: async () => ro,
332
+ lexicons: noLexicons,
333
+ });
334
+ expect(code).toBe(2);
335
+ expect(lister.calls).toEqual([]);
336
+ expect(io.err.join("")).toMatch(/read-only/);
337
+ });
338
+ });
339
+
340
+ describe("indexCloud, the library function", () => {
341
+ it("runs list, typeListing, deriveEdges and one write, and returns all three", async () => {
342
+ const store = fakeStore();
343
+ const lister = fakeLister();
344
+ const scope: CloudScope = { substrate: "aws", scopeId: ACCOUNT, locations: ["us-east-1"], types: "*" };
345
+ const target: SubstrateTarget = { substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } };
346
+ const s = await store.openStore({ kind: "user", dir: "/unused" });
347
+ const r = await indexCloud({ scope, target, store: s, lexicons: [], version: "9.9.9" }, { list: lister.list });
348
+ expect(lister.calls).toEqual([{ scope, target }]);
349
+ expect(r.listing.resources).toHaveLength(2);
350
+ expect(r.doc.stamp.scopeKey.startsWith(`cloud/aws/${ACCOUNT}/`)).toBe(true);
351
+ expect(r.write.written).toBe(true);
352
+ expect(store.writes).toEqual([r.doc]);
353
+ });
354
+
355
+ it("types through a lexicon's listedTypes and runs its catalog", async () => {
356
+ const store = fakeStore();
357
+ const s = await store.openStore({ kind: "user", dir: "/unused" });
358
+ // A lexicon whose kind for every AWS type is the type itself, with an empty catalog.
359
+ const lexicon = {
360
+ name: "aws",
361
+ listedTypes: { substrate: "aws" as const, kindFor: (t: string) => t },
362
+ referenceCatalog: { identities: [], refs: [] },
363
+ };
364
+ const r = await indexCloud(
365
+ {
366
+ scope: { substrate: "aws", scopeId: ACCOUNT, locations: ["us-east-1"], types: "*" },
367
+ target: { substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } },
368
+ store: s,
369
+ lexicons: [lexicon],
370
+ },
371
+ { list: fakeLister().list },
372
+ );
373
+ expect(r.doc.graph.nodes.map((n) => n.kind).sort()).toEqual(["AWS::IAM::Role", "AWS::S3::Bucket"]);
374
+ expect(r.doc.graph.nodes.some((n) => n.unmappedKind === true)).toBe(false);
375
+ // Whatever a catalog draws is derived; an empty one draws nothing.
376
+ expect(r.doc.graph.edges).toEqual([]);
377
+ });
378
+
379
+ it("a store whose write throws is an IndexWriteError, after the listing", async () => {
380
+ const { IndexWriteError } = await import("./cloud-index");
381
+ const boom: IndexStore = { kind: "local", where: "x", writable: true, writeIndex: async () => { throw new Error("disk full"); }, listIndex: async () => [] };
382
+ await expect(
383
+ indexCloud(
384
+ { scope: { substrate: "aws", scopeId: ACCOUNT, locations: ["us-east-1"], types: "*" }, target: { substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "t", secretAccessKey: "t" } } }, store: boom, lexicons: [] },
385
+ { list: fakeLister().list },
386
+ ),
387
+ ).rejects.toBeInstanceOf(IndexWriteError);
388
+ });
389
+ });
390
+
391
+ describe("scope and target from flags and the environment", () => {
392
+ const deps = { cwd: "/w", home: "/h" };
393
+ it("aws takes its region from AWS_REGION and its endpoint from AWS_ENDPOINT_URL", () => {
394
+ const { scope, target } = scopeAndTarget(parseIndexArgs(["aws", "--account", ACCOUNT]), { ...deps, env: { ...EMULATOR_ENV, AWS_REGION: "us-west-2", AWS_ENDPOINT_URL: ENDPOINT } });
395
+ expect(scope).toEqual({ substrate: "aws", scopeId: ACCOUNT, locations: ["us-west-2"], types: "*" });
396
+ expect(target).toEqual({ substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } });
397
+ });
398
+ it("azure and gcp read chant's token variables", () => {
399
+ const az = scopeAndTarget(parseIndexArgs(["azure", "--subscription", "s", "--endpoint", "https://localhost:4577"]), { ...deps, env: { CHANT_AZURE_TOKEN: "a" } });
400
+ expect(az.target).toEqual({ substrate: "azure", azure: { endpoint: "https://localhost:4577", token: "a" } });
401
+ const g = scopeAndTarget(parseIndexArgs(["gcp", "--project", "p", "--endpoint", "http://localhost:4588/cloudasset"]), { ...deps, env: { CHANT_GCP_TOKEN: "g" } });
402
+ expect(g.target).toEqual({ substrate: "gcp", gcp: { endpoint: "http://localhost:4588/cloudasset", token: "g" } });
403
+ });
404
+ it("gcp --anonymous sends no token, and needs an endpoint", () => {
405
+ const { target } = scopeAndTarget(parseIndexArgs(["gcp", "--project", "plc-corpus", "--endpoint", "http://localhost:4588/cloudasset", "--anonymous"]), { ...deps, env: {} });
406
+ expect(target).toEqual({ substrate: "gcp", gcp: { endpoint: "http://localhost:4588/cloudasset", token: null } });
407
+ expect(() => parseIndexArgs(["gcp", "--project", "p", "--anonymous"])).toThrow(/needs --endpoint/);
408
+ });
409
+ it("needs a scope id, and skips TLS checks only on loopback", () => {
410
+ expect(() => scopeAndTarget(parseIndexArgs(["azure"]), { ...deps, env: {} })).toThrow(/--subscription/);
411
+ expect(() => scopeAndTarget(parseIndexArgs(["azure", "--subscription", "s", "--endpoint", "https://management.azure.com", "--insecure-skip-verify"]), { ...deps, env: {} })).toThrow(/loopback/);
412
+ });
413
+ });
414
+
415
+ describe("the default store location (behold#1025 Q4)", () => {
416
+ it("is chant's per-user data directory", () => {
417
+ expect(chantUserStoreDir({ XDG_DATA_HOME: "/x" }, "/h")).toBe(join("/x", "chant"));
418
+ expect(chantUserStoreDir({}, "/h")).toBe(join("/h", ".local", "share", "chant"));
419
+ expect(chantUserStoreDir({ XDG_DATA_HOME: "relative" }, "/h")).toBe(join("/h", ".local", "share", "chant"));
420
+ expect(chantUserStoreDir({ CHANT_INDEX_DIR: "/d/index" }, "/h")).toBe("/d");
421
+ expect(() => chantUserStoreDir({ CHANT_INDEX_DIR: "/d/elsewhere" }, "/h")).toThrow(/must end in \/index/);
422
+ });
423
+
424
+ it("is used with no project and no --store, wherever the command runs", () => {
425
+ const none = () => false;
426
+ const dflt = () => chantUserStoreDir({ XDG_DATA_HOME: "/x" }, "/h");
427
+ expect(planIndexStore({ cwd: "/a/b", env: {}, defaultStoreDir: dflt, exists: none })).toEqual({ kind: "user", dir: join("/x", "chant") });
428
+ expect(planIndexStore({ cwd: "/elsewhere", env: {}, defaultStoreDir: dflt, exists: none })).toEqual({ kind: "user", dir: join("/x", "chant") });
429
+ });
430
+
431
+ it("is the caller's when it passes one (behold's userIndexDir parent)", async () => {
432
+ const store = fakeStore();
433
+ await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
434
+ command: "behold index",
435
+ defaultStoreDir: () => "/x/behold",
436
+ env: EMULATOR_ENV,
437
+ cwd: "/",
438
+ exists: () => false,
439
+ stdout: () => {},
440
+ stderr: () => {},
441
+ list: fakeLister().list,
442
+ openStore: store.openStore,
443
+ lexicons: noLexicons,
444
+ });
445
+ expect(store.opened).toEqual([{ kind: "user", dir: "/x/behold" }]);
446
+ });
447
+
448
+ it("gives way to a chant project's store, and to --store", () => {
449
+ const exists = (p: string) => p === join("/proj", "chant.config.ts");
450
+ const dflt = () => "/unused";
451
+ expect(findChantProject(join("/proj", "sub"), exists)).toBe("/proj");
452
+ expect(planIndexStore({ cwd: join("/proj", "sub"), env: {}, defaultStoreDir: dflt, exists })).toEqual({ kind: "project", projectDir: "/proj" });
453
+ const local = planIndexStore({ store: "local:out", cwd: "/w", env: {}, defaultStoreDir: dflt, exists });
454
+ expect(local).toMatchObject({ kind: "spec", configured: { store: "local" }, env: { CHANT_SNAPSHOT_STORE: "local", CHANT_SNAPSHOT_STORE_DIR: join("/w", "out") } });
455
+ const s3 = planIndexStore({ store: "s3://bucket/some/prefix/", cwd: "/w", env: {}, defaultStoreDir: dflt });
456
+ expect(s3).toMatchObject({ kind: "spec", env: { CHANT_SNAPSHOT_STORE: "s3", CHANT_SNAPSHOT_S3_BUCKET: "bucket", CHANT_SNAPSHOT_S3_PREFIX: "some/prefix" } });
457
+ expect(planIndexStore({ store: "git-ref:refs/x", cwd: "/w", env: {}, defaultStoreDir: dflt })).toMatchObject({ configured: { store: "git-ref", ref: "refs/x" } });
458
+ expect(() => planIndexStore({ store: "orphan-branch", cwd: "/w", env: {}, defaultStoreDir: dflt })).toThrow(/read-only/);
459
+ expect(() => planIndexStore({ store: "ftp://x", cwd: "/w", env: {}, defaultStoreDir: dflt })).toThrow(/not a store spec/);
460
+ });
461
+ });
462
+
463
+ describe("chant index with the real local store", () => {
464
+ it("writes only under the per-user store, and two runs give two versions under one scope.json", async () => {
465
+ const t = tempTree();
466
+ const lister = fakeLister();
467
+ const env = { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg };
468
+ const opts: RunCloudIndexOptions = { cwd: t.cwd, home: t.home, env, stdout: () => {}, stderr: () => {}, list: lister.list, lexicons: noLexicons, exists: () => false };
469
+ const argv = ["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1", "--types", "AWS::S3::Bucket,AWS::IAM::Role"];
470
+ expect(await runCloudIndex(argv, opts)).toBe(0);
471
+ expect(await runCloudIndex(argv, opts)).toBe(0);
472
+
473
+ const all = files(t.root);
474
+ const storeIndex = relative(t.root, join(t.xdg, "chant", "index")) + sep;
475
+ expect(all.length).toBeGreaterThan(0);
476
+ for (const f of all) expect(f.startsWith(storeIndex), f).toBe(true);
477
+ expect(files(t.cwd)).toEqual([]);
478
+ expect(files(t.home)).toEqual([]);
479
+
480
+ const versions = all.filter((f) => /\d{8}T\d{6}Z-[0-9a-f]{12}\.json$/.test(f));
481
+ expect(versions).toHaveLength(2);
482
+ expect(all.filter((f) => f.endsWith(`${sep}scope.json`))).toHaveLength(1);
483
+ expect(versions.every((v) => v.includes(`${sep}cloud${sep}aws${sep}${ACCOUNT}${sep}`))).toBe(true);
484
+
485
+ const store = createSnapshotStore({ store: "local", dir: join(t.xdg, "chant") }, { cwd: t.cwd });
486
+ const scopeKey = relative(storeIndex, versions[0]).split(sep).slice(0, -1).join("/");
487
+ expect(await store.listIndex(scopeKey)).toHaveLength(2);
488
+ });
489
+ });
490
+
491
+ describe("the real lister through the command", () => {
492
+ it("lists over a fake fetcher with static credentials and sends only reads", async () => {
493
+ const store = fakeStore();
494
+ const fake = fakeFetcher(() => json(200, { TypeName: "AWS::S3::Bucket", ResourceDescriptions: [] }));
495
+ const chains = refusingChains();
496
+ const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1", "--types", "AWS::S3::Bucket"], {
497
+ env: EMULATOR_ENV,
498
+ cwd: "/",
499
+ exists: () => false,
500
+ stdout: () => {},
501
+ stderr: () => {},
502
+ listOptions: { fetcher: fake.fetcher, chains, retryDelays: [] },
503
+ openStore: store.openStore,
504
+ lexicons: noLexicons,
505
+ });
506
+ expect(code).toBe(0);
507
+ expect(fake.calls).toHaveLength(1);
508
+ expect(fake.calls[0].headers["x-amz-target"] ?? fake.calls[0].headers["X-Amz-Target"]).toBe("CloudApiService.ListResources");
509
+ expect(chains.count).toEqual({ aws: 0, azure: 0, gcp: 0 });
510
+ expect(store.writes).toHaveLength(1);
511
+ });
512
+ });
513
+
514
+ // listCloud is the lister's own export, re-exported for library callers.
515
+ it("re-exports the lister", () => {
516
+ expect(typeof listCloud).toBe("function");
517
+ });