@intentius/chant 0.13.0 → 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 (453) 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/fetch.d.ts.map +1 -1
  4. package/dist/audit/proof.d.ts +3 -0
  5. package/dist/audit/proof.d.ts.map +1 -1
  6. package/dist/audit/report-model.d.ts +4 -1
  7. package/dist/audit/report-model.d.ts.map +1 -1
  8. package/dist/audit/report.d.ts +3 -0
  9. package/dist/audit/report.d.ts.map +1 -1
  10. package/dist/audit/rules-doc.d.ts +8 -2
  11. package/dist/audit/rules-doc.d.ts.map +1 -1
  12. package/dist/cli/commands/audit.d.ts.map +1 -1
  13. package/dist/cli/commands/doctor.d.ts.map +1 -1
  14. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
  15. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
  16. package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
  17. package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
  18. package/dist/cli/commands/lint.d.ts.map +1 -1
  19. package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
  20. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
  21. package/dist/cli/handlers/build.d.ts.map +1 -1
  22. package/dist/cli/handlers/components.d.ts +39 -0
  23. package/dist/cli/handlers/components.d.ts.map +1 -0
  24. package/dist/cli/handlers/dev.d.ts +3 -0
  25. package/dist/cli/handlers/dev.d.ts.map +1 -1
  26. package/dist/cli/handlers/graph.d.ts +4 -2
  27. package/dist/cli/handlers/graph.d.ts.map +1 -1
  28. package/dist/cli/handlers/misc.d.ts.map +1 -1
  29. package/dist/cli/handlers/run.d.ts +49 -0
  30. package/dist/cli/handlers/run.d.ts.map +1 -1
  31. package/dist/cli/main.d.ts.map +1 -1
  32. package/dist/cli/registry.d.ts +35 -0
  33. package/dist/cli/registry.d.ts.map +1 -1
  34. package/dist/codegen/fetch.d.ts +22 -0
  35. package/dist/codegen/fetch.d.ts.map +1 -1
  36. package/dist/codegen/lexicon-regen.d.ts +110 -0
  37. package/dist/codegen/lexicon-regen.d.ts.map +1 -0
  38. package/dist/codegen/pinned-upgrade.d.ts +153 -0
  39. package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
  40. package/dist/codegen/rolling-upgrade.d.ts +138 -0
  41. package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
  42. package/dist/codegen/surface-snapshot.d.ts +173 -0
  43. package/dist/codegen/surface-snapshot.d.ts.map +1 -0
  44. package/dist/codegen/version-bump.d.ts +21 -0
  45. package/dist/codegen/version-bump.d.ts.map +1 -0
  46. package/dist/components/auto-release.d.ts +93 -0
  47. package/dist/components/auto-release.d.ts.map +1 -0
  48. package/dist/components/builders.d.ts +37 -0
  49. package/dist/components/builders.d.ts.map +1 -0
  50. package/dist/components/capability-plugin-loader.d.ts +111 -0
  51. package/dist/components/capability-plugin-loader.d.ts.map +1 -0
  52. package/dist/components/capability-plugin-schema.d.ts +24 -0
  53. package/dist/components/capability-plugin-schema.d.ts.map +1 -0
  54. package/dist/components/capability-plugin.d.ts +85 -0
  55. package/dist/components/capability-plugin.d.ts.map +1 -0
  56. package/dist/components/capability.d.ts +89 -0
  57. package/dist/components/capability.d.ts.map +1 -0
  58. package/dist/components/cli-support.d.ts +204 -0
  59. package/dist/components/cli-support.d.ts.map +1 -0
  60. package/dist/components/component.d.ts +179 -0
  61. package/dist/components/component.d.ts.map +1 -0
  62. package/dist/components/config-defaults.d.ts +41 -0
  63. package/dist/components/config-defaults.d.ts.map +1 -0
  64. package/dist/components/discover.d.ts +60 -0
  65. package/dist/components/discover.d.ts.map +1 -0
  66. package/dist/components/driver-output.d.ts +20 -0
  67. package/dist/components/driver-output.d.ts.map +1 -0
  68. package/dist/components/driver.d.ts +209 -0
  69. package/dist/components/driver.d.ts.map +1 -0
  70. package/dist/components/index.d.ts +22 -0
  71. package/dist/components/index.d.ts.map +1 -0
  72. package/dist/components/manifest-persistence.d.ts +79 -0
  73. package/dist/components/manifest-persistence.d.ts.map +1 -0
  74. package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
  75. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
  76. package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
  77. package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
  78. package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
  79. package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
  80. package/dist/components/pilots/lambda.pilot.d.ts +35 -0
  81. package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
  82. package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
  83. package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
  84. package/dist/components/pilots/project.d.ts +13 -0
  85. package/dist/components/pilots/project.d.ts.map +1 -0
  86. package/dist/components/presets/ecs-fargate.d.ts +59 -0
  87. package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
  88. package/dist/components/presets/index.d.ts +29 -0
  89. package/dist/components/presets/index.d.ts.map +1 -0
  90. package/dist/components/presets/lambda.d.ts +35 -0
  91. package/dist/components/presets/lambda.d.ts.map +1 -0
  92. package/dist/components/presets/single-host-compose.d.ts +43 -0
  93. package/dist/components/presets/single-host-compose.d.ts.map +1 -0
  94. package/dist/components/registry.d.ts +29 -0
  95. package/dist/components/registry.d.ts.map +1 -0
  96. package/dist/components/starter-plugin.d.ts +51 -0
  97. package/dist/components/starter-plugin.d.ts.map +1 -0
  98. package/dist/components/temporal-codegen-loader.d.ts +27 -0
  99. package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
  100. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
  101. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
  102. package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
  103. package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
  104. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
  105. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
  106. package/dist/components/verbs/bom-writer.d.ts +155 -0
  107. package/dist/components/verbs/bom-writer.d.ts.map +1 -0
  108. package/dist/components/verbs/build-archive.d.ts +205 -0
  109. package/dist/components/verbs/build-archive.d.ts.map +1 -0
  110. package/dist/components/verbs/build.d.ts +150 -0
  111. package/dist/components/verbs/build.d.ts.map +1 -0
  112. package/dist/components/verbs/cloud-executor.d.ts +88 -0
  113. package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
  114. package/dist/components/verbs/component-bom.d.ts +103 -0
  115. package/dist/components/verbs/component-bom.d.ts.map +1 -0
  116. package/dist/components/verbs/index.d.ts +49 -0
  117. package/dist/components/verbs/index.d.ts.map +1 -0
  118. package/dist/components/verbs/license-policy.d.ts +56 -0
  119. package/dist/components/verbs/license-policy.d.ts.map +1 -0
  120. package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
  121. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
  122. package/dist/components/verbs/process-runner.d.ts +64 -0
  123. package/dist/components/verbs/process-runner.d.ts.map +1 -0
  124. package/dist/components/verbs/reproducibility.d.ts +80 -0
  125. package/dist/components/verbs/reproducibility.d.ts.map +1 -0
  126. package/dist/components/verbs/sbom-generator.d.ts +157 -0
  127. package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
  128. package/dist/components/verbs/sbom.d.ts +79 -0
  129. package/dist/components/verbs/sbom.d.ts.map +1 -0
  130. package/dist/components/verbs/shell.d.ts +35 -0
  131. package/dist/components/verbs/shell.d.ts.map +1 -0
  132. package/dist/components/verbs/sign.d.ts +222 -0
  133. package/dist/components/verbs/sign.d.ts.map +1 -0
  134. package/dist/components/verbs/stub.d.ts +18 -0
  135. package/dist/components/verbs/stub.d.ts.map +1 -0
  136. package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
  137. package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
  138. package/dist/components/verbs/verify.d.ts +106 -0
  139. package/dist/components/verbs/verify.d.ts.map +1 -0
  140. package/dist/components/verbs/vex.d.ts +65 -0
  141. package/dist/components/verbs/vex.d.ts.map +1 -0
  142. package/dist/components/verbs/vuln-gate.d.ts +91 -0
  143. package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
  144. package/dist/components/verbs/vuln-scan.d.ts +116 -0
  145. package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
  146. package/dist/components/verbs/wait-verify.d.ts +85 -0
  147. package/dist/components/verbs/wait-verify.d.ts.map +1 -0
  148. package/dist/config.d.ts +205 -0
  149. package/dist/config.d.ts.map +1 -1
  150. package/dist/index.d.ts +4 -0
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/lexicon.d.ts +78 -0
  153. package/dist/lexicon.d.ts.map +1 -1
  154. package/dist/lifecycle/build-ledger-store.d.ts +121 -0
  155. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
  156. package/dist/lifecycle/build-ledger.d.ts +225 -0
  157. package/dist/lifecycle/build-ledger.d.ts.map +1 -0
  158. package/dist/lifecycle/git.d.ts +84 -0
  159. package/dist/lifecycle/git.d.ts.map +1 -1
  160. package/dist/lifecycle/index.d.ts +5 -0
  161. package/dist/lifecycle/index.d.ts.map +1 -1
  162. package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
  163. package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
  164. package/dist/lifecycle/release-ledger.d.ts +122 -0
  165. package/dist/lifecycle/release-ledger.d.ts.map +1 -0
  166. package/dist/lifecycle/status.d.ts +150 -0
  167. package/dist/lifecycle/status.d.ts.map +1 -0
  168. package/dist/lint/component-checks.d.ts +95 -0
  169. package/dist/lint/component-checks.d.ts.map +1 -0
  170. package/dist/lint/engine.d.ts +23 -0
  171. package/dist/lint/engine.d.ts.map +1 -1
  172. package/dist/lint/presets/strict.json +8 -1
  173. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
  174. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
  175. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
  176. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
  177. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
  178. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
  179. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
  180. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
  181. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
  182. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
  183. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
  184. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
  185. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
  186. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
  187. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
  188. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
  189. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
  190. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
  191. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
  192. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
  193. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
  194. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
  195. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
  196. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
  197. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
  198. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
  199. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
  200. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
  201. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
  202. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
  203. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
  204. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
  205. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
  206. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
  207. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
  208. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
  209. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
  210. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
  211. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
  212. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
  213. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
  214. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
  215. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
  216. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
  217. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
  218. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
  219. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
  220. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
  221. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
  222. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
  223. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
  224. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
  225. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
  226. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
  227. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
  228. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
  229. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
  230. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
  231. package/dist/lint/rules/comp/index.d.ts +18 -0
  232. package/dist/lint/rules/comp/index.d.ts.map +1 -0
  233. package/dist/lint/rules/comp/support.d.ts +71 -0
  234. package/dist/lint/rules/comp/support.d.ts.map +1 -0
  235. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  236. package/dist/op/activity-registry.d.ts +11 -6
  237. package/dist/op/activity-registry.d.ts.map +1 -1
  238. package/dist/op/activity-runtime.d.ts +24 -0
  239. package/dist/op/activity-runtime.d.ts.map +1 -0
  240. package/dist/op/builders.d.ts +56 -0
  241. package/dist/op/builders.d.ts.map +1 -1
  242. package/dist/op/index.d.ts +2 -1
  243. package/dist/op/index.d.ts.map +1 -1
  244. package/dist/ownership.d.ts +20 -14
  245. package/dist/ownership.d.ts.map +1 -1
  246. package/package.json +14 -1
  247. package/src/audit/catalog.test.ts +74 -22
  248. package/src/audit/catalog.ts +74 -471
  249. package/src/audit/fetch.test.ts +112 -8
  250. package/src/audit/fetch.ts +53 -8
  251. package/src/audit/proof.ts +4 -2
  252. package/src/audit/report-html.test.ts +14 -7
  253. package/src/audit/report-model.ts +20 -9
  254. package/src/audit/report.test.ts +36 -13
  255. package/src/audit/report.ts +2 -0
  256. package/src/audit/rules-doc.test.ts +8 -6
  257. package/src/audit/rules-doc.ts +13 -5
  258. package/src/cli/commands/audit.ts +23 -18
  259. package/src/cli/commands/component-lint.test.ts +158 -0
  260. package/src/cli/commands/doctor.test.ts +116 -2
  261. package/src/cli/commands/doctor.ts +46 -0
  262. package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
  263. package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
  264. package/src/cli/commands/lexicon-surface-diff.ts +185 -0
  265. package/src/cli/commands/lint.ts +142 -1
  266. package/src/cli/commands/pinned-upgrade.ts +204 -0
  267. package/src/cli/handlers/build.ts +58 -1
  268. package/src/cli/handlers/components.test.ts +504 -0
  269. package/src/cli/handlers/components.ts +404 -0
  270. package/src/cli/handlers/dev.ts +60 -1
  271. package/src/cli/handlers/graph.ts +47 -2
  272. package/src/cli/handlers/misc.ts +45 -1
  273. package/src/cli/handlers/run.test.ts +967 -3
  274. package/src/cli/handlers/run.ts +618 -11
  275. package/src/cli/main.test.ts +66 -0
  276. package/src/cli/main.ts +105 -2
  277. package/src/cli/registry.ts +35 -0
  278. package/src/codegen/fetch.test.ts +84 -3
  279. package/src/codegen/fetch.ts +76 -2
  280. package/src/codegen/lexicon-regen.test.ts +298 -0
  281. package/src/codegen/lexicon-regen.ts +545 -0
  282. package/src/codegen/pinned-upgrade.test.ts +399 -0
  283. package/src/codegen/pinned-upgrade.ts +423 -0
  284. package/src/codegen/rolling-upgrade.test.ts +333 -0
  285. package/src/codegen/rolling-upgrade.ts +320 -0
  286. package/src/codegen/surface-snapshot.test.ts +461 -0
  287. package/src/codegen/surface-snapshot.ts +546 -0
  288. package/src/codegen/version-bump.test.ts +47 -0
  289. package/src/codegen/version-bump.ts +39 -0
  290. package/src/components/README.md +130 -0
  291. package/src/components/SPRAWL-VALIDATION.md +181 -0
  292. package/src/components/__fixtures__/alb-ecs-service.json +51 -0
  293. package/src/components/__fixtures__/dynamodb-infra.json +32 -0
  294. package/src/components/__fixtures__/emr-job-consumer.json +26 -0
  295. package/src/components/__fixtures__/jar-lib-producer.json +16 -0
  296. package/src/components/__fixtures__/lambda-image-processor.json +28 -0
  297. package/src/components/__fixtures__/neo4j-fanout.json +34 -0
  298. package/src/components/__fixtures__/single-host-compose.json +29 -0
  299. package/src/components/auto-release.test.ts +217 -0
  300. package/src/components/auto-release.ts +216 -0
  301. package/src/components/builders.test.ts +45 -0
  302. package/src/components/builders.ts +71 -0
  303. package/src/components/capability-plugin-loader.ts +218 -0
  304. package/src/components/capability-plugin-schema.ts +56 -0
  305. package/src/components/capability-plugin.test.ts +235 -0
  306. package/src/components/capability-plugin.ts +108 -0
  307. package/src/components/capability.ts +117 -0
  308. package/src/components/cli-support.test.ts +579 -0
  309. package/src/components/cli-support.ts +481 -0
  310. package/src/components/component-schema.test.ts +265 -0
  311. package/src/components/component.schema.json +235 -0
  312. package/src/components/component.test.ts +251 -0
  313. package/src/components/component.ts +255 -0
  314. package/src/components/config-defaults.test.ts +263 -0
  315. package/src/components/config-defaults.ts +145 -0
  316. package/src/components/discover.test.ts +352 -0
  317. package/src/components/discover.ts +167 -0
  318. package/src/components/driver-output.ts +71 -0
  319. package/src/components/driver.test.ts +638 -0
  320. package/src/components/driver.ts +690 -0
  321. package/src/components/index.ts +113 -0
  322. package/src/components/manifest-persistence.test.ts +152 -0
  323. package/src/components/manifest-persistence.ts +164 -0
  324. package/src/components/pilots/README.md +33 -0
  325. package/src/components/pilots/alb-ecs.pilot.ts +63 -0
  326. package/src/components/pilots/dynamodb.pilot.ts +59 -0
  327. package/src/components/pilots/jar-emr.pilot.ts +69 -0
  328. package/src/components/pilots/lambda.pilot.ts +55 -0
  329. package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
  330. package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
  331. package/src/components/pilots/pilots.test.ts +126 -0
  332. package/src/components/pilots/project.ts +13 -0
  333. package/src/components/presets/comp007-reduction.test.ts +122 -0
  334. package/src/components/presets/ecs-fargate.test.ts +84 -0
  335. package/src/components/presets/ecs-fargate.ts +103 -0
  336. package/src/components/presets/index.ts +32 -0
  337. package/src/components/presets/lambda.test.ts +35 -0
  338. package/src/components/presets/lambda.ts +53 -0
  339. package/src/components/presets/single-host-compose.test.ts +65 -0
  340. package/src/components/presets/single-host-compose.ts +64 -0
  341. package/src/components/registry.test.ts +112 -0
  342. package/src/components/registry.ts +37 -0
  343. package/src/components/starter-plugin.ts +105 -0
  344. package/src/components/temporal-codegen-loader.ts +41 -0
  345. package/src/components/verbs/__fixtures__/package-lock.json +45 -0
  346. package/src/components/verbs/__fixtures__/pom.xml +37 -0
  347. package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
  348. package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
  349. package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
  350. package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
  351. package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
  352. package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
  353. package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
  354. package/src/components/verbs/bom-writer.test.ts +331 -0
  355. package/src/components/verbs/bom-writer.ts +386 -0
  356. package/src/components/verbs/build-archive.test.ts +251 -0
  357. package/src/components/verbs/build-archive.ts +296 -0
  358. package/src/components/verbs/build.test.ts +222 -0
  359. package/src/components/verbs/build.ts +252 -0
  360. package/src/components/verbs/cloud-executor.ts +181 -0
  361. package/src/components/verbs/component-bom.test.ts +219 -0
  362. package/src/components/verbs/component-bom.ts +189 -0
  363. package/src/components/verbs/index.ts +49 -0
  364. package/src/components/verbs/license-policy.ts +115 -0
  365. package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
  366. package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
  367. package/src/components/verbs/process-runner.test.ts +79 -0
  368. package/src/components/verbs/process-runner.ts +113 -0
  369. package/src/components/verbs/reproducibility.test.ts +24 -0
  370. package/src/components/verbs/reproducibility.ts +100 -0
  371. package/src/components/verbs/sbom-generator.test.ts +96 -0
  372. package/src/components/verbs/sbom-generator.ts +209 -0
  373. package/src/components/verbs/sbom.test.ts +184 -0
  374. package/src/components/verbs/sbom.ts +152 -0
  375. package/src/components/verbs/shell.test.ts +36 -0
  376. package/src/components/verbs/shell.ts +51 -0
  377. package/src/components/verbs/sign.test.ts +210 -0
  378. package/src/components/verbs/sign.ts +350 -0
  379. package/src/components/verbs/stub.ts +34 -0
  380. package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
  381. package/src/components/verbs/tool-sbom-generator.ts +192 -0
  382. package/src/components/verbs/verify.test.ts +159 -0
  383. package/src/components/verbs/verify.ts +179 -0
  384. package/src/components/verbs/vex.ts +182 -0
  385. package/src/components/verbs/vuln-gate.test.ts +201 -0
  386. package/src/components/verbs/vuln-gate.ts +170 -0
  387. package/src/components/verbs/vuln-scan.test.ts +145 -0
  388. package/src/components/verbs/vuln-scan.ts +266 -0
  389. package/src/components/verbs/wait-verify.test.ts +111 -0
  390. package/src/components/verbs/wait-verify.ts +171 -0
  391. package/src/config.test.ts +74 -1
  392. package/src/config.ts +219 -0
  393. package/src/index.ts +32 -0
  394. package/src/lexicon.ts +88 -0
  395. package/src/lifecycle/build-ledger-store.test.ts +217 -0
  396. package/src/lifecycle/build-ledger-store.ts +165 -0
  397. package/src/lifecycle/build-ledger.test.ts +349 -0
  398. package/src/lifecycle/build-ledger.ts +305 -0
  399. package/src/lifecycle/git.test.ts +118 -0
  400. package/src/lifecycle/git.ts +149 -14
  401. package/src/lifecycle/index.ts +5 -0
  402. package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
  403. package/src/lifecycle/oras-referrer-lookup.ts +110 -0
  404. package/src/lifecycle/release-ledger.test.ts +209 -0
  405. package/src/lifecycle/release-ledger.ts +185 -0
  406. package/src/lifecycle/status.test.ts +330 -0
  407. package/src/lifecycle/status.ts +278 -0
  408. package/src/lint/component-checks.ts +148 -0
  409. package/src/lint/config.test.ts +21 -0
  410. package/src/lint/engine.ts +11 -2
  411. package/src/lint/presets/relaxed.json +8 -1
  412. package/src/lint/presets/strict.json +8 -1
  413. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
  414. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
  415. package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
  416. package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
  417. package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
  418. package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
  419. package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
  420. package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
  421. package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
  422. package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
  423. package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
  424. package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
  425. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
  426. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
  427. package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
  428. package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
  429. package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
  430. package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
  431. package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
  432. package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
  433. package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
  434. package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
  435. package/src/lint/rules/comp/comp.test.ts +378 -0
  436. package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
  437. package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
  438. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
  439. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
  440. package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
  441. package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
  442. package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
  443. package/src/lint/rules/comp/index.ts +37 -0
  444. package/src/lint/rules/comp/support.ts +173 -0
  445. package/src/lsp/lexicon-providers.test.ts +55 -0
  446. package/src/lsp/lexicon-providers.ts +13 -3
  447. package/src/op/activity-registry.test.ts +38 -0
  448. package/src/op/activity-registry.ts +31 -12
  449. package/src/op/activity-runtime.ts +73 -0
  450. package/src/op/builders.ts +92 -0
  451. package/src/op/index.ts +3 -1
  452. package/src/ownership.test.ts +24 -26
  453. package/src/ownership.ts +26 -38
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Unit tests for the typed `Component` authoring form (#560, epic #551):
3
+ * the `phase()`/`gate()`/`stackOutput()` builders, `isComponent`,
4
+ * `inferArchetype`, and `projectToJson`. Schema-validation and
5
+ * fixture-equality coverage for real components lives in
6
+ * `./component-schema.test.ts` and `./pilots/pilots.test.ts`; this file
7
+ * covers the authoring API's own behavior in isolation.
8
+ */
9
+
10
+ import { describe, expect, it } from "vitest";
11
+ import {
12
+ phase,
13
+ gate,
14
+ stackOutput,
15
+ isComponent,
16
+ inferArchetype,
17
+ projectToJson,
18
+ type Component,
19
+ } from "./component";
20
+
21
+ describe("phase()", () => {
22
+ it("builds a Phase with no parallel flag by default", () => {
23
+ expect(phase("Apply", [{ kind: "shell" }])).toEqual({
24
+ phase: "Apply",
25
+ steps: [{ kind: "shell" }],
26
+ });
27
+ });
28
+
29
+ it("sets parallel: true when requested", () => {
30
+ expect(phase("Verify", [{ kind: "shell" }], { parallel: true })).toEqual({
31
+ phase: "Verify",
32
+ steps: [{ kind: "shell" }],
33
+ parallel: true,
34
+ });
35
+ });
36
+ });
37
+
38
+ describe("gate()", () => {
39
+ it("builds a minimal Gate", () => {
40
+ expect(gate("approve-x")).toEqual({ kind: "gate", signalName: "approve-x" });
41
+ });
42
+
43
+ it("carries optional timeout/description", () => {
44
+ expect(gate("approve-x", { timeout: "24h", description: "confirm" })).toEqual({
45
+ kind: "gate",
46
+ signalName: "approve-x",
47
+ timeout: "24h",
48
+ description: "confirm",
49
+ });
50
+ });
51
+ });
52
+
53
+ describe("stackOutput()", () => {
54
+ it("builds a StackOutputReference", () => {
55
+ expect(stackOutput("shared-alb", "ListenerArn")).toEqual({
56
+ stackOutput: { stack: "shared-alb", name: "ListenerArn" },
57
+ });
58
+ });
59
+ });
60
+
61
+ describe("isComponent()", () => {
62
+ it("accepts a minimal valid Component shape", () => {
63
+ expect(isComponent({ name: "x", dependsOn: [], deploy: [] })).toBe(true);
64
+ });
65
+
66
+ it("rejects null/non-objects", () => {
67
+ expect(isComponent(null)).toBe(false);
68
+ expect(isComponent(42)).toBe(false);
69
+ expect(isComponent("x")).toBe(false);
70
+ expect(isComponent(undefined)).toBe(false);
71
+ });
72
+
73
+ it("rejects an object missing dependsOn or deploy", () => {
74
+ expect(isComponent({ name: "x" })).toBe(false);
75
+ expect(isComponent({ name: "x", dependsOn: [] })).toBe(false);
76
+ expect(isComponent({ dependsOn: [], deploy: [] })).toBe(false);
77
+ });
78
+
79
+ it("rejects a plain non-Component object (e.g. a helper/const export)", () => {
80
+ expect(isComponent({ foo: "bar" })).toBe(false);
81
+ });
82
+ });
83
+
84
+ describe("inferArchetype()", () => {
85
+ it("infers infra when there is no build", () => {
86
+ expect(
87
+ inferArchetype({
88
+ deploy: [phase("Apply", [{ kind: "cfn-deploy" }])],
89
+ }),
90
+ ).toBe("infra");
91
+ });
92
+
93
+ it("infers producer-library when build is present and every step is publish-family", () => {
94
+ expect(
95
+ inferArchetype({
96
+ build: { kind: "jvm-build" },
97
+ deploy: [phase("Publish", [{ kind: "publish-artifact" }])],
98
+ }),
99
+ ).toBe("producer-library");
100
+ });
101
+
102
+ it("infers producer-library when the only non-publish steps are gates", () => {
103
+ expect(
104
+ inferArchetype({
105
+ build: { kind: "docker-build" },
106
+ deploy: [phase("Publish", [gate("approve"), { kind: "publish-image" }])],
107
+ }),
108
+ ).toBe("producer-library");
109
+ });
110
+
111
+ it("infers service when build is present and an apply/verify step follows publish", () => {
112
+ expect(
113
+ inferArchetype({
114
+ build: { kind: "docker-build" },
115
+ deploy: [
116
+ phase("Publish", [{ kind: "publish-image" }]),
117
+ phase("Apply", [{ kind: "cfn-deploy" }]),
118
+ ],
119
+ }),
120
+ ).toBe("service");
121
+ });
122
+
123
+ it("infers service for load-image-on-host + a non-publish apply step (single-host compose shape)", () => {
124
+ expect(
125
+ inferArchetype({
126
+ build: { kind: "docker-build" },
127
+ deploy: [
128
+ phase("Publish", [{ kind: "load-image-on-host" }]),
129
+ phase("Apply", [{ kind: "remote-exec" }]),
130
+ ],
131
+ }),
132
+ ).toBe("service");
133
+ });
134
+
135
+ it("looks inside nested fan-out phases", () => {
136
+ expect(
137
+ inferArchetype({
138
+ build: { kind: "docker-build" },
139
+ deploy: [
140
+ phase("Rolling", [
141
+ phase("Node 1", [{ kind: "publish-image" }]),
142
+ phase("Node 2", [{ kind: "cfn-deploy" }]),
143
+ ]),
144
+ ],
145
+ }),
146
+ ).toBe("service");
147
+ });
148
+ });
149
+
150
+ describe("projectToJson()", () => {
151
+ it("fills in archetype via inferArchetype when the author omits it", () => {
152
+ const component: Component = {
153
+ name: "table",
154
+ dependsOn: [],
155
+ deploy: [phase("Apply", [{ kind: "cfn-deploy" }])],
156
+ };
157
+ const projected = projectToJson(component) as { archetype: string };
158
+ expect(projected.archetype).toBe("infra");
159
+ });
160
+
161
+ it("keeps an explicit archetype as authored, even if it disagrees with the inferred shape", () => {
162
+ const component: Component = {
163
+ name: "table",
164
+ archetype: "service",
165
+ dependsOn: [],
166
+ deploy: [phase("Apply", [{ kind: "cfn-deploy" }])],
167
+ };
168
+ const projected = projectToJson(component) as { archetype: string };
169
+ expect(projected.archetype).toBe("service");
170
+ });
171
+
172
+ it("drops undefined optional fields (build/verify/rollback) rather than emitting nulls", () => {
173
+ const component: Component = {
174
+ name: "table",
175
+ dependsOn: [],
176
+ deploy: [phase("Apply", [{ kind: "cfn-deploy" }])],
177
+ };
178
+ const projected = projectToJson(component) as Record<string, unknown>;
179
+ expect("build" in projected).toBe(false);
180
+ expect("verify" in projected).toBe(false);
181
+ expect("rollback" in projected).toBe(false);
182
+ });
183
+
184
+ it("projects an explicit liveNames mapping through unchanged (#598)", () => {
185
+ const component: Component = {
186
+ name: "search-svc",
187
+ dependsOn: [],
188
+ liveNames: ["search-service-v2"],
189
+ deploy: [phase("Apply", [{ kind: "cfn-deploy" }])],
190
+ };
191
+ const projected = projectToJson(component) as { liveNames?: string[] };
192
+ expect(projected.liveNames).toEqual(["search-service-v2"]);
193
+ });
194
+
195
+ it("omits liveNames from the projection when not authored (#598)", () => {
196
+ const component: Component = {
197
+ name: "table",
198
+ dependsOn: [],
199
+ deploy: [phase("Apply", [{ kind: "cfn-deploy" }])],
200
+ };
201
+ const projected = projectToJson(component) as Record<string, unknown>;
202
+ expect("liveNames" in projected).toBe(false);
203
+ });
204
+
205
+ it("projects a stackOutput() wiring reference to its plain-JSON form", () => {
206
+ const component: Component = {
207
+ name: "svc",
208
+ dependsOn: ["shared-alb"],
209
+ deploy: [
210
+ phase("Apply", [
211
+ { kind: "cfn-deploy", inputs: { listenerArn: stackOutput("shared-alb", "ListenerArn") } },
212
+ ]),
213
+ ],
214
+ };
215
+ const projected = projectToJson(component) as {
216
+ deploy: Array<{ steps: Array<{ inputs: Record<string, unknown> }> }>;
217
+ };
218
+ expect(projected.deploy[0]!.steps[0]!.inputs.listenerArn).toEqual({
219
+ stackOutput: { stack: "shared-alb", name: "ListenerArn" },
220
+ });
221
+ });
222
+ });
223
+
224
+ describe("BuildSpec.sbom (#606 — component-level SBOM authoring hint)", () => {
225
+ it("projects an authored sbom hint through unchanged, riding BuildSpec's open additionalProperties shape", () => {
226
+ const component: Component = {
227
+ name: "search-service",
228
+ dependsOn: [],
229
+ build: { kind: "docker-build", context: ".", sbom: { format: "cyclonedx" } },
230
+ deploy: [phase("Publish", [{ kind: "publish-image" }])],
231
+ };
232
+ const projected = projectToJson(component) as { build: { sbom?: { format?: string; optOut?: boolean } } };
233
+ expect(projected.build.sbom).toEqual({ format: "cyclonedx" });
234
+ });
235
+
236
+ it("omits sbom from the projection when not authored (no behavior change for existing components)", () => {
237
+ const component: Component = {
238
+ name: "search-service",
239
+ dependsOn: [],
240
+ build: { kind: "docker-build", context: "." },
241
+ deploy: [phase("Publish", [{ kind: "publish-image" }])],
242
+ };
243
+ const projected = projectToJson(component) as { build: Record<string, unknown> };
244
+ expect("sbom" in projected.build).toBe(false);
245
+ });
246
+
247
+ it("supports an explicit opt-out hint", () => {
248
+ const build = { kind: "docker-build", sbom: { optOut: true } };
249
+ expect(build.sbom.optOut).toBe(true);
250
+ });
251
+ });
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Typed `Component` authoring form — Phase 2 (#560, epic #551).
3
+ *
4
+ * This is the real authoring frontend the docs (component-contract.mdx,
5
+ * composition-and-wiring.mdx) describe and that `pilots/authoring-shape.ts`
6
+ * (#555's stopgap) explicitly deferred to this issue. It mirrors
7
+ * `component.schema.json` field-for-field, so `projectToJson` stays a
8
+ * structural no-op — the interesting content lives in each component's
9
+ * composition, not in a bespoke serializer.
10
+ *
11
+ * See https://intentius.io/chant/components/component-contract/ and
12
+ * https://intentius.io/chant/components/composition-and-wiring/.
13
+ */
14
+
15
+ /** Mirrors `$defs.Archetype` in component.schema.json. */
16
+ export type Archetype = "service" | "infra" | "producer-library";
17
+
18
+ /** Mirrors `$defs.StackOutputReference`. */
19
+ export interface StackOutputReference {
20
+ stackOutput: { stack: string; name: string };
21
+ }
22
+
23
+ /**
24
+ * Mirrors `$defs.WiringValue` — a literal, or one of the reference forms
25
+ * (`$env.*`, `@Phase.field`, `@<component>.publish.uri|digest|key`, or a
26
+ * `{ stackOutput }` object), all resolved by the graph rather than by
27
+ * orchestrator code. Loosened to `string` for the literal/`$env`/prior-step/
28
+ * artifact-reference forms since they share one representation; only
29
+ * `stackOutput` needs its own shape.
30
+ */
31
+ export type Wiring = string | StackOutputReference;
32
+
33
+ /** Mirrors `$defs.BuildSpec`. */
34
+ export interface BuildSpec {
35
+ /** Build capability verb, keyed by artifact type, e.g. "docker-build", "zip-package", "jvm-build". */
36
+ kind: string;
37
+ /** Build context path (e.g. a Docker build context directory). */
38
+ context?: string;
39
+ /** Build output always lands in the self-contained BuildArchive. */
40
+ into?: "archive";
41
+ /**
42
+ * Optional component-level SBOM authoring hint (#606, epic #551 follow-up
43
+ * to #564/#568) — not itself a `generate-sbom` step (that is composed
44
+ * explicitly in `deploy`/build tooling, see
45
+ * ../verbs/sbom.ts's `GenerateSbomInput`); this is metadata an authoring
46
+ * frontend or generator can read when deciding whether/how to compose
47
+ * that step for this component. Rides `BuildSpec`'s existing
48
+ * `additionalProperties: true` in component.schema.json — no schema change
49
+ * needed for this extension.
50
+ */
51
+ sbom?: {
52
+ /** Preferred SBOM format for this component, overriding `chant.config.ts`'s project-wide `sbom.format` default (see ../../config.ts's `resolveSbomFormat`). */
53
+ format?: "spdx" | "cyclonedx";
54
+ /** Set true to skip SBOM generation for this component even where a project default would otherwise include it. `generate-sbom` is never invoked implicitly — this only documents intent for whatever composes the component's build phase. */
55
+ optOut?: boolean;
56
+ };
57
+ [extra: string]: unknown;
58
+ }
59
+
60
+ /**
61
+ * Mirrors `$defs.Step` — one capability invocation, the leaf unit of a
62
+ * composition. `kind` selects the capability (a verb, e.g. "cfn-deploy",
63
+ * "publish-image", "ecs-update-service"); the remaining properties are that
64
+ * capability's typed input. `kind: "gate"` is reserved for `Gate` below, not
65
+ * a capability — use `gate()` to author one.
66
+ */
67
+ export interface Step {
68
+ kind: string;
69
+ /** Reference to a published image digest, typically `"@Publish.digest"`. */
70
+ imageRef?: Wiring;
71
+ /** Reference to a published JAR/artifact location, e.g. `"@jar-lib.publish.uri"`. */
72
+ jar?: Wiring;
73
+ /** Reference to a published revision/bundle location for host/code-delivery capabilities. */
74
+ revision?: Wiring;
75
+ /** Named inputs passed into an apply step; each may be a literal or any wiring reference. */
76
+ inputs?: Record<string, Wiring>;
77
+ [param: string]: unknown;
78
+ }
79
+
80
+ /** Mirrors `$defs.Gate` — pauses the composition for an external signal (typically human approval). */
81
+ export interface Gate {
82
+ kind: "gate";
83
+ signalName: string;
84
+ /** Duration string bounding the wait, e.g. "48h". Default: "48h". */
85
+ timeout?: string;
86
+ /** Human-readable description of the action required to unblock this gate. */
87
+ description?: string;
88
+ }
89
+
90
+ /**
91
+ * Mirrors `$defs.Phase` — one named phase of a deploy composition. A step may
92
+ * itself be a nested `Phase`, which is how a fan-out unit becomes a mini-
93
+ * composition (see composition-and-wiring.mdx).
94
+ */
95
+ export interface Phase {
96
+ phase: string;
97
+ steps: Array<Step | Gate | Phase>;
98
+ /** Run all steps in this phase concurrently instead of sequentially. */
99
+ parallel?: boolean;
100
+ /** Compensation phases for this phase, executed in reverse order on failure. */
101
+ onFailure?: Phase[];
102
+ }
103
+
104
+ /**
105
+ * The typed `Component` authoring form — projects 1:1 to the JSON contract
106
+ * (component.schema.json). `archetype` is optional on both sides: when
107
+ * omitted here, `projectToJson` infers it structurally (see
108
+ * `inferArchetype`) so the JSON projection always carries an explicit value,
109
+ * matching how the merged fixtures are authored.
110
+ */
111
+ export interface Component {
112
+ name: string;
113
+ /** Optional explicit archetype hint; inferred from the composition shape when omitted (see `inferArchetype`). */
114
+ archetype?: Archetype;
115
+ /** Other component names that must complete before this one runs. Ordering only — no logic. */
116
+ dependsOn: string[];
117
+ /** Optional: source -> BuildArchive. Omitted entirely for config-only / infra components. */
118
+ build?: BuildSpec;
119
+ /** The component's own composition over shared capabilities. */
120
+ deploy: Phase[];
121
+ /** Optional standalone verify phases, for components that separate verification from `deploy`. */
122
+ verify?: Phase[];
123
+ /** Optional explicit compensation phases, executed in reverse order on terminal failure of `deploy`. */
124
+ rollback?: Phase[];
125
+ /**
126
+ * Optional: the live lexicon entity/resource name(s) this component owns,
127
+ * when they differ from `name` (#598). `chant components status --live`
128
+ * joins the release ledger against live evidence by name; components and
129
+ * lexicon entities are different namespaces in general (see
130
+ * `../lifecycle/status.ts`), so a component whose deploy composition
131
+ * targets an entity/resource declared under a different name must say so
132
+ * explicitly here. A component that owns several entities (e.g. a fan-out
133
+ * cluster with one stack per node) may list them all — live evidence is
134
+ * aggregated across every name. Omitted entirely (the common case for the
135
+ * pilot components) falls back to `[name]`, preserving the original
136
+ * name == entity join with no behavior change.
137
+ */
138
+ liveNames?: string[];
139
+ }
140
+
141
+ /** Author a named phase. `steps` may mix capability `Step`s, `Gate`s, and nested `Phase`s (fan-out). */
142
+ export function phase(name: string, steps: Array<Step | Gate | Phase>, opts?: { parallel?: boolean }): Phase {
143
+ return { phase: name, steps, ...(opts?.parallel ? { parallel: true } : {}) };
144
+ }
145
+
146
+ /** Author a gate step — pauses the composition for an external signal (typically human approval). */
147
+ export function gate(signalName: string, opts?: { timeout?: string; description?: string }): Gate {
148
+ return { kind: "gate", signalName, ...opts };
149
+ }
150
+
151
+ /**
152
+ * Author a cross-stack output reference — the TypeScript-side equivalent of
153
+ * the JSON contract's `{ stackOutput: { stack, name } }` (schema
154
+ * `StackOutputReference`), e.g. `stackOutput("shared-alb", "ListenerArn")`.
155
+ * Resolved by `chant graph --stacks`, never by orchestrator code.
156
+ */
157
+ export function stackOutput(stack: string, name: string): StackOutputReference {
158
+ return { stackOutput: { stack, name } };
159
+ }
160
+
161
+ /**
162
+ * Every capability-family marker `inferArchetype` looks for, grouped the same
163
+ * way component-contract.mdx's archetype table groups phases. Kept as a plain
164
+ * list (not the full starter verb set) so this module has no dependency on
165
+ * `./registry`/`./verbs` — inference is a structural, name-based heuristic
166
+ * over the composition, not a capability-registry lookup.
167
+ */
168
+ const BUILD_ONLY_HINT = new Set(["docker-build", "zip-package", "jvm-build"]);
169
+ const PUBLISH_KIND_PREFIX = /^(publish-|load-image-on-host)/;
170
+
171
+ /** True if a step's `kind` looks like a publish-family capability (`publish-image`, `publish-artifact`, `load-image-on-host`, ...). */
172
+ function isPublishStep(step: Step): boolean {
173
+ return PUBLISH_KIND_PREFIX.test(step.kind);
174
+ }
175
+
176
+ /**
177
+ * Distinguishes a nested fan-out `Phase` from a `Step`/`Gate` within a
178
+ * phase's `steps` array. `Step` carries an open index signature
179
+ * (`[param: string]: unknown`), so a plain `"phase" in s` structural check
180
+ * cannot narrow `Step` away from `Phase` — checking the concrete field types
181
+ * (`phase` is a string, `steps` is an array) here is what actually
182
+ * disambiguates them.
183
+ */
184
+ function isNestedPhase(s: Step | Gate | Phase): s is Phase {
185
+ return typeof (s as Phase).phase === "string" && Array.isArray((s as Phase).steps);
186
+ }
187
+
188
+ /** Flatten every step across every phase (including nested fan-out phases) into one list, for structural inspection. */
189
+ function allSteps(phases: Phase[]): Array<Step | Gate> {
190
+ const out: Array<Step | Gate> = [];
191
+ const walk = (ps: Phase[]) => {
192
+ for (const p of ps) {
193
+ for (const s of p.steps) {
194
+ if (isNestedPhase(s)) walk([s]);
195
+ else out.push(s);
196
+ }
197
+ if (p.onFailure) walk(p.onFailure);
198
+ }
199
+ };
200
+ walk(phases);
201
+ return out;
202
+ }
203
+
204
+ /**
205
+ * Infer a component's archetype from the shape of its composition, when no
206
+ * explicit `archetype` is authored — matching the archetype table in
207
+ * component-contract.mdx:
208
+ * - **producer-library**: has a `build`, and every step across `deploy` is a
209
+ * publish-family step (or a gate) — build -> publish only, no apply.
210
+ * - **service**: has a `build` and at least one non-publish, non-gate step
211
+ * (an apply/verify step) — build -> publish -> apply -> verify.
212
+ * - **infra**: no `build` — apply -> verify only.
213
+ *
214
+ * This is a structural heuristic, not a capability-registry lookup (see
215
+ * `BUILD_ONLY_HINT`/`isPublishStep` above): it only needs to distinguish
216
+ * "nothing but publish" from "something else happens after publish", which
217
+ * every merged pilot/fixture satisfies without consulting the registry.
218
+ */
219
+ export function inferArchetype(component: Pick<Component, "build" | "deploy">): Archetype {
220
+ if (!component.build) return "infra";
221
+
222
+ const steps = allSteps(component.deploy);
223
+ const nonGateSteps = steps.filter((s): s is Step => s.kind !== "gate");
224
+ const hasNonPublishStep = nonGateSteps.some((s) => !isPublishStep(s));
225
+
226
+ return hasNonPublishStep ? "service" : "producer-library";
227
+ }
228
+
229
+ /**
230
+ * Project a typed `Component` to its plain-JSON contract form
231
+ * (component.schema.json). Field names already match the schema 1:1, so
232
+ * projection is mechanical: a deep `JSON.parse(JSON.stringify())` round-trip
233
+ * (dropping `undefined` optional fields) plus filling in `archetype` via
234
+ * `inferArchetype` when the author didn't supply one explicitly. Kept
235
+ * intentionally dumb beyond that inference — the schema/fixtures stay the
236
+ * source of truth for shape, not this function.
237
+ */
238
+ export function projectToJson(component: Component): unknown {
239
+ const withArchetype: Component = {
240
+ ...component,
241
+ archetype: component.archetype ?? inferArchetype(component),
242
+ };
243
+ return JSON.parse(JSON.stringify(withArchetype));
244
+ }
245
+
246
+ /** Runtime type guard: true if `value` looks like a `Component` (has the required `name`/`dependsOn`/`deploy` shape). Used by discovery to pick exported `Component` values out of a `*.component.ts` module without requiring a class/marker symbol. */
247
+ export function isComponent(value: unknown): value is Component {
248
+ if (typeof value !== "object" || value === null) return false;
249
+ const v = value as Record<string, unknown>;
250
+ return (
251
+ typeof v.name === "string" &&
252
+ Array.isArray(v.dependsOn) &&
253
+ Array.isArray(v.deploy)
254
+ );
255
+ }