@intentius/chant 0.13.1 → 0.15.0

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 (450) hide show
  1. package/dist/audit/catalog.d.ts +45 -5
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/proof.d.ts +3 -0
  4. package/dist/audit/proof.d.ts.map +1 -1
  5. package/dist/audit/report-model.d.ts +4 -1
  6. package/dist/audit/report-model.d.ts.map +1 -1
  7. package/dist/audit/report.d.ts +3 -0
  8. package/dist/audit/report.d.ts.map +1 -1
  9. package/dist/audit/rules-doc.d.ts +8 -2
  10. package/dist/audit/rules-doc.d.ts.map +1 -1
  11. package/dist/cli/commands/audit.d.ts.map +1 -1
  12. package/dist/cli/commands/doctor.d.ts.map +1 -1
  13. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
  14. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
  15. package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
  16. package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
  17. package/dist/cli/commands/lint.d.ts.map +1 -1
  18. package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
  19. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
  20. package/dist/cli/handlers/build.d.ts.map +1 -1
  21. package/dist/cli/handlers/components.d.ts +39 -0
  22. package/dist/cli/handlers/components.d.ts.map +1 -0
  23. package/dist/cli/handlers/dev.d.ts +3 -0
  24. package/dist/cli/handlers/dev.d.ts.map +1 -1
  25. package/dist/cli/handlers/graph.d.ts +4 -2
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/misc.d.ts.map +1 -1
  28. package/dist/cli/handlers/run.d.ts +49 -0
  29. package/dist/cli/handlers/run.d.ts.map +1 -1
  30. package/dist/cli/main.d.ts.map +1 -1
  31. package/dist/cli/registry.d.ts +35 -0
  32. package/dist/cli/registry.d.ts.map +1 -1
  33. package/dist/codegen/fetch.d.ts +22 -0
  34. package/dist/codegen/fetch.d.ts.map +1 -1
  35. package/dist/codegen/lexicon-regen.d.ts +110 -0
  36. package/dist/codegen/lexicon-regen.d.ts.map +1 -0
  37. package/dist/codegen/pinned-upgrade.d.ts +153 -0
  38. package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
  39. package/dist/codegen/rolling-upgrade.d.ts +138 -0
  40. package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
  41. package/dist/codegen/surface-snapshot.d.ts +173 -0
  42. package/dist/codegen/surface-snapshot.d.ts.map +1 -0
  43. package/dist/codegen/version-bump.d.ts +21 -0
  44. package/dist/codegen/version-bump.d.ts.map +1 -0
  45. package/dist/components/auto-release.d.ts +93 -0
  46. package/dist/components/auto-release.d.ts.map +1 -0
  47. package/dist/components/builders.d.ts +37 -0
  48. package/dist/components/builders.d.ts.map +1 -0
  49. package/dist/components/capability-plugin-loader.d.ts +111 -0
  50. package/dist/components/capability-plugin-loader.d.ts.map +1 -0
  51. package/dist/components/capability-plugin-schema.d.ts +24 -0
  52. package/dist/components/capability-plugin-schema.d.ts.map +1 -0
  53. package/dist/components/capability-plugin.d.ts +85 -0
  54. package/dist/components/capability-plugin.d.ts.map +1 -0
  55. package/dist/components/capability.d.ts +89 -0
  56. package/dist/components/capability.d.ts.map +1 -0
  57. package/dist/components/cli-support.d.ts +204 -0
  58. package/dist/components/cli-support.d.ts.map +1 -0
  59. package/dist/components/component.d.ts +179 -0
  60. package/dist/components/component.d.ts.map +1 -0
  61. package/dist/components/config-defaults.d.ts +41 -0
  62. package/dist/components/config-defaults.d.ts.map +1 -0
  63. package/dist/components/discover.d.ts +60 -0
  64. package/dist/components/discover.d.ts.map +1 -0
  65. package/dist/components/driver-output.d.ts +20 -0
  66. package/dist/components/driver-output.d.ts.map +1 -0
  67. package/dist/components/driver.d.ts +209 -0
  68. package/dist/components/driver.d.ts.map +1 -0
  69. package/dist/components/index.d.ts +22 -0
  70. package/dist/components/index.d.ts.map +1 -0
  71. package/dist/components/manifest-persistence.d.ts +79 -0
  72. package/dist/components/manifest-persistence.d.ts.map +1 -0
  73. package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
  74. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
  75. package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
  76. package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
  77. package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
  78. package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
  79. package/dist/components/pilots/lambda.pilot.d.ts +35 -0
  80. package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
  81. package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
  82. package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
  83. package/dist/components/pilots/project.d.ts +13 -0
  84. package/dist/components/pilots/project.d.ts.map +1 -0
  85. package/dist/components/presets/ecs-fargate.d.ts +59 -0
  86. package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
  87. package/dist/components/presets/index.d.ts +29 -0
  88. package/dist/components/presets/index.d.ts.map +1 -0
  89. package/dist/components/presets/lambda.d.ts +35 -0
  90. package/dist/components/presets/lambda.d.ts.map +1 -0
  91. package/dist/components/presets/single-host-compose.d.ts +43 -0
  92. package/dist/components/presets/single-host-compose.d.ts.map +1 -0
  93. package/dist/components/registry.d.ts +29 -0
  94. package/dist/components/registry.d.ts.map +1 -0
  95. package/dist/components/starter-plugin.d.ts +51 -0
  96. package/dist/components/starter-plugin.d.ts.map +1 -0
  97. package/dist/components/temporal-codegen-loader.d.ts +27 -0
  98. package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
  99. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
  100. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
  101. package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
  102. package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
  103. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
  104. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
  105. package/dist/components/verbs/bom-writer.d.ts +155 -0
  106. package/dist/components/verbs/bom-writer.d.ts.map +1 -0
  107. package/dist/components/verbs/build-archive.d.ts +205 -0
  108. package/dist/components/verbs/build-archive.d.ts.map +1 -0
  109. package/dist/components/verbs/build.d.ts +150 -0
  110. package/dist/components/verbs/build.d.ts.map +1 -0
  111. package/dist/components/verbs/cloud-executor.d.ts +88 -0
  112. package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
  113. package/dist/components/verbs/component-bom.d.ts +103 -0
  114. package/dist/components/verbs/component-bom.d.ts.map +1 -0
  115. package/dist/components/verbs/index.d.ts +49 -0
  116. package/dist/components/verbs/index.d.ts.map +1 -0
  117. package/dist/components/verbs/license-policy.d.ts +56 -0
  118. package/dist/components/verbs/license-policy.d.ts.map +1 -0
  119. package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
  120. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
  121. package/dist/components/verbs/process-runner.d.ts +64 -0
  122. package/dist/components/verbs/process-runner.d.ts.map +1 -0
  123. package/dist/components/verbs/reproducibility.d.ts +80 -0
  124. package/dist/components/verbs/reproducibility.d.ts.map +1 -0
  125. package/dist/components/verbs/sbom-generator.d.ts +157 -0
  126. package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
  127. package/dist/components/verbs/sbom.d.ts +79 -0
  128. package/dist/components/verbs/sbom.d.ts.map +1 -0
  129. package/dist/components/verbs/shell.d.ts +35 -0
  130. package/dist/components/verbs/shell.d.ts.map +1 -0
  131. package/dist/components/verbs/sign.d.ts +222 -0
  132. package/dist/components/verbs/sign.d.ts.map +1 -0
  133. package/dist/components/verbs/stub.d.ts +18 -0
  134. package/dist/components/verbs/stub.d.ts.map +1 -0
  135. package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
  136. package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
  137. package/dist/components/verbs/verify.d.ts +106 -0
  138. package/dist/components/verbs/verify.d.ts.map +1 -0
  139. package/dist/components/verbs/vex.d.ts +65 -0
  140. package/dist/components/verbs/vex.d.ts.map +1 -0
  141. package/dist/components/verbs/vuln-gate.d.ts +91 -0
  142. package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
  143. package/dist/components/verbs/vuln-scan.d.ts +116 -0
  144. package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
  145. package/dist/components/verbs/wait-verify.d.ts +85 -0
  146. package/dist/components/verbs/wait-verify.d.ts.map +1 -0
  147. package/dist/config.d.ts +205 -0
  148. package/dist/config.d.ts.map +1 -1
  149. package/dist/index.d.ts +4 -0
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/lexicon.d.ts +78 -0
  152. package/dist/lexicon.d.ts.map +1 -1
  153. package/dist/lifecycle/build-ledger-store.d.ts +121 -0
  154. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
  155. package/dist/lifecycle/build-ledger.d.ts +225 -0
  156. package/dist/lifecycle/build-ledger.d.ts.map +1 -0
  157. package/dist/lifecycle/git.d.ts +84 -0
  158. package/dist/lifecycle/git.d.ts.map +1 -1
  159. package/dist/lifecycle/index.d.ts +5 -0
  160. package/dist/lifecycle/index.d.ts.map +1 -1
  161. package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
  162. package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
  163. package/dist/lifecycle/release-ledger.d.ts +122 -0
  164. package/dist/lifecycle/release-ledger.d.ts.map +1 -0
  165. package/dist/lifecycle/status.d.ts +150 -0
  166. package/dist/lifecycle/status.d.ts.map +1 -0
  167. package/dist/lint/component-checks.d.ts +95 -0
  168. package/dist/lint/component-checks.d.ts.map +1 -0
  169. package/dist/lint/engine.d.ts +23 -0
  170. package/dist/lint/engine.d.ts.map +1 -1
  171. package/dist/lint/presets/strict.json +8 -1
  172. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
  173. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
  174. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
  175. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
  176. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
  177. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
  178. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
  179. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
  180. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
  181. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
  182. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
  183. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
  184. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
  185. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
  186. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
  187. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
  188. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
  189. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
  190. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
  191. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
  192. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
  193. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
  194. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
  195. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
  196. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
  197. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
  198. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
  199. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
  200. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
  201. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
  202. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
  203. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
  204. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
  205. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
  206. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
  207. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
  208. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
  209. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
  210. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
  211. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
  212. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
  213. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
  214. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
  215. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
  216. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
  217. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
  218. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
  219. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
  220. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
  221. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
  222. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
  223. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
  224. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
  225. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
  226. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
  227. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
  228. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
  229. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
  230. package/dist/lint/rules/comp/index.d.ts +18 -0
  231. package/dist/lint/rules/comp/index.d.ts.map +1 -0
  232. package/dist/lint/rules/comp/support.d.ts +71 -0
  233. package/dist/lint/rules/comp/support.d.ts.map +1 -0
  234. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  235. package/dist/op/activity-registry.d.ts +11 -6
  236. package/dist/op/activity-registry.d.ts.map +1 -1
  237. package/dist/op/activity-runtime.d.ts +24 -0
  238. package/dist/op/activity-runtime.d.ts.map +1 -0
  239. package/dist/op/builders.d.ts +56 -0
  240. package/dist/op/builders.d.ts.map +1 -1
  241. package/dist/op/index.d.ts +2 -1
  242. package/dist/op/index.d.ts.map +1 -1
  243. package/dist/ownership.d.ts +20 -14
  244. package/dist/ownership.d.ts.map +1 -1
  245. package/package.json +14 -1
  246. package/src/audit/catalog.test.ts +74 -22
  247. package/src/audit/catalog.ts +74 -471
  248. package/src/audit/proof.ts +4 -2
  249. package/src/audit/report-html.test.ts +14 -7
  250. package/src/audit/report-model.ts +20 -9
  251. package/src/audit/report.test.ts +36 -13
  252. package/src/audit/report.ts +2 -0
  253. package/src/audit/rules-doc.test.ts +8 -6
  254. package/src/audit/rules-doc.ts +13 -5
  255. package/src/cli/commands/audit.ts +23 -18
  256. package/src/cli/commands/component-lint.test.ts +158 -0
  257. package/src/cli/commands/doctor.test.ts +116 -2
  258. package/src/cli/commands/doctor.ts +46 -0
  259. package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
  260. package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
  261. package/src/cli/commands/lexicon-surface-diff.ts +185 -0
  262. package/src/cli/commands/lint.ts +142 -1
  263. package/src/cli/commands/pinned-upgrade.ts +204 -0
  264. package/src/cli/handlers/build.ts +58 -1
  265. package/src/cli/handlers/components.test.ts +504 -0
  266. package/src/cli/handlers/components.ts +404 -0
  267. package/src/cli/handlers/dev.ts +60 -1
  268. package/src/cli/handlers/graph.ts +47 -2
  269. package/src/cli/handlers/misc.ts +45 -1
  270. package/src/cli/handlers/run.test.ts +967 -3
  271. package/src/cli/handlers/run.ts +618 -11
  272. package/src/cli/main.test.ts +66 -0
  273. package/src/cli/main.ts +105 -2
  274. package/src/cli/registry.ts +35 -0
  275. package/src/codegen/fetch.test.ts +84 -3
  276. package/src/codegen/fetch.ts +76 -2
  277. package/src/codegen/lexicon-regen.test.ts +298 -0
  278. package/src/codegen/lexicon-regen.ts +545 -0
  279. package/src/codegen/pinned-upgrade.test.ts +399 -0
  280. package/src/codegen/pinned-upgrade.ts +423 -0
  281. package/src/codegen/rolling-upgrade.test.ts +333 -0
  282. package/src/codegen/rolling-upgrade.ts +320 -0
  283. package/src/codegen/surface-snapshot.test.ts +461 -0
  284. package/src/codegen/surface-snapshot.ts +546 -0
  285. package/src/codegen/version-bump.test.ts +47 -0
  286. package/src/codegen/version-bump.ts +39 -0
  287. package/src/components/README.md +130 -0
  288. package/src/components/SPRAWL-VALIDATION.md +181 -0
  289. package/src/components/__fixtures__/alb-ecs-service.json +51 -0
  290. package/src/components/__fixtures__/dynamodb-infra.json +32 -0
  291. package/src/components/__fixtures__/emr-job-consumer.json +26 -0
  292. package/src/components/__fixtures__/jar-lib-producer.json +16 -0
  293. package/src/components/__fixtures__/lambda-image-processor.json +28 -0
  294. package/src/components/__fixtures__/neo4j-fanout.json +34 -0
  295. package/src/components/__fixtures__/single-host-compose.json +29 -0
  296. package/src/components/auto-release.test.ts +217 -0
  297. package/src/components/auto-release.ts +216 -0
  298. package/src/components/builders.test.ts +45 -0
  299. package/src/components/builders.ts +71 -0
  300. package/src/components/capability-plugin-loader.ts +218 -0
  301. package/src/components/capability-plugin-schema.ts +56 -0
  302. package/src/components/capability-plugin.test.ts +235 -0
  303. package/src/components/capability-plugin.ts +108 -0
  304. package/src/components/capability.ts +117 -0
  305. package/src/components/cli-support.test.ts +579 -0
  306. package/src/components/cli-support.ts +481 -0
  307. package/src/components/component-schema.test.ts +265 -0
  308. package/src/components/component.schema.json +235 -0
  309. package/src/components/component.test.ts +251 -0
  310. package/src/components/component.ts +255 -0
  311. package/src/components/config-defaults.test.ts +263 -0
  312. package/src/components/config-defaults.ts +145 -0
  313. package/src/components/discover.test.ts +352 -0
  314. package/src/components/discover.ts +167 -0
  315. package/src/components/driver-output.ts +71 -0
  316. package/src/components/driver.test.ts +638 -0
  317. package/src/components/driver.ts +690 -0
  318. package/src/components/index.ts +113 -0
  319. package/src/components/manifest-persistence.test.ts +152 -0
  320. package/src/components/manifest-persistence.ts +164 -0
  321. package/src/components/pilots/README.md +33 -0
  322. package/src/components/pilots/alb-ecs.pilot.ts +63 -0
  323. package/src/components/pilots/dynamodb.pilot.ts +59 -0
  324. package/src/components/pilots/jar-emr.pilot.ts +69 -0
  325. package/src/components/pilots/lambda.pilot.ts +55 -0
  326. package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
  327. package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
  328. package/src/components/pilots/pilots.test.ts +126 -0
  329. package/src/components/pilots/project.ts +13 -0
  330. package/src/components/presets/comp007-reduction.test.ts +122 -0
  331. package/src/components/presets/ecs-fargate.test.ts +84 -0
  332. package/src/components/presets/ecs-fargate.ts +103 -0
  333. package/src/components/presets/index.ts +32 -0
  334. package/src/components/presets/lambda.test.ts +35 -0
  335. package/src/components/presets/lambda.ts +53 -0
  336. package/src/components/presets/single-host-compose.test.ts +65 -0
  337. package/src/components/presets/single-host-compose.ts +64 -0
  338. package/src/components/registry.test.ts +112 -0
  339. package/src/components/registry.ts +37 -0
  340. package/src/components/starter-plugin.ts +105 -0
  341. package/src/components/temporal-codegen-loader.ts +41 -0
  342. package/src/components/verbs/__fixtures__/package-lock.json +45 -0
  343. package/src/components/verbs/__fixtures__/pom.xml +37 -0
  344. package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
  345. package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
  346. package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
  347. package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
  348. package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
  349. package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
  350. package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
  351. package/src/components/verbs/bom-writer.test.ts +331 -0
  352. package/src/components/verbs/bom-writer.ts +386 -0
  353. package/src/components/verbs/build-archive.test.ts +251 -0
  354. package/src/components/verbs/build-archive.ts +296 -0
  355. package/src/components/verbs/build.test.ts +222 -0
  356. package/src/components/verbs/build.ts +252 -0
  357. package/src/components/verbs/cloud-executor.ts +181 -0
  358. package/src/components/verbs/component-bom.test.ts +219 -0
  359. package/src/components/verbs/component-bom.ts +189 -0
  360. package/src/components/verbs/index.ts +49 -0
  361. package/src/components/verbs/license-policy.ts +115 -0
  362. package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
  363. package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
  364. package/src/components/verbs/process-runner.test.ts +79 -0
  365. package/src/components/verbs/process-runner.ts +113 -0
  366. package/src/components/verbs/reproducibility.test.ts +24 -0
  367. package/src/components/verbs/reproducibility.ts +100 -0
  368. package/src/components/verbs/sbom-generator.test.ts +96 -0
  369. package/src/components/verbs/sbom-generator.ts +209 -0
  370. package/src/components/verbs/sbom.test.ts +184 -0
  371. package/src/components/verbs/sbom.ts +152 -0
  372. package/src/components/verbs/shell.test.ts +36 -0
  373. package/src/components/verbs/shell.ts +51 -0
  374. package/src/components/verbs/sign.test.ts +210 -0
  375. package/src/components/verbs/sign.ts +350 -0
  376. package/src/components/verbs/stub.ts +34 -0
  377. package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
  378. package/src/components/verbs/tool-sbom-generator.ts +192 -0
  379. package/src/components/verbs/verify.test.ts +159 -0
  380. package/src/components/verbs/verify.ts +179 -0
  381. package/src/components/verbs/vex.ts +182 -0
  382. package/src/components/verbs/vuln-gate.test.ts +201 -0
  383. package/src/components/verbs/vuln-gate.ts +170 -0
  384. package/src/components/verbs/vuln-scan.test.ts +145 -0
  385. package/src/components/verbs/vuln-scan.ts +266 -0
  386. package/src/components/verbs/wait-verify.test.ts +111 -0
  387. package/src/components/verbs/wait-verify.ts +171 -0
  388. package/src/config.test.ts +74 -1
  389. package/src/config.ts +219 -0
  390. package/src/index.ts +32 -0
  391. package/src/lexicon.ts +88 -0
  392. package/src/lifecycle/build-ledger-store.test.ts +217 -0
  393. package/src/lifecycle/build-ledger-store.ts +165 -0
  394. package/src/lifecycle/build-ledger.test.ts +349 -0
  395. package/src/lifecycle/build-ledger.ts +305 -0
  396. package/src/lifecycle/git.test.ts +118 -0
  397. package/src/lifecycle/git.ts +149 -14
  398. package/src/lifecycle/index.ts +5 -0
  399. package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
  400. package/src/lifecycle/oras-referrer-lookup.ts +110 -0
  401. package/src/lifecycle/release-ledger.test.ts +209 -0
  402. package/src/lifecycle/release-ledger.ts +185 -0
  403. package/src/lifecycle/status.test.ts +330 -0
  404. package/src/lifecycle/status.ts +278 -0
  405. package/src/lint/component-checks.ts +148 -0
  406. package/src/lint/config.test.ts +21 -0
  407. package/src/lint/engine.ts +11 -2
  408. package/src/lint/presets/relaxed.json +8 -1
  409. package/src/lint/presets/strict.json +8 -1
  410. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
  411. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
  412. package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
  413. package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
  414. package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
  415. package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
  416. package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
  417. package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
  418. package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
  419. package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
  420. package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
  421. package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
  422. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
  423. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
  424. package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
  425. package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
  426. package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
  427. package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
  428. package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
  429. package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
  430. package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
  431. package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
  432. package/src/lint/rules/comp/comp.test.ts +378 -0
  433. package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
  434. package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
  435. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
  436. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
  437. package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
  438. package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
  439. package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
  440. package/src/lint/rules/comp/index.ts +37 -0
  441. package/src/lint/rules/comp/support.ts +173 -0
  442. package/src/lsp/lexicon-providers.test.ts +55 -0
  443. package/src/lsp/lexicon-providers.ts +13 -3
  444. package/src/op/activity-registry.test.ts +38 -0
  445. package/src/op/activity-registry.ts +31 -12
  446. package/src/op/activity-runtime.ts +73 -0
  447. package/src/op/builders.ts +92 -0
  448. package/src/op/index.ts +3 -1
  449. package/src/ownership.test.ts +24 -26
  450. package/src/ownership.ts +26 -38
@@ -0,0 +1,404 @@
1
+ /**
2
+ * `chant components` handlers — release ledger + status surface (#568, epic
3
+ * #551 "Build & deploy observability").
4
+ *
5
+ * Two subcommands:
6
+ * - `chant components release record` — append one immutable release record
7
+ * to the `chant/lifecycle` orphan branch (../../lifecycle/release-ledger.ts).
8
+ * A deploy composition calls this (typically from a `Verify` phase, or the
9
+ * CI job that ran `chant build --components --generate <lexicon>`) once
10
+ * the artifact digest, git sha, and run id are known.
11
+ * - `chant components status [env]` — the status surface: joins the release
12
+ * ledger against live evidence (`lifecycle diff --live` + ownership,
13
+ * reused via `buildChangeSet`) by digest, and reports what's built vs
14
+ * what's deployed where, flagging unrecorded deploys and drift.
15
+ *
16
+ * `componentBom`/`build.reproducibility` (#614) resolve to real data as of
17
+ * #609: for every recorded digest in an environment's ledger, this handler
18
+ * looks up the persisted `BuildArchiveManifest` that produced it
19
+ * (`findBuildManifestByArtifactDigest`, ../../lifecycle/build-ledger-
20
+ * store.ts) and derives `buildsByDigest`/`componentBomByDigest` from it via
21
+ * `buildLedgerEntries`/`componentBomSummary` — the same derivation
22
+ * `build-ledger.test.ts` already exercises directly, now fed by a real
23
+ * manifest instead of a hand-built one. A digest with no persisted manifest
24
+ * (predates #609, or was recorded via `chant components release` alone with
25
+ * no corresponding build) simply has no entry in either map, so `build`/
26
+ * `componentBom` fall back to `null` exactly as before — no regression for
27
+ * ledgers with no persisted manifests at all.
28
+ */
29
+ import { resolve } from "node:path";
30
+ import { getHeadCommit, fetchLifecycle, pushLifecycle, StaleLifecycleBranchError } from "../../lifecycle/git";
31
+ import {
32
+ appendReleaseRecord,
33
+ readReleaseLedger,
34
+ listReleaseEnvironments,
35
+ InvalidReleaseRecordError,
36
+ } from "../../lifecycle/release-ledger";
37
+ import { reconcileStatus, liveEvidenceFromChangeSet, compareAcrossEnvironments } from "../../lifecycle/status";
38
+ import { buildChangeSet } from "../../lifecycle/change-set";
39
+ import { buildLedgerEntries, componentBomSummary, type BuildLedgerEntry } from "../../lifecycle/build-ledger";
40
+ import { findBuildManifestByArtifactDigest } from "../../lifecycle/build-ledger-store";
41
+ import type { ComponentBomSummary } from "../../lifecycle/build-ledger";
42
+ import { loadChantConfig } from "../../config";
43
+ import { build } from "../../build";
44
+ import { discoverComponents } from "../../components/discover";
45
+ import { formatError, formatWarning, formatSuccess, formatBold } from "../format";
46
+ import type { CommandContext } from "../registry";
47
+ import type { ResourceMetadata } from "../../lexicon";
48
+
49
+ /**
50
+ * chant components release <env> --component <name> --digest <sha256:...>
51
+ * [--git-sha <sha>] [--run-id <id>] [--actor <name>]
52
+ *
53
+ * `--git-sha` defaults to the current HEAD commit (`git rev-parse HEAD`);
54
+ * `--run-id` defaults to common CI run-id env vars
55
+ * (`GITHUB_RUN_ID`/`CI_PIPELINE_ID`) or a locally generated id; `--actor`
56
+ * defaults to common CI actor env vars
57
+ * (`GITHUB_ACTOR`/`GITLAB_USER_LOGIN`/`USER`) but must resolve to *something*
58
+ * — an unattributed release record defeats the point of a release ledger, so
59
+ * this is the one field with no silent fallback to a placeholder.
60
+ *
61
+ * The timestamp is always a real `new Date()` taken here, at record time —
62
+ * never threaded in from elsewhere and never mocked in production code, per
63
+ * #568: "the session cannot call Date.now() in some contexts; take the
64
+ * timestamp from the environment/CLI at record time."
65
+ */
66
+ export async function runComponentsReleaseRecord(ctx: CommandContext): Promise<number> {
67
+ const { args } = ctx;
68
+ const environment = args.extraPositional;
69
+ if (!environment) {
70
+ console.error(formatError({
71
+ message: "Environment is required: chant components release <env> --component <name> --digest <sha256:...>",
72
+ }));
73
+ return 1;
74
+ }
75
+
76
+ const component = args.component;
77
+ const digest = args.digest;
78
+ if (!component || !digest) {
79
+ console.error(formatError({
80
+ message: "--component and --digest are required",
81
+ hint: "chant components release <env> --component <name> --digest <sha256:...> [--git-sha <sha>] [--run-id <id>] [--actor <name>]",
82
+ }));
83
+ return 1;
84
+ }
85
+
86
+ const gitSha = args.gitSha ?? (await getHeadCommit().catch(() => undefined));
87
+ const runId = args.runId ?? process.env.GITHUB_RUN_ID ?? process.env.CI_PIPELINE_ID ?? `local-${Date.now()}`;
88
+ const actor = args.actor ?? process.env.GITHUB_ACTOR ?? process.env.GITLAB_USER_LOGIN ?? process.env.USER;
89
+
90
+ if (!gitSha) {
91
+ console.error(formatError({ message: "Could not resolve --git-sha (not in a git repo?) — pass it explicitly." }));
92
+ return 1;
93
+ }
94
+ if (!actor) {
95
+ console.error(formatError({
96
+ message: "Could not resolve --actor from the environment",
97
+ hint: "Pass --actor explicitly, or set GITHUB_ACTOR / GITLAB_USER_LOGIN / USER.",
98
+ }));
99
+ return 1;
100
+ }
101
+
102
+ const timestamp = new Date().toISOString();
103
+
104
+ try {
105
+ const { commit, record } = await appendReleaseRecord({
106
+ component,
107
+ env: environment,
108
+ digest,
109
+ gitSha,
110
+ runId,
111
+ timestamp,
112
+ actor,
113
+ });
114
+ await pushLifecycle();
115
+ if (args.json) {
116
+ console.log(JSON.stringify(record, null, 2));
117
+ } else {
118
+ console.error(formatSuccess(
119
+ `Recorded release: ${formatBold(component)}@${environment} -> ${digest} (commit ${commit.slice(0, 7)})`,
120
+ ));
121
+ }
122
+ return 0;
123
+ } catch (err) {
124
+ if (err instanceof InvalidReleaseRecordError) {
125
+ console.error(formatError({ message: err.message }));
126
+ return 1;
127
+ }
128
+ if (err instanceof StaleLifecycleBranchError) {
129
+ console.error(formatError({
130
+ message: err.message,
131
+ hint: `Pull and retry: \`git fetch origin chant/lifecycle:chant/lifecycle\` && \`chant components release ${environment} --component ${component} --digest ${digest}\`.`,
132
+ }));
133
+ return 1;
134
+ }
135
+ throw err;
136
+ }
137
+ }
138
+
139
+ /** One row of `chant components status` JSON output. */
140
+ interface StatusJsonRow {
141
+ component: string;
142
+ env: string;
143
+ recorded: {
144
+ digest: string;
145
+ gitSha: string;
146
+ runId: string;
147
+ timestamp: string;
148
+ actor: string;
149
+ } | null;
150
+ build: {
151
+ manifestDigest: string;
152
+ referrers: string[];
153
+ /** SBOM summary for this digest (#606), when one was generated and is discoverable — archive-carried or referrer-projected. `null` when neither source has one (e.g. the component opted out, or has no built artifact). */
154
+ sbom: { mediaType: string; packageCount?: number; generator?: string; source: string } | null;
155
+ /** This artifact's own honest, per-artifact reproducibility record (#614) — `null` when none is recorded. */
156
+ reproducibility: { basis: string; verifyBy?: string } | null;
157
+ } | null;
158
+ /**
159
+ * Component-level BOM aggregation summary (#614), when the recorded
160
+ * digest's build archive manifest is available — resolved from the
161
+ * persisted manifest store (#609, ../../lifecycle/build-ledger-store.ts)
162
+ * by digest. `null` when unavailable (no manifest was ever persisted for
163
+ * this digest — it predates #609, or was recorded via `chant components
164
+ * release` alone with no corresponding `chant build`/`run`) or when the
165
+ * manifest carries no BOM at all.
166
+ */
167
+ componentBom: {
168
+ leaves: Array<{ path: string; bomKind: string; subjectDigest?: string; mediaType: string; packageCount?: number; generator?: string }>;
169
+ totalPackageCount: number;
170
+ isAssembly: boolean;
171
+ } | null;
172
+ reconciliation: string;
173
+ detail: string;
174
+ }
175
+
176
+ /**
177
+ * chant components status [env] [--live] [--json] [--compare-to <env>]
178
+ *
179
+ * Answers "what's built" and "what's deployed where," joined by digest.
180
+ * Without `--live`, reports the release ledger alone (recorded vs unrecorded
181
+ * is meaningless without live evidence, so every recorded row reports
182
+ * `unknown` reconciliation — still useful as a pure ledger read). With
183
+ * `--live`, joins against `lifecycle diff --live` + ownership (reusing
184
+ * `buildChangeSet`, the same classification `lifecycle plan` already
185
+ * trusts) to flag unrecorded deploys and drift.
186
+ *
187
+ * Omitting `<env>` reports every environment that has release records.
188
+ * `--compare-to <env>` answers the single-query cross-environment question
189
+ * the epic names explicitly: "which build is in `<env>`, and is it the one
190
+ * tested in `<compare-to>`."
191
+ */
192
+ export async function runComponentsStatus(ctx: CommandContext): Promise<number> {
193
+ const { args, plugins, serializers } = ctx;
194
+ const requestedEnv = args.extraPositional;
195
+
196
+ await fetchLifecycle();
197
+
198
+ const environments = requestedEnv ? [requestedEnv] : await listReleaseEnvironments();
199
+ if (environments.length === 0) {
200
+ console.error(formatWarning({
201
+ message: requestedEnv
202
+ ? `No release records found for environment "${requestedEnv}"`
203
+ : "No release records found in any environment",
204
+ }));
205
+ return args.json ? (console.log(JSON.stringify([])), 0) : 0;
206
+ }
207
+
208
+ // Discover components (best-effort) so a live/owned-but-never-recorded
209
+ // component still gets a row, not just those that appear in the ledger.
210
+ const { config } = await loadChantConfig(resolve("."));
211
+ const discovery = await discoverComponents(resolve(args.src ?? config.sourceDir ?? "."));
212
+ const allComponents = [...discovery.components.keys()];
213
+
214
+ // Component -> live entity/resource name(s) it owns (#598), when declared
215
+ // explicitly via `Component.liveNames`. Components with no `liveNames`
216
+ // simply have no entry here, so `liveEvidenceFromChangeSet` falls back to
217
+ // the name == entity join — no regression for the pilot components.
218
+ const liveNameMapping = new Map<string, string[] | undefined>();
219
+ for (const [name, discovered] of discovery.components) {
220
+ if (discovered.component.liveNames?.length) {
221
+ liveNameMapping.set(name, discovered.component.liveNames);
222
+ }
223
+ }
224
+
225
+ const allRows: StatusJsonRow[] = [];
226
+ const ledgerByEnv = new Map<string, Awaited<ReturnType<typeof readReleaseLedger>>>();
227
+
228
+ for (const environment of environments) {
229
+ const ledger = await readReleaseLedger(environment);
230
+ ledgerByEnv.set(environment, ledger);
231
+ if (ledger.malformed > 0) {
232
+ console.error(formatWarning({ message: `${environment}: skipped ${ledger.malformed} malformed ledger line(s)` }));
233
+ }
234
+
235
+ let liveEvidence;
236
+ if (args.live) {
237
+ const targetSerializers = serializers;
238
+ const buildResult = await build(resolve(args.src ?? config.sourceDir ?? "."), targetSerializers);
239
+ const merged: { env: string; entries: import("../../lifecycle/change-set").ChangeSetEntry[] } = { env: environment, entries: [] };
240
+ for (const plugin of plugins) {
241
+ if (!plugin.describeResources) continue;
242
+ const declared = new Set<string>();
243
+ const entities = new Map<string, { entityType: string; props: Record<string, unknown> }>();
244
+ for (const [name, entity] of buildResult.entities) {
245
+ if (entity.lexicon === plugin.name) {
246
+ declared.add(name);
247
+ entities.set(name, {
248
+ entityType: entity.entityType,
249
+ props: ("props" in entity && entity.props != null ? entity.props : {}) as Record<string, unknown>,
250
+ });
251
+ }
252
+ }
253
+ let observedNow: Record<string, ResourceMetadata>;
254
+ try {
255
+ observedNow = await plugin.describeResources({ environment, buildOutput: "", entityNames: Array.from(declared), entities });
256
+ } catch (err) {
257
+ console.error(formatWarning({ message: `${plugin.name}: describeResources failed — ${err instanceof Error ? err.message : String(err)}` }));
258
+ continue;
259
+ }
260
+ const cs = buildChangeSet(environment, { declared, observedNow, observedThen: undefined });
261
+ merged.entries.push(...cs.entries);
262
+ }
263
+ liveEvidence = liveEvidenceFromChangeSet(merged, liveNameMapping);
264
+ }
265
+
266
+ // #609: resolve the persisted build manifest behind each recorded digest
267
+ // (if any) so `build`/`componentBom` are real queries, not always null.
268
+ const buildsByDigest = new Map<string, BuildLedgerEntry>();
269
+ const componentBomByDigest = new Map<string, ComponentBomSummary>();
270
+ const recordedDigests = new Set(ledger.records.map((r) => r.digest));
271
+ for (const digest of recordedDigests) {
272
+ const manifest = await findBuildManifestByArtifactDigest(digest);
273
+ if (!manifest) continue;
274
+
275
+ const bom = componentBomSummary(manifest);
276
+ if (bom) componentBomByDigest.set(digest, bom);
277
+
278
+ const ledgerEntries = await buildLedgerEntries(manifest);
279
+ const entry = ledgerEntries.find((e) => e.digest === digest);
280
+ if (entry) buildsByDigest.set(digest, entry);
281
+ }
282
+
283
+ const rows = reconcileStatus(environment, ledger.records, {
284
+ liveEvidence,
285
+ allComponents,
286
+ buildsByDigest,
287
+ componentBomByDigest,
288
+ });
289
+
290
+ for (const row of rows) {
291
+ allRows.push({
292
+ component: row.component,
293
+ env: row.env,
294
+ recorded: row.recorded
295
+ ? {
296
+ digest: row.recorded.digest,
297
+ gitSha: row.recorded.gitSha,
298
+ runId: row.recorded.runId,
299
+ timestamp: row.recorded.timestamp,
300
+ actor: row.recorded.actor,
301
+ }
302
+ : null,
303
+ build: row.build
304
+ ? {
305
+ manifestDigest: row.build.manifestDigest,
306
+ referrers: row.build.referrers.map((r) => r.kind),
307
+ sbom: row.build.sbom
308
+ ? {
309
+ mediaType: row.build.sbom.mediaType,
310
+ packageCount: row.build.sbom.packageCount,
311
+ generator: row.build.sbom.generator,
312
+ source: row.build.sbom.source,
313
+ }
314
+ : null,
315
+ reproducibility: row.build.reproducibility
316
+ ? { basis: row.build.reproducibility.basis, verifyBy: row.build.reproducibility.verifyBy }
317
+ : null,
318
+ }
319
+ : null,
320
+ componentBom: row.componentBom
321
+ ? {
322
+ leaves: row.componentBom.leaves.map((l) => ({
323
+ path: l.path,
324
+ bomKind: l.bomKind,
325
+ subjectDigest: l.subjectDigest,
326
+ mediaType: l.mediaType,
327
+ packageCount: l.packageCount,
328
+ generator: l.generator,
329
+ })),
330
+ totalPackageCount: row.componentBom.totalPackageCount,
331
+ isAssembly: row.componentBom.isAssembly,
332
+ }
333
+ : null,
334
+ reconciliation: row.reconciliation,
335
+ detail: row.detail,
336
+ });
337
+ }
338
+ }
339
+
340
+ // `--compare-to` — single-query cross-env digest comparison, per component.
341
+ let comparisons: ReturnType<typeof compareAcrossEnvironments>[] | undefined;
342
+ if (args.compareTo && requestedEnv) {
343
+ const otherLedger = ledgerByEnv.get(args.compareTo) ?? (await readReleaseLedger(args.compareTo));
344
+ const componentsToCompare = new Set([...allRows.map((r) => r.component)]);
345
+ comparisons = [...componentsToCompare].sort().map((component) =>
346
+ compareAcrossEnvironments(
347
+ component,
348
+ { name: requestedEnv, records: ledgerByEnv.get(requestedEnv)?.records ?? [] },
349
+ { name: args.compareTo!, records: otherLedger.records },
350
+ ),
351
+ );
352
+ }
353
+
354
+ if (args.json) {
355
+ console.log(JSON.stringify(comparisons ? { rows: allRows, comparisons } : allRows, null, 2));
356
+ return 0;
357
+ }
358
+
359
+ console.log(
360
+ formatBold("COMPONENT".padEnd(24)) +
361
+ formatBold("ENV".padEnd(12)) +
362
+ formatBold("DIGEST".padEnd(20)) +
363
+ formatBold("STATUS".padEnd(14)) +
364
+ formatBold("DETAIL"),
365
+ );
366
+ console.log("-".repeat(110));
367
+ for (const row of allRows) {
368
+ const digestShort = row.recorded ? row.recorded.digest.slice(0, 19) : "-";
369
+ console.log(
370
+ row.component.padEnd(24) +
371
+ row.env.padEnd(12) +
372
+ digestShort.padEnd(20) +
373
+ row.reconciliation.padEnd(14) +
374
+ row.detail,
375
+ );
376
+ }
377
+
378
+ if (comparisons) {
379
+ console.log(`\n${formatBold(`Cross-check: ${requestedEnv} vs ${args.compareTo}`)}`);
380
+ for (const c of comparisons) {
381
+ const verdict = c.same ? "same build" : "DIFFERENT builds";
382
+ console.log(` ${c.component}: ${c.digestA ?? "(none)"} vs ${c.digestB ?? "(none)"} — ${verdict}`);
383
+ }
384
+ }
385
+
386
+ const unrecordedCount = allRows.filter((r) => r.reconciliation === "unrecorded").length;
387
+ const driftedCount = allRows.filter((r) => r.reconciliation === "drifted").length;
388
+ if (unrecordedCount === 0 && driftedCount === 0) {
389
+ console.error(formatSuccess(`No unrecorded deploys or drift across ${allRows.length} row(s)`));
390
+ } else {
391
+ console.error(formatWarning({ message: `${unrecordedCount} unrecorded, ${driftedCount} drifted` }));
392
+ }
393
+
394
+ return 0;
395
+ }
396
+
397
+ /** Fallback for `chant components` with no/unknown subcommand. */
398
+ export async function runComponentsUnknown(ctx: CommandContext): Promise<number> {
399
+ console.error(formatError({
400
+ message: `Unknown components subcommand: ${ctx.args.path}`,
401
+ hint: "Available: chant components status [env], chant components release <env>",
402
+ }));
403
+ return 1;
404
+ }
@@ -46,10 +46,69 @@ export async function runDevCheckLexicon(ctx: CommandContext): Promise<number> {
46
46
  return result.tier1Pass ? 0 : 1;
47
47
  }
48
48
 
49
+ export async function runDevSurfaceDiff(ctx: CommandContext): Promise<number> {
50
+ const dir = ctx.args.extraPositional ?? ".";
51
+ const { runSurfaceDiff, printSurfaceDiffResult } = await import("../commands/lexicon-surface-diff");
52
+ const result = await runSurfaceDiff({
53
+ lexiconDir: resolve(dir),
54
+ force: ctx.args.force,
55
+ verbose: ctx.args.verbose,
56
+ runExamples: ctx.args.runExamples,
57
+ pinnedDigestPath: ctx.args.pinnedDigest,
58
+ // --check never writes; it verifies the committed baseline is in sync.
59
+ updateSnapshot: ctx.args.check ? false : ctx.args.updateSnapshot,
60
+ bump: ctx.args.bump,
61
+ });
62
+ printSurfaceDiffResult(result, ctx.args.format === "json");
63
+ // --check: fail if regen failed OR the fresh surface drifted from the
64
+ // committed baseline (stale/hand-edited baseline, or pin bumped without
65
+ // updating it). Meaningful for pinned lexicons — a fresh regen at the pinned
66
+ // version must equal the baseline. #545.
67
+ if (ctx.args.check) {
68
+ if (!result.ok) return 1;
69
+ if (result.changed) {
70
+ console.error(
71
+ `Baseline out of sync: ${dir}/surface.snapshot.json differs from a fresh regen. ` +
72
+ `Re-baseline with: chant dev surface-diff ${dir} --update-snapshot --bump`,
73
+ );
74
+ return 1;
75
+ }
76
+ return 0;
77
+ }
78
+ return result.ok ? 0 : 1;
79
+ }
80
+
81
+ export async function runDevPinnedUpgrade(ctx: CommandContext): Promise<number> {
82
+ const dir = ctx.args.extraPositional ?? ".";
83
+ const { runPinnedUpgrade, printPinnedUpgradeResult } = await import("../commands/pinned-upgrade");
84
+ const result = await runPinnedUpgrade({
85
+ lexiconDir: resolve(dir),
86
+ force: ctx.args.force,
87
+ verbose: ctx.args.verbose,
88
+ });
89
+ printPinnedUpgradeResult(result, ctx.args.format === "json");
90
+ // Exit non-zero when the upstream query failed or the regen validation broke.
91
+ if (result.fetchError) return 1;
92
+ if (result.validation && !result.validation.ok) return 1;
93
+ return 0;
94
+ }
95
+
96
+ export async function runDevRollingUpgrade(ctx: CommandContext): Promise<number> {
97
+ const dir = ctx.args.extraPositional ?? ".";
98
+ const { runRollingUpgrade, printRollingUpgradeResult } = await import("../commands/lexicon-rolling-upgrade");
99
+ const result = await runRollingUpgrade({
100
+ lexiconDir: resolve(dir),
101
+ force: ctx.args.force,
102
+ verbose: ctx.args.verbose,
103
+ });
104
+ printRollingUpgradeResult(result, ctx.args.format === "json");
105
+ return result.validationOk ? 0 : 1;
106
+ }
107
+
49
108
  export async function runDevUnknown(ctx: CommandContext): Promise<number> {
50
109
  console.error(formatError({
51
110
  message: `Unknown dev subcommand: ${ctx.args.path}`,
52
- hint: "Available: chant dev generate, chant dev publish, chant dev onboard, chant dev check-lexicon",
111
+ hint: "Available: chant dev generate, chant dev publish, chant dev onboard, chant dev check-lexicon, chant dev surface-diff, chant dev pinned-upgrade, chant dev rolling-upgrade",
53
112
  }));
54
113
  return 1;
55
114
  }
@@ -12,22 +12,67 @@ import { lintCommand } from "../commands/lint";
12
12
  import { readFileSync } from "node:fs";
13
13
  import { formatError, formatWarning, formatBold } from "../format";
14
14
  import type { CommandContext } from "../registry";
15
+ import { computeComponentGraph } from "../../components/cli-support";
15
16
 
16
17
  /**
17
18
  * `chant graph` — the Op dependency graph by default; `--stacks` renders the
18
19
  * cross-stack apply-ordering graph (edges, order, waves) chant computes from
19
- * cross-lexicon references; `--format ir|mermaid` emits the lint-gated
20
- * entity-graph IR (or a Mermaid flowchart of it) for diagrams (#493/#496).
20
+ * cross-lexicon references; `--components` (#560) renders the same
21
+ * order/waves shape for discovered `Component` declarations, from their
22
+ * `dependsOn`; `--format ir|mermaid` emits the lint-gated entity-graph IR (or
23
+ * a Mermaid flowchart of it) for diagrams (#493/#496).
21
24
  */
22
25
  export async function runGraph(ctx: CommandContext): Promise<number> {
23
26
  const viewFormats = ["ir", "mermaid", "dot", "layout"] as const;
24
27
  if ((viewFormats as readonly string[]).includes(ctx.args.format)) {
25
28
  return runGraphView(ctx, ctx.args.format as (typeof viewFormats)[number]);
26
29
  }
30
+ if (ctx.args.components) return runComponentGraph(ctx);
27
31
  if (ctx.args.stacks) return runStackGraph(ctx);
28
32
  return runOpGraph();
29
33
  }
30
34
 
35
+ /**
36
+ * `chant graph --components` (#560) — dependency order/waves for discovered
37
+ * `Component` declarations, mirroring `runStackGraph`'s presentation
38
+ * (waves top-to-bottom, consumer → producer edges) but sourced from
39
+ * `computeComponentGraph` (../../components/cli-support.ts), which resolves
40
+ * order purely from each component's flat `dependsOn` list — no AttrRef-style
41
+ * cross-lexicon inference needed, since a component's dependency is always
42
+ * an explicit name.
43
+ */
44
+ async function runComponentGraph(ctx: CommandContext): Promise<number> {
45
+ const projectPath = resolve(ctx.args.path === "." ? "." : ctx.args.path);
46
+ const graph = await computeComponentGraph(projectPath);
47
+
48
+ if (!graph.success) {
49
+ console.error(formatError({ message: graph.error ?? "Failed to compute component graph" }));
50
+ return 1;
51
+ }
52
+
53
+ if (ctx.args.json) {
54
+ console.log(JSON.stringify(graph, null, 2));
55
+ return 0;
56
+ }
57
+
58
+ if (graph.order.length === 0) {
59
+ console.log("No components found");
60
+ return 0;
61
+ }
62
+
63
+ console.log(formatBold("Deploy order (waves apply top-to-bottom; a wave's components are parallel-safe):"));
64
+ graph.waves.forEach((wave, i) => console.log(` ${i + 1}. ${wave.join(", ")}`));
65
+
66
+ if (graph.edges.length > 0) {
67
+ console.log(formatBold("\nDependencies (consumer → producer):"));
68
+ for (const { from, to } of graph.edges) console.log(` ${from} → ${to}`);
69
+ } else {
70
+ console.log("\nNo cross-component dependencies — all components are independent.");
71
+ }
72
+
73
+ return 0;
74
+ }
75
+
31
76
  /**
32
77
  * `chant graph --format ir|mermaid|dot|layout` — build the graph IR (honouring
33
78
  * `--detail`) and emit it as JSON, a Mermaid flowchart, Graphviz DOT, or node
@@ -4,9 +4,10 @@ import { importCommand, importFromLive, printImportResult } from "../commands/im
4
4
  import { auditCommand, printAuditResult, type AuditFormat, type AuditTier, type AuditFailOn } from "../commands/audit";
5
5
  import type { ReportTheme } from "../../audit/report-html";
6
6
  import type { ResourceSelector } from "../../lexicon";
7
- import { formatError, formatSuccess, formatWarning } from "../format";
7
+ import { formatError, formatSuccess, formatWarning, formatBold } from "../format";
8
8
  import type { CommandContext } from "../registry";
9
9
  import { createRequire } from "module";
10
+ import { listComponents, describeComponent } from "../../components/cli-support";
10
11
 
11
12
  const CHANT_VERSION: string = (() => {
12
13
  try {
@@ -84,6 +85,30 @@ export async function runList(ctx: CommandContext): Promise<number> {
84
85
  return 1;
85
86
  }
86
87
 
88
+ // `chant list --components` (#560) surfaces discovered `Component`
89
+ // declarations instead of lexicon resources — a distinct entity kind (no
90
+ // `lexicon`/`entityType`), so it is a separate branch rather than folded
91
+ // into `listCommand`'s Declarable-shaped `ListEntity` rows.
92
+ if (args.components) {
93
+ const result = await listComponents(args.path);
94
+ if (!result.success) {
95
+ for (const e of result.errors) console.error(formatError({ message: e }));
96
+ return 1;
97
+ }
98
+ if (listFormat === "json") {
99
+ console.log(JSON.stringify(result.components, null, 2));
100
+ } else if (result.components.length === 0) {
101
+ console.log("No components found.");
102
+ } else {
103
+ console.log(formatBold("NAME") + " " + formatBold("ARCHETYPE") + " " + formatBold("DEPENDS ON") + " " + formatBold("PHASES"));
104
+ for (const c of result.components) {
105
+ console.log(`${c.name} ${c.archetype} ${c.dependsOn.join(", ") || "-"} ${c.phases.join(", ")}`);
106
+ }
107
+ }
108
+ console.error(formatSuccess(`Found ${formatBold(String(result.components.length))} component(s)`));
109
+ return 0;
110
+ }
111
+
87
112
  const result = await listCommand({
88
113
  path: args.path,
89
114
  format: listFormat,
@@ -112,6 +137,25 @@ export async function runDescribe(ctx: CommandContext): Promise<number> {
112
137
  return 1;
113
138
  }
114
139
 
140
+ // `chant describe <name> --components` (#560): describe a discovered
141
+ // `Component` (its full JSON contract projection) rather than a lexicon
142
+ // resource's resolved props bag.
143
+ if (args.components) {
144
+ const result = await describeComponent(args.extraPositional ?? ".", component);
145
+ if (!result.success || !result.described) {
146
+ console.log(result.output);
147
+ return 1;
148
+ }
149
+ if (describeFormat === "json") {
150
+ console.log(JSON.stringify(result.described.json, null, 2));
151
+ } else {
152
+ console.log(`${formatBold(result.described.name)} (${result.described.filePath})`);
153
+ console.log(JSON.stringify(result.described.json, null, 2));
154
+ }
155
+ console.error(formatSuccess(`Described ${formatBold(component)}`));
156
+ return 0;
157
+ }
158
+
115
159
  const result = await describeCommand({
116
160
  component,
117
161
  path: args.extraPositional ?? ".",