@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,736 @@
1
+ /**
2
+ * `chant index <substrate>` and the library function behind it (chant#4532,
3
+ * tier 1 of INTENTIUS/behold#1025). It fills an index from a cloud with no
4
+ * project and keeps it in the index store.
5
+ *
6
+ * Built in behold as behold#1026 (the command) and behold#1029 (the lister),
7
+ * and moved here on the ruling that behold is a control plane and every
8
+ * model lives in chant
9
+ * (https://github.com/INTENTIUS/behold/issues/1024#issuecomment-6433236820).
10
+ * behold's `behold index` calls {@link runCloudIndex} with its own command
11
+ * name and default store directory.
12
+ *
13
+ * The pipeline, behold#1025's design as ruled (Q1-Q6, 2026-10-26):
14
+ *
15
+ * listCloud(scope, target) ../cloud-lister/
16
+ * -> ListingResult
17
+ * -> typeListing ./type-listing.ts (#4521)
18
+ * -> deriveEdges ./derive-edges.ts (#4522, with #4523's identity pass)
19
+ * -> IndexDocument
20
+ * -> store.writeIndex ./snapshot-store.ts (#4519)
21
+ *
22
+ * One run writes one version (Q6): one substrate and one account,
23
+ * subscription, project or cluster, with every location and type the flags
24
+ * name. The version is one immutable file (Q3),
25
+ * `index/cloud/<substrate>/<scopeId>/<scope digest>/<observedAt>-<digest12>.json`
26
+ * under the store's root, beside the `scope.json` that says what the digest
27
+ * means. A second run writes a second version; the first stays.
28
+ *
29
+ * Where it writes:
30
+ *
31
+ * - `--store <spec>`: a store from its spec ({@link planIndexStore});
32
+ * - else, inside a chant project (a `chant.config.ts` or `chant.config.json`
33
+ * in the working directory or above it): that project's configured store;
34
+ * - else (Q4): a `local` store in chant's per-user data directory,
35
+ * `$XDG_DATA_HOME/chant`, else `~/.local/share/chant`
36
+ * ({@link chantUserStoreDir}). `CHANT_INDEX_DIR`, when set, names that
37
+ * store's `index/` directory. A caller (behold) passes its own
38
+ * `defaultStoreDir` instead.
39
+ *
40
+ * Read-only:
41
+ *
42
+ * - the lister sends only its allowlisted reads (../cloud-lister/guard.ts),
43
+ * pins every call to an explicit endpoint, and with an endpoint takes
44
+ * static credentials only, never an SDK's default chain;
45
+ * - the command refuses to start with any action flag ({@link ACTION_FLAGS})
46
+ * before anything else is read, and starts no server;
47
+ * - nothing is written but the one index version (and its `scope.json`), and
48
+ * the store is never published to a remote by this command;
49
+ * - for GCP nothing is enabled: when the Cloud Asset API is off, the
50
+ * lister's note carries the `gcloud services enable` command for the
51
+ * person to run.
52
+ *
53
+ * The index is never consulted for a decision. Deleting it loses history and
54
+ * nothing else.
55
+ *
56
+ * Environment the command reads (and nothing else):
57
+ *
58
+ * - aws: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`
59
+ * (static credentials, when the first two are set), `AWS_ENDPOINT_URL`
60
+ * (the endpoint when `--endpoint` is absent), `AWS_REGION` then
61
+ * `AWS_DEFAULT_REGION` (the region when `--regions` is absent);
62
+ * - azure: `CHANT_AZURE_TOKEN` (an ARM bearer token);
63
+ * - gcp: `CHANT_GCP_TOKEN` (an OAuth access token);
64
+ * - kubernetes: `KUBECONFIG` (its first path) when `--kubeconfig` is absent;
65
+ * - the store: `CHANT_INDEX_DIR`, `XDG_DATA_HOME`, and for `--store` the
66
+ * `CHANT_SNAPSHOT_*` variables ./snapshot-store.ts reads.
67
+ *
68
+ * The maintainer's emulator run (never run by an agent), against the pinned
69
+ * floci on 4566 with a scratch data dir:
70
+ *
71
+ * env -u AWS_PROFILE -u AWS_SESSION_TOKEN \
72
+ * AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test \
73
+ * XDG_DATA_HOME=$(mktemp -d) \
74
+ * npx tsx packages/core/src/cli/main.ts index aws --endpoint http://localhost:4566 \
75
+ * --account 000000000000 --regions us-east-1 \
76
+ * --types AWS::S3::Bucket,AWS::IAM::Role,AWS::SQS::Queue
77
+ *
78
+ * Its last line is the verdict, `chant index: wrote <version> ...`.
79
+ */
80
+ import { existsSync, readFileSync } from "node:fs";
81
+ import { homedir } from "node:os";
82
+ import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
83
+ import { CHANT_VERSION } from "../chant-version";
84
+ import {
85
+ kubeTargetFromKubeconfig,
86
+ listCloud,
87
+ ListerConfigError,
88
+ MutatingCallRefused,
89
+ OriginRefused,
90
+ type CloudScope,
91
+ type ListingResult,
92
+ type ListOptions,
93
+ type Substrate,
94
+ type SubstrateTarget,
95
+ } from "../cloud-lister/index";
96
+ import type { TlsOptions } from "../cloud-lister/transport";
97
+ import { NEXT_RELEASE } from "../release-floors";
98
+ import { deriveEdges, type EdgeLexicon } from "./derive-edges";
99
+ import type { IndexDocument } from "./index-document";
100
+ import { createSnapshotStore, resolveSnapshotStore, snapshotStoreConfig, type SnapshotStore, type StoreWrite } from "./snapshot-store";
101
+ import { typeListing, type ListingLexicon } from "./type-listing";
102
+
103
+ /** The first chant with `chant index` and {@link runCloudIndex} / {@link indexCloud}. */
104
+ export const CLOUD_INDEX_FLOOR = NEXT_RELEASE;
105
+
106
+ /** What typing and edge derivation read from a lexicon. A `LexiconPlugin` is one. */
107
+ export type IndexLexicon = ListingLexicon & EdgeLexicon;
108
+
109
+ /** The part of a {@link SnapshotStore} an index run uses. Tests pass a fake. */
110
+ export type IndexStore = Pick<SnapshotStore, "kind" | "where" | "writable" | "writeIndex" | "listIndex">;
111
+
112
+ // ── The pipeline ────────────────────────────────────────────────────────
113
+
114
+ export interface IndexCloudRequest {
115
+ scope: CloudScope;
116
+ target: SubstrateTarget;
117
+ /** Where the version goes. */
118
+ store: IndexStore;
119
+ /** The lexicons that type the substrate's listed types. Empty keeps every object as a node of unknown kind. */
120
+ lexicons: readonly IndexLexicon[];
121
+ /** The caller's version, for the stamp's `source.version`. Default chant's. */
122
+ version?: string;
123
+ }
124
+
125
+ export interface IndexCloudDeps {
126
+ /** The lister; tests pass a fake. */
127
+ list?: (scope: CloudScope, target: SubstrateTarget, options: ListOptions) => Promise<ListingResult>;
128
+ /** Options handed to the lister (a test's fetcher and chains). */
129
+ listOptions?: Omit<ListOptions, "version">;
130
+ }
131
+
132
+ export interface IndexCloudResult {
133
+ listing: ListingResult;
134
+ doc: IndexDocument;
135
+ write: StoreWrite;
136
+ }
137
+
138
+ /**
139
+ * List one scope, type it, derive its edges and write one stamped version.
140
+ * Throws what the lister throws ({@link ListerConfigError},
141
+ * {@link OriginRefused}, {@link MutatingCallRefused}, a failed read) before
142
+ * anything is written, and {@link IndexWriteError} when the store's write
143
+ * throws.
144
+ */
145
+ export async function indexCloud(req: IndexCloudRequest, deps: IndexCloudDeps = {}): Promise<IndexCloudResult> {
146
+ if (!req.store.writable && req.store.kind !== "none") {
147
+ throw new IndexUsageError(`the store ${req.store.where} is read-only`);
148
+ }
149
+ const listing = await (deps.list ?? listCloud)(req.scope, req.target, { ...(deps.listOptions ?? {}), version: req.version ?? CHANT_VERSION });
150
+ const doc = deriveEdges(typeListing(listing, req.lexicons), req.lexicons);
151
+ let write: StoreWrite;
152
+ try {
153
+ write = (await req.store.writeIndex(doc)) ?? { written: false, reason: `the ${req.store.kind} store keeps nothing` };
154
+ } catch (e) {
155
+ throw new IndexWriteError((e as Error).message);
156
+ }
157
+ return { listing, doc, write };
158
+ }
159
+
160
+ // ── Arguments ───────────────────────────────────────────────────────────
161
+
162
+ /** Flags that would reach an action (deploy, apply, Ops, rollbacks). An index run refuses every one. */
163
+ export const ACTION_FLAGS: readonly string[] = [
164
+ "--apply",
165
+ "--approve",
166
+ "--approver",
167
+ "--auto-approve",
168
+ "--adopt",
169
+ "--create",
170
+ "--delete",
171
+ "--deploy",
172
+ "--destroy",
173
+ "--enable",
174
+ "--enable-api",
175
+ "--fix",
176
+ "--import",
177
+ "--live",
178
+ "--op",
179
+ "--ops",
180
+ "--promote",
181
+ "--rollback",
182
+ "--run-op",
183
+ "--write",
184
+ "--yes",
185
+ ];
186
+
187
+ const SUBSTRATES: Readonly<Record<string, Substrate>> = { aws: "aws", azure: "azure", gcp: "gcp", kubernetes: "kubernetes", k8s: "kubernetes" };
188
+
189
+ /** The chant lexicon that types each substrate's listed types. */
190
+ export const SUBSTRATE_LEXICON: Readonly<Record<Substrate, string>> = { aws: "aws", azure: "azure", gcp: "gcp", kubernetes: "k8s" };
191
+
192
+ export function indexUsage(command = "chant index", storeDefault = "a local store in chant's per-user data directory ($XDG_DATA_HOME/chant, else ~/.local/share/chant)"): string {
193
+ return `${command} <aws|azure|gcp|kubernetes> [scope] [target] [--store <spec>] [--json]
194
+
195
+ Read one account, subscription, project or cluster through its inventory
196
+ API, type it through chant's lexicons, add derived edges, and write one
197
+ stamped index version to the index store. Read-only: it lists, and writes
198
+ nothing but the index version. Every run writes a new version; the old ones
199
+ stay.
200
+
201
+ Scope:
202
+ --account <id> | --subscription <id> | --project <id> | --cluster <name> | --scope-id <id>
203
+ The AWS account, Azure subscription, GCP project or
204
+ cluster name the run reads (required, except for
205
+ kubernetes, which defaults to the kubeconfig's cluster).
206
+ --regions <r,...> Regions or locations (kubernetes: namespaces). AWS needs
207
+ them named (default AWS_REGION); others default to all.
208
+ --locations <l,...> Same as --regions.
209
+ --types <t,...> Types as the inventory API names them (default: all,
210
+ or a fixed default set for AWS).
211
+ --tag <k=v> Only objects with this tag or label. Repeatable.
212
+
213
+ Target:
214
+ --endpoint <url> An emulator's endpoint. With one, credentials must be
215
+ static: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY,
216
+ CHANT_AZURE_TOKEN, CHANT_GCP_TOKEN or --anonymous.
217
+ No SDK default credential chain is used. AWS also reads
218
+ AWS_ENDPOINT_URL.
219
+ --anonymous gcp with --endpoint: send no token (floci-gcp).
220
+ --ca <file> A CA bundle for the endpoint's TLS.
221
+ --insecure-skip-verify
222
+ Skip TLS verification; only for a loopback endpoint.
223
+ --kubeconfig <file> kubernetes: the kubeconfig (default KUBECONFIG, then
224
+ ~/.kube/config). Token or client certificate only.
225
+ --context <name> kubernetes: the kubeconfig context.
226
+
227
+ Store:
228
+ --store <spec> local, local:<dir>, git-ref, git-ref:<ref>, s3,
229
+ s3://<bucket>[/<prefix>], or none.
230
+ Default: the chant project's store when run inside one,
231
+ else ${storeDefault}.
232
+ --json Print the result as one JSON object.
233
+
234
+ Refused: any action flag (${ACTION_FLAGS.slice(0, 5).join(", ")} and the rest of
235
+ ACTION_FLAGS in packages/core/src/lifecycle/cloud-index.ts). It starts no server.
236
+ `;
237
+ }
238
+
239
+ export interface IndexArgs {
240
+ substrate: Substrate;
241
+ scopeId?: string;
242
+ locations?: string[];
243
+ types?: string[];
244
+ tags: Record<string, string>;
245
+ endpoint?: string;
246
+ anonymous: boolean;
247
+ ca?: string;
248
+ insecureSkipVerify: boolean;
249
+ kubeconfig?: string;
250
+ context?: string;
251
+ store?: string;
252
+ json: boolean;
253
+ }
254
+
255
+ export class IndexUsageError extends Error {
256
+ constructor(
257
+ message: string,
258
+ readonly actionFlag?: string,
259
+ ) {
260
+ super(message);
261
+ this.name = "IndexUsageError";
262
+ }
263
+ }
264
+
265
+ function list(value: string): string[] {
266
+ return value
267
+ .split(",")
268
+ .map((s) => s.trim())
269
+ .filter(Boolean);
270
+ }
271
+
272
+ /** An index run's arguments. Throws {@link IndexUsageError}; an action flag is named in `actionFlag`. */
273
+ export function parseIndexArgs(argv: readonly string[], command = "chant index"): IndexArgs {
274
+ // An action flag is refused before anything else is read, wherever it sits.
275
+ for (const a of argv) {
276
+ const flag = a.startsWith("--") ? a.split("=")[0] : undefined;
277
+ if (flag && ACTION_FLAGS.includes(flag)) {
278
+ throw new IndexUsageError(
279
+ `${command} is read-only and refuses ${flag}: it lists and writes one index version, and no deploy, apply, Op or rollback is reachable from it. Nothing was listed and nothing was written.`,
280
+ flag,
281
+ );
282
+ }
283
+ }
284
+ const [first, ...rest] = argv;
285
+ if (!first || first.startsWith("-")) throw new IndexUsageError(`${command} needs a substrate: aws, azure, gcp or kubernetes`);
286
+ const substrate = SUBSTRATES[first];
287
+ if (!substrate) throw new IndexUsageError(`${command}: unknown substrate '${first}' (aws, azure, gcp or kubernetes)`);
288
+ const out: IndexArgs = { substrate, tags: {}, anonymous: false, insecureSkipVerify: false, json: false };
289
+ const scopeFlags = ["--account", "--subscription", "--project", "--cluster", "--scope-id"];
290
+ for (let i = 0; i < rest.length; i++) {
291
+ const raw = rest[i];
292
+ const eq = raw.startsWith("--") ? raw.indexOf("=") : -1;
293
+ const flag = eq > 0 ? raw.slice(0, eq) : raw;
294
+ const inline = eq > 0 ? raw.slice(eq + 1) : undefined;
295
+ const value = (): string => {
296
+ if (inline !== undefined) return inline;
297
+ const v = rest[i + 1];
298
+ if (v === undefined || v.startsWith("--")) throw new IndexUsageError(`${command}: ${flag} needs a value`);
299
+ i++;
300
+ return v;
301
+ };
302
+ if (scopeFlags.includes(flag)) {
303
+ const v = value();
304
+ if (out.scopeId !== undefined && out.scopeId !== v) throw new IndexUsageError(`${command} reads one account, subscription, project or cluster per run; got ${out.scopeId} and ${v}`);
305
+ out.scopeId = v;
306
+ } else if (flag === "--regions" || flag === "--locations" || flag === "--namespaces") {
307
+ out.locations = [...(out.locations ?? []), ...list(value())];
308
+ } else if (flag === "--types") {
309
+ out.types = [...(out.types ?? []), ...list(value())];
310
+ } else if (flag === "--tag") {
311
+ const v = value();
312
+ const at = v.indexOf("=");
313
+ if (at <= 0) throw new IndexUsageError(`${command}: --tag takes key=value, got '${v}'`);
314
+ out.tags[v.slice(0, at)] = v.slice(at + 1);
315
+ } else if (flag === "--endpoint") {
316
+ out.endpoint = value();
317
+ } else if (flag === "--anonymous") {
318
+ out.anonymous = true;
319
+ } else if (flag === "--ca") {
320
+ out.ca = value();
321
+ } else if (flag === "--insecure-skip-verify") {
322
+ out.insecureSkipVerify = true;
323
+ } else if (flag === "--kubeconfig") {
324
+ out.kubeconfig = value();
325
+ } else if (flag === "--context") {
326
+ out.context = value();
327
+ } else if (flag === "--store") {
328
+ out.store = value();
329
+ } else if (flag === "--json") {
330
+ out.json = true;
331
+ } else {
332
+ throw new IndexUsageError(`${command}: unknown argument '${raw}'`);
333
+ }
334
+ }
335
+ if (out.anonymous && out.substrate !== "gcp") throw new IndexUsageError(`${command}: --anonymous is for gcp against an emulator`);
336
+ if (out.anonymous && out.endpoint === undefined) throw new IndexUsageError(`${command}: --anonymous needs --endpoint (an emulator); a real project always takes a token`);
337
+ return out;
338
+ }
339
+
340
+ export type Env = Readonly<Record<string, string | undefined>>;
341
+
342
+ function isLoopback(endpoint: string): boolean {
343
+ try {
344
+ const h = new URL(endpoint).hostname.replace(/^\[|\]$/g, "");
345
+ return h === "localhost" || h === "::1" || /^127\./.test(h);
346
+ } catch {
347
+ return false;
348
+ }
349
+ }
350
+
351
+ export interface TargetDeps {
352
+ env: Env;
353
+ cwd: string;
354
+ home: string;
355
+ readFile?: (path: string) => string;
356
+ command?: string;
357
+ }
358
+
359
+ /** The run's scope and target, from the flags and the variables the module comment lists. */
360
+ export function scopeAndTarget(args: IndexArgs, deps: TargetDeps): { scope: CloudScope; target: SubstrateTarget } {
361
+ const { env } = deps;
362
+ const command = deps.command ?? "chant index";
363
+ const read = deps.readFile ?? ((p: string) => readFileSync(p, "utf8"));
364
+ const endpoint = args.endpoint ?? (args.substrate === "aws" ? env.AWS_ENDPOINT_URL || undefined : undefined);
365
+ if (args.insecureSkipVerify && (endpoint === undefined || !isLoopback(endpoint))) {
366
+ throw new ListerConfigError("--insecure-skip-verify is only for an emulator on a loopback endpoint");
367
+ }
368
+ const tls: TlsOptions | undefined =
369
+ args.ca || args.insecureSkipVerify ? { ...(args.ca ? { ca: read(resolve(deps.cwd, args.ca)) } : {}), ...(args.insecureSkipVerify ? { insecureSkipVerify: true } : {}) } : undefined;
370
+ const base = {
371
+ locations: args.locations && args.locations.length > 0 ? args.locations : ("*" as const),
372
+ types: args.types && args.types.length > 0 ? args.types : ("*" as const),
373
+ ...(Object.keys(args.tags).length > 0 ? { tagFilter: args.tags } : {}),
374
+ };
375
+ const needScope = (what: string): string => {
376
+ if (!args.scopeId) throw new ListerConfigError(`${command} ${args.substrate} needs ${what}`);
377
+ return args.scopeId;
378
+ };
379
+ switch (args.substrate) {
380
+ case "aws": {
381
+ const region = env.AWS_REGION || env.AWS_DEFAULT_REGION;
382
+ const locations = base.locations === "*" && region ? [region] : base.locations;
383
+ const credentials =
384
+ env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY
385
+ ? { accessKeyId: env.AWS_ACCESS_KEY_ID, secretAccessKey: env.AWS_SECRET_ACCESS_KEY, ...(env.AWS_SESSION_TOKEN ? { sessionToken: env.AWS_SESSION_TOKEN } : {}) }
386
+ : undefined;
387
+ return {
388
+ scope: { substrate: "aws", scopeId: needScope("--account <id>"), ...base, locations },
389
+ target: { substrate: "aws", aws: { ...(endpoint !== undefined ? { endpoint } : {}), ...(credentials ? { credentials } : {}), ...(tls ? { tls } : {}) } },
390
+ };
391
+ }
392
+ case "azure": {
393
+ const token = env.CHANT_AZURE_TOKEN || undefined;
394
+ return {
395
+ scope: { substrate: "azure", scopeId: needScope("--subscription <id>"), ...base },
396
+ target: { substrate: "azure", azure: { ...(endpoint !== undefined ? { endpoint } : {}), ...(token !== undefined ? { token } : {}), ...(tls ? { tls } : {}) } },
397
+ };
398
+ }
399
+ case "gcp": {
400
+ const token = args.anonymous ? null : env.CHANT_GCP_TOKEN || undefined;
401
+ return {
402
+ scope: { substrate: "gcp", scopeId: needScope("--project <id>"), ...base },
403
+ target: { substrate: "gcp", gcp: { ...(endpoint !== undefined ? { endpoint } : {}), ...(token !== undefined ? { token } : {}), ...(tls ? { tls } : {}) } },
404
+ };
405
+ }
406
+ case "kubernetes": {
407
+ const path = args.kubeconfig
408
+ ? resolve(deps.cwd, args.kubeconfig)
409
+ : env.KUBECONFIG
410
+ ? env.KUBECONFIG.split(delimiter).filter(Boolean)[0]
411
+ : join(deps.home, ".kube", "config");
412
+ if (!path) throw new ListerConfigError(`${command} kubernetes needs a kubeconfig (--kubeconfig or KUBECONFIG)`);
413
+ let text: string;
414
+ try {
415
+ text = read(path);
416
+ } catch (e) {
417
+ throw new ListerConfigError(`${command} kubernetes could not read the kubeconfig ${path}: ${(e as Error).message}`);
418
+ }
419
+ const kube = kubeTargetFromKubeconfig(text, { ...(args.context ? { context: args.context } : {}), baseDir: dirname(path) });
420
+ const server = endpoint ?? kube.server;
421
+ const kubeTls = tls ? { ...kube.tls, ...tls } : kube.tls;
422
+ return {
423
+ scope: { substrate: "kubernetes", scopeId: args.scopeId ?? kube.clusterName, ...base },
424
+ target: { substrate: "kubernetes", kubernetes: { server, ...(kube.token ? { token: kube.token } : {}), ...(kubeTls ? { tls: kubeTls } : {}) } },
425
+ };
426
+ }
427
+ }
428
+ }
429
+
430
+ // ── The store ───────────────────────────────────────────────────────────
431
+
432
+ /** Where the run writes, before any store is built (so it can be tested without one). */
433
+ export type StorePlan =
434
+ | { kind: "user"; dir: string }
435
+ | { kind: "project"; projectDir: string }
436
+ | { kind: "spec"; spec: string; configured: Record<string, unknown> & { store: string }; env: Record<string, string | undefined> };
437
+
438
+ /**
439
+ * behold#1025 Q4: the per-user store's root, chant's per-user data directory.
440
+ * `CHANT_INDEX_DIR` names the store's `index/` directory; else
441
+ * `$XDG_DATA_HOME/chant`; else `~/.local/share/chant`.
442
+ */
443
+ export function chantUserStoreDir(env: Env = process.env, home: string = homedir()): string {
444
+ const indexDir = env.CHANT_INDEX_DIR?.trim();
445
+ if (indexDir) {
446
+ if (basename(indexDir) !== "index") {
447
+ throw new IndexUsageError(`CHANT_INDEX_DIR (${indexDir}) must end in /index: the local store keeps index versions under <store>/index`);
448
+ }
449
+ return dirname(resolve(indexDir));
450
+ }
451
+ const xdg = env.XDG_DATA_HOME?.trim();
452
+ return join(xdg && isAbsolute(xdg) ? xdg : join(home, ".local", "share"), "chant");
453
+ }
454
+
455
+ const PROJECT_FILES = ["chant.config.ts", "chant.config.json"];
456
+
457
+ /** The chant project the working directory is in, if any: the nearest directory with a chant config. */
458
+ export function findChantProject(cwd: string, exists: (p: string) => boolean = existsSync): string | undefined {
459
+ let dir = resolve(cwd);
460
+ for (;;) {
461
+ if (PROJECT_FILES.some((f) => exists(join(dir, f)))) return dir;
462
+ const up = dirname(dir);
463
+ if (up === dir) return undefined;
464
+ dir = up;
465
+ }
466
+ }
467
+
468
+ /**
469
+ * The store a run writes to. `--store` takes ./snapshot-store.ts's kinds as a
470
+ * spec: `local` (`.chant/store`, or `CHANT_SNAPSHOT_STORE_DIR`),
471
+ * `local:<dir>`, `git-ref`, `git-ref:<ref>`, `s3` (from `CHANT_SNAPSHOT_S3_*`),
472
+ * `s3://<bucket>[/<prefix>]`, `none`. The read-only `orphan-branch` store is
473
+ * refused. With no `--store`: the project's store, else `defaultStoreDir`.
474
+ */
475
+ export function planIndexStore(o: { store?: string; cwd: string; env: Env; defaultStoreDir: () => string; exists?: (p: string) => boolean; command?: string }): StorePlan {
476
+ const command = o.command ?? "chant index";
477
+ const env: Record<string, string | undefined> = { ...o.env };
478
+ if (o.store === undefined) {
479
+ const project = findChantProject(o.cwd, o.exists);
480
+ if (project) return { kind: "project", projectDir: project };
481
+ return { kind: "user", dir: o.defaultStoreDir() };
482
+ }
483
+ const spec = o.store.trim();
484
+ const colon = spec.indexOf(":");
485
+ const head = spec.startsWith("s3://") ? "s3" : colon > 0 ? spec.slice(0, colon) : spec;
486
+ const tail = spec.startsWith("s3://") ? spec.slice("s3://".length) : colon > 0 ? spec.slice(colon + 1) : undefined;
487
+ env.CHANT_SNAPSHOT_STORE = head;
488
+ switch (head) {
489
+ case "local": {
490
+ if (tail !== undefined) {
491
+ if (!tail) throw new IndexUsageError(`${command}: --store local:<dir> needs a directory`);
492
+ env.CHANT_SNAPSHOT_STORE_DIR = isAbsolute(tail) ? tail : resolve(o.cwd, tail);
493
+ }
494
+ return { kind: "spec", spec, configured: { store: "local" }, env };
495
+ }
496
+ case "git-ref":
497
+ return { kind: "spec", spec, configured: { store: "git-ref", readOrphanBranch: false, ...(tail ? { ref: tail } : {}) }, env };
498
+ case "s3": {
499
+ if (tail !== undefined) {
500
+ const [bucket, ...prefix] = tail.split("/");
501
+ if (!bucket) throw new IndexUsageError(`${command}: --store s3://<bucket>[/<prefix>] needs a bucket`);
502
+ env.CHANT_SNAPSHOT_S3_BUCKET = bucket;
503
+ const p = prefix.join("/").replace(/\/+$/, "");
504
+ if (p) env.CHANT_SNAPSHOT_S3_PREFIX = p;
505
+ else delete env.CHANT_SNAPSHOT_S3_PREFIX;
506
+ }
507
+ return { kind: "spec", spec, configured: { store: "s3" }, env };
508
+ }
509
+ case "none":
510
+ return { kind: "spec", spec, configured: { store: "none" }, env };
511
+ case "orphan-branch":
512
+ throw new IndexUsageError(`${command}: the orphan-branch store is read-only; pass local, git-ref, s3 or none`);
513
+ default:
514
+ throw new IndexUsageError(`${command}: --store '${spec}' is not a store spec (local, local:<dir>, git-ref, git-ref:<ref>, s3, s3://<bucket>[/<prefix>], none)`);
515
+ }
516
+ }
517
+
518
+ /** Build the planned store. */
519
+ export async function openIndexStore(plan: StorePlan, cwd: string): Promise<IndexStore> {
520
+ switch (plan.kind) {
521
+ case "user":
522
+ return createSnapshotStore({ store: "local", dir: plan.dir }, { cwd });
523
+ case "project":
524
+ return resolveSnapshotStore({ cwd: plan.projectDir });
525
+ case "spec":
526
+ return createSnapshotStore(snapshotStoreConfig(plan.configured, plan.env), { cwd, env: plan.env });
527
+ }
528
+ }
529
+
530
+ /** The substrate's lexicon plugin, or a note saying why there is none. */
531
+ export async function substrateLexicons(substrate: Substrate): Promise<{ lexicons: IndexLexicon[]; note?: string }> {
532
+ const name = SUBSTRATE_LEXICON[substrate];
533
+ const pkg = `@intentius/chant-lexicon-${name}`;
534
+ let plugin: IndexLexicon | undefined;
535
+ try {
536
+ const { loadPlugin } = await import("../cli/plugins");
537
+ plugin = (await loadPlugin(name)) as IndexLexicon;
538
+ } catch {
539
+ plugin = undefined;
540
+ }
541
+ if (!plugin || typeof plugin.name !== "string") {
542
+ return {
543
+ lexicons: [],
544
+ note: `${pkg} is not installed, so ${substrate} objects are kept as nodes of unknown kind and get no derived edges; install it to type them`,
545
+ };
546
+ }
547
+ if (!plugin.listedTypes) {
548
+ return { lexicons: [plugin], note: `${pkg} has no listedTypes (chant#4521), so ${substrate} objects are kept as nodes of unknown kind` };
549
+ }
550
+ return { lexicons: [plugin] };
551
+ }
552
+
553
+ // ── The command ─────────────────────────────────────────────────────────
554
+
555
+ export interface IndexSummary {
556
+ substrate: Substrate;
557
+ scopeId: string;
558
+ scopeKey: string;
559
+ observedAt: string;
560
+ digest: string;
561
+ store: { kind: string; where: string };
562
+ written: boolean;
563
+ version?: string;
564
+ path?: string;
565
+ reason?: string;
566
+ nodes: number;
567
+ typed: number;
568
+ unmapped: number;
569
+ derivedEdges: number;
570
+ coverage: { listed: number; notObserved: number };
571
+ notes: string[];
572
+ }
573
+
574
+ export interface RunCloudIndexOptions extends IndexCloudDeps {
575
+ /** The command name in messages: `chant index` (default) or `behold index`. */
576
+ command?: string;
577
+ /** The per-user store root when there is no project and no `--store`. Default {@link chantUserStoreDir}. */
578
+ defaultStoreDir?: () => string;
579
+ /** How the usage text names that default. */
580
+ defaultStoreText?: string;
581
+ cwd?: string;
582
+ env?: Env;
583
+ home?: string;
584
+ stdout?: (s: string) => void;
585
+ stderr?: (s: string) => void;
586
+ /** The substrate's lexicons; tests pass a table. */
587
+ lexicons?: (substrate: Substrate) => Promise<{ lexicons: IndexLexicon[]; note?: string }>;
588
+ /** Builds the store; tests pass a fake. */
589
+ openStore?: (plan: StorePlan, cwd: string) => Promise<IndexStore>;
590
+ readFile?: (path: string) => string;
591
+ exists?: (path: string) => boolean;
592
+ /** The caller's version, for the stamp's `source.version`. Default chant's. */
593
+ version?: string;
594
+ }
595
+
596
+ function summarize(doc: IndexDocument): Pick<IndexSummary, "nodes" | "typed" | "unmapped" | "derivedEdges" | "coverage"> {
597
+ const nodes = doc.graph.nodes;
598
+ const unmapped = nodes.filter((n) => n.unmappedKind === true).length;
599
+ const listed = doc.coverage.filter((c) => c.verdict === "listed").length;
600
+ return {
601
+ nodes: nodes.length,
602
+ typed: nodes.length - unmapped,
603
+ unmapped,
604
+ derivedEdges: doc.graph.edges.filter((e) => e.origin === "derived").length,
605
+ coverage: { listed, notObserved: doc.coverage.length - listed },
606
+ };
607
+ }
608
+
609
+ /**
610
+ * `chant index <substrate> …`, and `behold index` through it. Returns the
611
+ * exit code: 0 written (or a store that keeps nothing), 1 a read or write
612
+ * failed, 2 refused (usage, an action flag, a credential rule, a read-only
613
+ * store).
614
+ */
615
+ export async function runCloudIndex(argv: readonly string[], opts: RunCloudIndexOptions = {}): Promise<number> {
616
+ const command = opts.command ?? "chant index";
617
+ const cwd = opts.cwd ?? process.cwd();
618
+ const env = opts.env ?? process.env;
619
+ const home = opts.home ?? homedir();
620
+ const out = opts.stdout ?? ((s: string) => void process.stdout.write(s));
621
+ const err = opts.stderr ?? ((s: string) => void process.stderr.write(s));
622
+ const usage = indexUsage(command, opts.defaultStoreText);
623
+
624
+ if (argv.includes("-h") || argv.includes("--help")) {
625
+ out(usage);
626
+ return 0;
627
+ }
628
+
629
+ let args: IndexArgs;
630
+ let plan: StorePlan;
631
+ try {
632
+ args = parseIndexArgs(argv, command);
633
+ plan = planIndexStore({
634
+ store: args.store,
635
+ cwd,
636
+ env,
637
+ defaultStoreDir: opts.defaultStoreDir ?? (() => chantUserStoreDir(env, home)),
638
+ command,
639
+ ...(opts.exists ? { exists: opts.exists } : {}),
640
+ });
641
+ } catch (e) {
642
+ if (e instanceof IndexUsageError) {
643
+ err(`${e.message}\n`);
644
+ if (!e.actionFlag) err(`\n${usage}`);
645
+ return 2;
646
+ }
647
+ throw e;
648
+ }
649
+
650
+ let scope: CloudScope;
651
+ let target: SubstrateTarget;
652
+ try {
653
+ ({ scope, target } = scopeAndTarget(args, { env, cwd, home, command, ...(opts.readFile ? { readFile: opts.readFile } : {}) }));
654
+ } catch (e) {
655
+ if (e instanceof ListerConfigError) {
656
+ err(`${e.message}. Nothing was listed and nothing was written.\n`);
657
+ return 2;
658
+ }
659
+ throw e;
660
+ }
661
+
662
+ let store: IndexStore;
663
+ try {
664
+ store = await (opts.openStore ?? openIndexStore)(plan, cwd);
665
+ } catch (e) {
666
+ err(`${command}: the index store could not be opened: ${(e as Error).message}. Nothing was listed and nothing was written.\n`);
667
+ return 2;
668
+ }
669
+ if (!store.writable && store.kind !== "none") {
670
+ err(`${command}: the store ${store.where} is read-only. Nothing was listed and nothing was written.\n`);
671
+ return 2;
672
+ }
673
+
674
+ const lex = await (opts.lexicons ?? substrateLexicons)(args.substrate);
675
+ let result: IndexCloudResult;
676
+ try {
677
+ result = await indexCloud(
678
+ { scope, target, store, lexicons: lex.lexicons, ...(opts.version ? { version: opts.version } : {}) },
679
+ { ...(opts.list ? { list: opts.list } : {}), ...(opts.listOptions ? { listOptions: opts.listOptions } : {}) },
680
+ );
681
+ } catch (e) {
682
+ if (e instanceof ListerConfigError || e instanceof OriginRefused || e instanceof MutatingCallRefused) {
683
+ err(`${e.message}. Nothing was written.\n`);
684
+ return 2;
685
+ }
686
+ if (e instanceof IndexWriteError) {
687
+ err(`${command}: the index version could not be written to ${store.where}: ${e.message}\n`);
688
+ return 1;
689
+ }
690
+ err(`${command}: ${(e as Error).message}. Nothing was written.\n`);
691
+ return 1;
692
+ }
693
+ const { doc, write } = result;
694
+ const notes: string[] = [];
695
+ if (lex.note) notes.push(lex.note);
696
+ for (const n of doc.notes ?? []) notes.push(n.message);
697
+
698
+ const version = write.path ? basename(write.path) : undefined;
699
+ const summary: IndexSummary = {
700
+ substrate: args.substrate,
701
+ scopeId: scope.scopeId,
702
+ scopeKey: doc.stamp.scopeKey,
703
+ observedAt: doc.stamp.observedAt,
704
+ digest: doc.stamp.digest,
705
+ store: { kind: store.kind, where: store.where },
706
+ written: write.written,
707
+ ...(version ? { version } : {}),
708
+ ...(write.path ? { path: write.path } : {}),
709
+ ...(write.reason ? { reason: write.reason } : {}),
710
+ ...summarize(doc),
711
+ notes,
712
+ };
713
+
714
+ if (args.json) {
715
+ out(`${JSON.stringify(summary, null, 2)}\n`);
716
+ } else {
717
+ out(`${args.substrate} ${scope.scopeId}: ${summary.nodes} nodes (${summary.typed} typed, ${summary.unmapped} of unknown kind), ${summary.derivedEdges} derived edges\n`);
718
+ out(`coverage: ${summary.coverage.listed} (type, location) listed, ${summary.coverage.notObserved} not observed\n`);
719
+ for (const n of notes) out(` note: ${n}\n`);
720
+ if (write.written) out(`${command}: wrote ${version} under ${summary.scopeKey} in ${store.where}\n`);
721
+ else out(`${command}: wrote nothing to ${store.where}: ${write.reason ?? "the store kept nothing"}\n`);
722
+ }
723
+ // An unchanged re-read at the same second, or a store that keeps nothing, is not a failure.
724
+ return 0;
725
+ }
726
+
727
+ /** A store write that threw, told apart from a failed listing. */
728
+ export class IndexWriteError extends Error {
729
+ constructor(message: string) {
730
+ super(message);
731
+ this.name = "IndexWriteError";
732
+ }
733
+ }
734
+
735
+ export { listCloud, ListerConfigError, MutatingCallRefused, OriginRefused, READ_OPERATIONS } from "../cloud-lister/index";
736
+ export type { CloudScope, ListingResult, ListOptions, Substrate, SubstrateTarget } from "../cloud-lister/index";