@intentius/chant 0.102.0 → 0.104.1

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 (471) hide show
  1. package/dist/audit/core.d.ts +2 -0
  2. package/dist/audit/core.d.ts.map +1 -1
  3. package/dist/audit/discover.d.ts.map +1 -1
  4. package/dist/change-set.d.ts +232 -0
  5. package/dist/change-set.d.ts.map +1 -0
  6. package/dist/cli/commands/audit.d.ts +7 -0
  7. package/dist/cli/commands/audit.d.ts.map +1 -1
  8. package/dist/cli/commands/build.d.ts.map +1 -1
  9. package/dist/cli/handlers/build.d.ts.map +1 -1
  10. package/dist/cli/handlers/change-set.d.ts +11 -0
  11. package/dist/cli/handlers/change-set.d.ts.map +1 -0
  12. package/dist/cli/handlers/fan-out.d.ts +33 -0
  13. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  14. package/dist/cli/handlers/operator.d.ts +7 -0
  15. package/dist/cli/handlers/operator.d.ts.map +1 -1
  16. package/dist/cli/handlers/pr.d.ts +31 -0
  17. package/dist/cli/handlers/pr.d.ts.map +1 -0
  18. package/dist/cli/handlers/run.d.ts.map +1 -1
  19. package/dist/cli/main.d.ts.map +1 -1
  20. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  21. package/dist/cli/mcp/workspace-tools.d.ts +3 -2
  22. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  23. package/dist/cli/registry.d.ts +63 -1
  24. package/dist/cli/registry.d.ts.map +1 -1
  25. package/dist/components/auto-release.d.ts +16 -0
  26. package/dist/components/auto-release.d.ts.map +1 -1
  27. package/dist/components/capability.d.ts +53 -0
  28. package/dist/components/capability.d.ts.map +1 -1
  29. package/dist/components/changed-files.d.ts +31 -0
  30. package/dist/components/changed-files.d.ts.map +1 -0
  31. package/dist/components/cli-support.d.ts +9 -1
  32. package/dist/components/cli-support.d.ts.map +1 -1
  33. package/dist/components/component.d.ts +24 -0
  34. package/dist/components/component.d.ts.map +1 -1
  35. package/dist/components/deploy-units.d.ts.map +1 -1
  36. package/dist/components/driver.d.ts +13 -0
  37. package/dist/components/driver.d.ts.map +1 -1
  38. package/dist/components/fan-out-output.d.ts +6 -0
  39. package/dist/components/fan-out-output.d.ts.map +1 -1
  40. package/dist/components/fan-out-record.d.ts +41 -0
  41. package/dist/components/fan-out-record.d.ts.map +1 -0
  42. package/dist/components/fan-out-run.d.ts +65 -0
  43. package/dist/components/fan-out-run.d.ts.map +1 -1
  44. package/dist/components/fan-out-support.d.ts +2 -0
  45. package/dist/components/fan-out-support.d.ts.map +1 -1
  46. package/dist/components/fan-out.d.ts +6 -0
  47. package/dist/components/fan-out.d.ts.map +1 -1
  48. package/dist/components/gated-wave-pipeline.d.ts +50 -0
  49. package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
  50. package/dist/components/index.d.ts +1 -1
  51. package/dist/components/index.d.ts.map +1 -1
  52. package/dist/components/layers.d.ts +25 -0
  53. package/dist/components/layers.d.ts.map +1 -0
  54. package/dist/components/pr-pipeline.d.ts +61 -0
  55. package/dist/components/pr-pipeline.d.ts.map +1 -0
  56. package/dist/components/pr-run.d.ts +119 -0
  57. package/dist/components/pr-run.d.ts.map +1 -0
  58. package/dist/components/promote.d.ts.map +1 -1
  59. package/dist/components/verbs/shell.d.ts.map +1 -1
  60. package/dist/components/wave-plan.d.ts +49 -0
  61. package/dist/components/wave-plan.d.ts.map +1 -0
  62. package/dist/gated-waves.d.ts +147 -0
  63. package/dist/gated-waves.d.ts.map +1 -0
  64. package/dist/index.d.ts +1 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/lexicon.d.ts +48 -0
  67. package/dist/lexicon.d.ts.map +1 -1
  68. package/dist/lifecycle/gate-ledger.d.ts +7 -0
  69. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  70. package/dist/lifecycle/git.d.ts +46 -1
  71. package/dist/lifecycle/git.d.ts.map +1 -1
  72. package/dist/lint/post-synth.d.ts +18 -0
  73. package/dist/lint/post-synth.d.ts.map +1 -1
  74. package/dist/op/activities/activity-contracts.d.ts +126 -0
  75. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  76. package/dist/op/activities/change-set.d.ts +62 -0
  77. package/dist/op/activities/change-set.d.ts.map +1 -0
  78. package/dist/op/activities/decide.d.ts +2 -0
  79. package/dist/op/activities/decide.d.ts.map +1 -1
  80. package/dist/op/activities/factory.d.ts +137 -0
  81. package/dist/op/activities/factory.d.ts.map +1 -0
  82. package/dist/op/activities/index.d.ts +4 -0
  83. package/dist/op/activities/index.d.ts.map +1 -1
  84. package/dist/op/activity-contract.d.ts.map +1 -1
  85. package/dist/op/builders.d.ts +11 -0
  86. package/dist/op/builders.d.ts.map +1 -1
  87. package/dist/op/decide-backend.d.ts +5 -1
  88. package/dist/op/decide-backend.d.ts.map +1 -1
  89. package/dist/op/decide-read-inputs.d.ts +4 -2
  90. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  91. package/dist/op/factory.d.ts +83 -0
  92. package/dist/op/factory.d.ts.map +1 -0
  93. package/dist/op/index.d.ts +4 -1
  94. package/dist/op/index.d.ts.map +1 -1
  95. package/dist/op/op-ir.d.ts +2 -0
  96. package/dist/op/op-ir.d.ts.map +1 -1
  97. package/dist/op/op-verb-class.d.ts.map +1 -1
  98. package/dist/op/types.d.ts +8 -0
  99. package/dist/op/types.d.ts.map +1 -1
  100. package/dist/op/work-lease-run.d.ts.map +1 -1
  101. package/dist/plan-summary.d.ts +207 -0
  102. package/dist/plan-summary.d.ts.map +1 -0
  103. package/dist/pr-forge.d.ts +105 -0
  104. package/dist/pr-forge.d.ts.map +1 -0
  105. package/dist/pr-loop.d.ts +178 -0
  106. package/dist/pr-loop.d.ts.map +1 -0
  107. package/dist/telemetry-attribution.d.ts +31 -0
  108. package/dist/telemetry-attribution.d.ts.map +1 -1
  109. package/dist/terraform/hcl2json.d.ts +45 -0
  110. package/dist/terraform/hcl2json.d.ts.map +1 -0
  111. package/dist/terraform/parse.d.ts +4 -40
  112. package/dist/terraform/parse.d.ts.map +1 -1
  113. package/dist/vendor/js-yaml-load.d.ts +56 -0
  114. package/dist/vendor/js-yaml-load.d.ts.map +1 -0
  115. package/dist/workspace/box-cli.d.ts +12 -0
  116. package/dist/workspace/box-cli.d.ts.map +1 -0
  117. package/dist/workspace/box-factory.d.ts +27 -3
  118. package/dist/workspace/box-factory.d.ts.map +1 -1
  119. package/dist/workspace/box-listing.d.ts +85 -0
  120. package/dist/workspace/box-listing.d.ts.map +1 -0
  121. package/dist/workspace/box-publish.d.ts +147 -0
  122. package/dist/workspace/box-publish.d.ts.map +1 -0
  123. package/dist/workspace/broker-protocol.d.ts +190 -0
  124. package/dist/workspace/broker-protocol.d.ts.map +1 -0
  125. package/dist/workspace/checks.d.ts.map +1 -1
  126. package/dist/workspace/composites.d.ts +2 -2
  127. package/dist/workspace/composites.d.ts.map +1 -1
  128. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
  129. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
  130. package/dist/workspace/conformance/broker.d.ts +202 -0
  131. package/dist/workspace/conformance/broker.d.ts.map +1 -0
  132. package/dist/workspace/conformance/index.d.ts +2 -1
  133. package/dist/workspace/conformance/index.d.ts.map +1 -1
  134. package/dist/workspace/conformance/vitest.d.ts +9 -2
  135. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  136. package/dist/workspace/conformance/writer.d.ts +108 -14
  137. package/dist/workspace/conformance/writer.d.ts.map +1 -1
  138. package/dist/workspace/decide.d.ts +126 -12
  139. package/dist/workspace/decide.d.ts.map +1 -1
  140. package/dist/workspace/decision-points.schema.json +11 -4
  141. package/dist/workspace/declaration.d.ts +65 -0
  142. package/dist/workspace/declaration.d.ts.map +1 -1
  143. package/dist/workspace/declaration.schema.json +153 -4
  144. package/dist/workspace/environments.d.ts +36 -10
  145. package/dist/workspace/environments.d.ts.map +1 -1
  146. package/dist/workspace/factory-rules.d.ts +180 -0
  147. package/dist/workspace/factory-rules.d.ts.map +1 -0
  148. package/dist/workspace/init.d.ts +21 -0
  149. package/dist/workspace/init.d.ts.map +1 -1
  150. package/dist/workspace/intent-cli.d.ts +1 -1
  151. package/dist/workspace/intent-cli.d.ts.map +1 -1
  152. package/dist/workspace/intent-record.d.ts +28 -1
  153. package/dist/workspace/intent-record.d.ts.map +1 -1
  154. package/dist/workspace/intent.d.ts +102 -5
  155. package/dist/workspace/intent.d.ts.map +1 -1
  156. package/dist/workspace/json-edit.d.ts +24 -0
  157. package/dist/workspace/json-edit.d.ts.map +1 -0
  158. package/dist/workspace/jsonc.d.ts +11 -0
  159. package/dist/workspace/jsonc.d.ts.map +1 -1
  160. package/dist/workspace/kinds.d.ts +48 -0
  161. package/dist/workspace/kinds.d.ts.map +1 -1
  162. package/dist/workspace/lexicon-symbols.d.ts +29 -0
  163. package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
  164. package/dist/workspace/lineage-upgrade.d.ts +31 -2
  165. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  166. package/dist/workspace/point-answer.schema.json +42 -2
  167. package/dist/workspace/points-cli.d.ts +10 -3
  168. package/dist/workspace/points-cli.d.ts.map +1 -1
  169. package/dist/workspace/points.d.ts +66 -5
  170. package/dist/workspace/points.d.ts.map +1 -1
  171. package/dist/workspace/reason-codes.d.ts +33 -4
  172. package/dist/workspace/reason-codes.d.ts.map +1 -1
  173. package/dist/workspace/record-sessions.d.ts +5 -7
  174. package/dist/workspace/record-sessions.d.ts.map +1 -1
  175. package/dist/workspace/records-cli.d.ts +7 -0
  176. package/dist/workspace/records-cli.d.ts.map +1 -1
  177. package/dist/workspace/records-close.d.ts +7 -3
  178. package/dist/workspace/records-close.d.ts.map +1 -1
  179. package/dist/workspace/records-write.d.ts +66 -6
  180. package/dist/workspace/records-write.d.ts.map +1 -1
  181. package/dist/workspace/records.d.ts +28 -9
  182. package/dist/workspace/records.d.ts.map +1 -1
  183. package/dist/workspace/runs-cli.d.ts +138 -6
  184. package/dist/workspace/runs-cli.d.ts.map +1 -1
  185. package/dist/workspace/runs.d.ts +132 -11
  186. package/dist/workspace/runs.d.ts.map +1 -1
  187. package/dist/workspace/session-kinds.d.ts +1 -1
  188. package/dist/workspace/session-kinds.d.ts.map +1 -1
  189. package/dist/workspace/squash.d.ts +80 -0
  190. package/dist/workspace/squash.d.ts.map +1 -0
  191. package/dist/workspace/status-gates.d.ts +2 -0
  192. package/dist/workspace/status-gates.d.ts.map +1 -1
  193. package/dist/workspace/status.d.ts +54 -0
  194. package/dist/workspace/status.d.ts.map +1 -1
  195. package/dist/workspace/symbols.d.ts +16 -5
  196. package/dist/workspace/symbols.d.ts.map +1 -1
  197. package/dist/workspace/trust/run-commits.d.ts +46 -0
  198. package/dist/workspace/trust/run-commits.d.ts.map +1 -0
  199. package/dist/workspace/trust/run-statement.d.ts +128 -0
  200. package/dist/workspace/trust/run-statement.d.ts.map +1 -0
  201. package/dist/workspace/trust/seal.d.ts +6 -1
  202. package/dist/workspace/trust/seal.d.ts.map +1 -1
  203. package/dist/workspace/trust/verify-cli.d.ts +1 -1
  204. package/dist/workspace/trust/verify.d.ts +16 -2
  205. package/dist/workspace/trust/verify.d.ts.map +1 -1
  206. package/dist/workspace/wip-cli.d.ts +21 -0
  207. package/dist/workspace/wip-cli.d.ts.map +1 -0
  208. package/dist/workspace/wip.d.ts +268 -0
  209. package/dist/workspace/wip.d.ts.map +1 -0
  210. package/dist/workspace/work-cli.d.ts.map +1 -1
  211. package/dist/workspace/work-evidence.d.ts +1 -1
  212. package/dist/workspace/work-evidence.d.ts.map +1 -1
  213. package/dist/workspace/work-size.d.ts +55 -0
  214. package/dist/workspace/work-size.d.ts.map +1 -0
  215. package/dist/workspace/workspace-kinds.schema.json +122 -0
  216. package/dist/workspace/write-lock-cli.d.ts +60 -0
  217. package/dist/workspace/write-lock-cli.d.ts.map +1 -0
  218. package/dist/workspace/write-lock.d.ts +152 -0
  219. package/dist/workspace/write-lock.d.ts.map +1 -0
  220. package/dist/workspace/write-scope.d.ts +6 -2
  221. package/dist/workspace/write-scope.d.ts.map +1 -1
  222. package/dist/yaml.d.ts +1 -1
  223. package/dist/yaml.d.ts.map +1 -1
  224. package/package.json +6 -1
  225. package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
  226. package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
  227. package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
  228. package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
  229. package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
  230. package/src/__fixtures__/change-set/warden.plan.json +44 -0
  231. package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
  232. package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
  233. package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
  234. package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
  235. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
  236. package/src/audit/core.test.ts +15 -0
  237. package/src/audit/core.ts +8 -2
  238. package/src/audit/discover.test.ts +11 -0
  239. package/src/audit/discover.ts +7 -2
  240. package/src/change-set-bundle.test.ts +57 -0
  241. package/src/change-set.test.ts +215 -0
  242. package/src/change-set.ts +445 -0
  243. package/src/cli/commands/audit-opt-in.test.ts +54 -0
  244. package/src/cli/commands/audit.ts +29 -2
  245. package/src/cli/commands/build.test.ts +19 -0
  246. package/src/cli/commands/build.ts +3 -2
  247. package/src/cli/handlers/build.ts +13 -1
  248. package/src/cli/handlers/change-set.test.ts +56 -0
  249. package/src/cli/handlers/change-set.ts +44 -0
  250. package/src/cli/handlers/fan-out.test.ts +221 -2
  251. package/src/cli/handlers/fan-out.ts +165 -75
  252. package/src/cli/handlers/graph.ts +3 -0
  253. package/src/cli/handlers/operator.test.ts +21 -0
  254. package/src/cli/handlers/operator.ts +34 -3
  255. package/src/cli/handlers/pr.ts +373 -0
  256. package/src/cli/handlers/run.ts +1 -0
  257. package/src/cli/main.test.ts +20 -0
  258. package/src/cli/main.ts +185 -23
  259. package/src/cli/mcp/never-over-mcp.test.ts +101 -0
  260. package/src/cli/mcp/op-tools.ts +24 -2
  261. package/src/cli/mcp/workspace-tools.test.ts +1 -1
  262. package/src/cli/mcp/workspace-tools.ts +34 -6
  263. package/src/cli/registry.ts +63 -1
  264. package/src/components/auto-release.ts +1 -1
  265. package/src/components/capability.ts +55 -0
  266. package/src/components/changed-files.ts +66 -0
  267. package/src/components/cli-support.ts +28 -5
  268. package/src/components/component.schema.json +17 -0
  269. package/src/components/component.ts +25 -0
  270. package/src/components/deploy-units.ts +3 -0
  271. package/src/components/driver.test.ts +52 -0
  272. package/src/components/driver.ts +31 -13
  273. package/src/components/fan-out-output.ts +42 -1
  274. package/src/components/fan-out-record.ts +69 -0
  275. package/src/components/fan-out-run.test.ts +17 -0
  276. package/src/components/fan-out-run.ts +304 -1
  277. package/src/components/fan-out-support.ts +3 -0
  278. package/src/components/fan-out-waves.test.ts +375 -0
  279. package/src/components/fan-out.ts +18 -17
  280. package/src/components/gated-wave-pipeline.ts +82 -0
  281. package/src/components/index.ts +1 -0
  282. package/src/components/layers.ts +30 -0
  283. package/src/components/pr-pipeline.ts +91 -0
  284. package/src/components/pr-run.test.ts +205 -0
  285. package/src/components/pr-run.ts +280 -0
  286. package/src/components/promote.ts +5 -0
  287. package/src/components/verbs/shell.test.ts +11 -0
  288. package/src/components/verbs/shell.ts +7 -3
  289. package/src/components/wave-plan.ts +124 -0
  290. package/src/discovery/sandbox/bundle.ts +1 -1
  291. package/src/gated-waves-bundle.test.ts +62 -0
  292. package/src/gated-waves.test.ts +118 -0
  293. package/src/gated-waves.ts +240 -0
  294. package/src/index.ts +1 -0
  295. package/src/lexicon.ts +51 -0
  296. package/src/lifecycle/gate-ledger.ts +7 -0
  297. package/src/lifecycle/git.ts +102 -16
  298. package/src/lint/post-synth.test.ts +19 -0
  299. package/src/lint/post-synth.ts +19 -1
  300. package/src/meta/declared-imports.test.ts +1 -1
  301. package/src/op/activities/activity-contracts.ts +84 -0
  302. package/src/op/activities/change-set.ts +114 -0
  303. package/src/op/activities/decide.ts +3 -0
  304. package/src/op/activities/factory.ts +675 -0
  305. package/src/op/activities/index.ts +6 -0
  306. package/src/op/activity-contract.test.ts +21 -1
  307. package/src/op/activity-contract.ts +19 -9
  308. package/src/op/builders.ts +23 -0
  309. package/src/op/decide-backend.ts +5 -1
  310. package/src/op/decide-read-inputs.ts +33 -5
  311. package/src/op/factory.e2e.test.ts +232 -0
  312. package/src/op/factory.ts +118 -0
  313. package/src/op/index.ts +9 -1
  314. package/src/op/op-ir.test.ts +9 -0
  315. package/src/op/op-ir.ts +4 -0
  316. package/src/op/op-verb-class.ts +3 -0
  317. package/src/op/types.ts +8 -0
  318. package/src/op/work-lease-run.ts +3 -0
  319. package/src/plan-summary.test.ts +263 -0
  320. package/src/plan-summary.ts +845 -0
  321. package/src/pr-forge.test.ts +237 -0
  322. package/src/pr-forge.ts +332 -0
  323. package/src/pr-loop-bundle.test.ts +46 -0
  324. package/src/pr-loop.test.ts +171 -0
  325. package/src/pr-loop.ts +324 -0
  326. package/src/telemetry-attribution.test.ts +23 -1
  327. package/src/telemetry-attribution.ts +51 -0
  328. package/src/terraform/hcl2json.test.ts +21 -0
  329. package/src/terraform/hcl2json.ts +81 -0
  330. package/src/terraform/parse.ts +11 -74
  331. package/src/vendor/js-yaml-load.test.ts +115 -0
  332. package/src/vendor/js-yaml-load.ts +1939 -0
  333. package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
  334. package/src/workspace/app-kind.test.ts +196 -0
  335. package/src/workspace/box-cli.ts +113 -0
  336. package/src/workspace/box-factory.test.ts +4 -1
  337. package/src/workspace/box-factory.ts +37 -4
  338. package/src/workspace/box-listing-write.schema.json +204 -0
  339. package/src/workspace/box-listing.test.ts +234 -0
  340. package/src/workspace/box-listing.ts +324 -0
  341. package/src/workspace/box-publish.schema.json +498 -0
  342. package/src/workspace/box-publish.test.ts +204 -0
  343. package/src/workspace/box-publish.ts +420 -0
  344. package/src/workspace/box-ship.test.ts +96 -0
  345. package/src/workspace/broker-protocol.schema.json +186 -0
  346. package/src/workspace/broker-protocol.test.ts +122 -0
  347. package/src/workspace/broker-protocol.ts +317 -0
  348. package/src/workspace/builder-tiers.test.ts +146 -0
  349. package/src/workspace/change-set.schema.json +460 -0
  350. package/src/workspace/chant-migrations.e2e.test.ts +17 -5
  351. package/src/workspace/checks/boxes.test.ts +3 -0
  352. package/src/workspace/checks.ts +10 -3
  353. package/src/workspace/component-environments.test.ts +105 -0
  354. package/src/workspace/composites.schema.json +23 -4
  355. package/src/workspace/composites.test.ts +8 -8
  356. package/src/workspace/composites.ts +13 -2
  357. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
  358. package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
  359. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +7 -2
  360. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +42 -2
  361. package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  362. package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  363. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +96 -0
  364. package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  365. package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  366. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +14 -8
  367. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +187 -6
  368. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +25 -0
  369. package/src/workspace/conformance/broker.test.ts +122 -0
  370. package/src/workspace/conformance/broker.ts +792 -0
  371. package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
  372. package/src/workspace/conformance/index.mjs +22 -1
  373. package/src/workspace/conformance/index.ts +5 -1
  374. package/src/workspace/conformance/vitest.ts +33 -1
  375. package/src/workspace/conformance/writer-conformance.e2e.test.ts +49 -3
  376. package/src/workspace/conformance/writer.test.ts +32 -2
  377. package/src/workspace/conformance/writer.ts +339 -28
  378. package/src/workspace/decide.test.ts +208 -4
  379. package/src/workspace/decide.ts +427 -73
  380. package/src/workspace/decision-points.schema.json +11 -4
  381. package/src/workspace/declaration.schema.json +153 -4
  382. package/src/workspace/declaration.ts +141 -0
  383. package/src/workspace/environments.ts +66 -14
  384. package/src/workspace/factory-rules.test.ts +62 -0
  385. package/src/workspace/factory-rules.ts +218 -0
  386. package/src/workspace/graph-cli.ts +2 -2
  387. package/src/workspace/graph.schema.json +67 -0
  388. package/src/workspace/identity.test.ts +23 -0
  389. package/src/workspace/init.ts +82 -2
  390. package/src/workspace/intent-cli.ts +26 -9
  391. package/src/workspace/intent-patch-id.test.ts +162 -0
  392. package/src/workspace/intent-record.schema.json +130 -3
  393. package/src/workspace/intent-record.ts +74 -28
  394. package/src/workspace/intent-reviews.test.ts +76 -0
  395. package/src/workspace/intent-squash.test.ts +213 -0
  396. package/src/workspace/intent-why.test.ts +5 -5
  397. package/src/workspace/intent.schema.json +234 -4
  398. package/src/workspace/intent.ts +260 -66
  399. package/src/workspace/json-edit.test.ts +121 -0
  400. package/src/workspace/json-edit.ts +142 -0
  401. package/src/workspace/jsonc.ts +20 -0
  402. package/src/workspace/kinds.ts +157 -2
  403. package/src/workspace/lexicon-symbols.test.ts +148 -0
  404. package/src/workspace/lexicon-symbols.ts +125 -0
  405. package/src/workspace/lineage-upgrade.test.ts +63 -0
  406. package/src/workspace/lineage-upgrade.ts +146 -5
  407. package/src/workspace/plan-summary.schema.json +155 -0
  408. package/src/workspace/point-answer.schema.json +42 -2
  409. package/src/workspace/points-cli.ts +42 -16
  410. package/src/workspace/points-write.schema.json +162 -4
  411. package/src/workspace/points.schema.json +157 -2
  412. package/src/workspace/points.test.ts +13 -1
  413. package/src/workspace/points.ts +118 -12
  414. package/src/workspace/pr-report.schema.json +95 -0
  415. package/src/workspace/profiles.test.ts +159 -0
  416. package/src/workspace/read-contract.test.ts +2 -2
  417. package/src/workspace/reason-codes.test.ts +13 -1
  418. package/src/workspace/reason-codes.ts +38 -4
  419. package/src/workspace/record-sessions.ts +9 -8
  420. package/src/workspace/records-amend.schema.json +78 -0
  421. package/src/workspace/records-cli.ts +20 -6
  422. package/src/workspace/records-close.schema.json +78 -0
  423. package/src/workspace/records-close.ts +31 -7
  424. package/src/workspace/records-concurrent.e2e.test.ts +135 -0
  425. package/src/workspace/records-concurrent.test.ts +145 -0
  426. package/src/workspace/records-formats.test.ts +46 -10
  427. package/src/workspace/records-new.schema.json +7 -0
  428. package/src/workspace/records-review.schema.json +78 -0
  429. package/src/workspace/records-sessions-write.test.ts +69 -0
  430. package/src/workspace/records-sessions.test.ts +22 -0
  431. package/src/workspace/records-write.ts +192 -25
  432. package/src/workspace/records.schema.json +16 -0
  433. package/src/workspace/records.ts +50 -9
  434. package/src/workspace/reference-kinds/app/package.json +10 -0
  435. package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  436. package/src/workspace/run-statement.schema.json +622 -0
  437. package/src/workspace/runs-cli.ts +343 -14
  438. package/src/workspace/runs-statement.test.ts +239 -0
  439. package/src/workspace/runs-write.schema.json +416 -5
  440. package/src/workspace/runs.schema.json +451 -4
  441. package/src/workspace/runs.test.ts +39 -0
  442. package/src/workspace/runs.ts +296 -35
  443. package/src/workspace/session-kinds.ts +3 -3
  444. package/src/workspace/squash.ts +198 -0
  445. package/src/workspace/status-contract.test.ts +5 -2
  446. package/src/workspace/status-gates.ts +3 -1
  447. package/src/workspace/status.schema.json +126 -3
  448. package/src/workspace/status.ts +90 -1
  449. package/src/workspace/symbols.ts +20 -9
  450. package/src/workspace/trust/run-commits.ts +115 -0
  451. package/src/workspace/trust/run-statement.ts +226 -0
  452. package/src/workspace/trust/seal.ts +8 -2
  453. package/src/workspace/trust/verify-cli.ts +6 -5
  454. package/src/workspace/trust/verify.ts +39 -6
  455. package/src/workspace/wip-cli.ts +97 -0
  456. package/src/workspace/wip-write.schema.json +504 -0
  457. package/src/workspace/wip.schema.json +334 -0
  458. package/src/workspace/wip.test.ts +294 -0
  459. package/src/workspace/wip.ts +753 -0
  460. package/src/workspace/work-cli.ts +3 -0
  461. package/src/workspace/work-evidence.schema.json +3 -0
  462. package/src/workspace/work-size.test.ts +77 -0
  463. package/src/workspace/work-size.ts +93 -0
  464. package/src/workspace/workspace-kinds.schema.json +122 -0
  465. package/src/workspace/write-lock-cli.ts +131 -0
  466. package/src/workspace/write-lock.schema.json +172 -0
  467. package/src/workspace/write-lock.test.ts +189 -0
  468. package/src/workspace/write-lock.ts +474 -0
  469. package/src/workspace/write-scope.test.ts +16 -1
  470. package/src/workspace/write-scope.ts +33 -11
  471. package/src/yaml.ts +31 -21
@@ -0,0 +1,460 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://intentius.io/chant/schemas/workspace/change-set/v1/change-set.schema.json",
4
+ "title": "change-set document",
5
+ "description": "One change set across planners (#3181): what a combined run's chant, terraform, tofu, choudoufu and warden members will change, a summary, and the digest a gate binds. Written by the composeChangeSet Op activity and by composeChangeSet in @intentius/chant/change-set. Version 1 of the workspace read contract. Readers ignore fields they do not know; a field is only ever added within a version.",
6
+ "type": "object",
7
+ "required": [
8
+ "$schema",
9
+ "contract",
10
+ "digest",
11
+ "members",
12
+ "entries",
13
+ "summary"
14
+ ],
15
+ "properties": {
16
+ "$schema": {
17
+ "const": "https://intentius.io/chant/schemas/workspace/change-set/v1/change-set.schema.json"
18
+ },
19
+ "contract": {
20
+ "const": 1
21
+ },
22
+ "chant": {
23
+ "type": "string",
24
+ "description": "The chant that composed the document."
25
+ },
26
+ "digest": {
27
+ "type": "string",
28
+ "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$",
29
+ "description": "computePlanDigest(\"change-set\", \u2026) over the members' { member, planDigest } pairs sorted by member, provisional members left out. What a gate over the whole run binds."
30
+ },
31
+ "members": {
32
+ "type": "array",
33
+ "description": "Sorted by member. Each name appears once.",
34
+ "items": {
35
+ "$ref": "#/$defs/member"
36
+ }
37
+ },
38
+ "entries": {
39
+ "type": "array",
40
+ "description": "Sorted by member, address, deposed key and action.",
41
+ "items": {
42
+ "$ref": "#/$defs/entry"
43
+ }
44
+ },
45
+ "sideEffects": {
46
+ "type": "array",
47
+ "description": "Provider-defined actions an apply runs (Terraform actions blocks), sorted by member and address. Absent when none.",
48
+ "items": {
49
+ "type": "object",
50
+ "required": ["member", "address", "type"],
51
+ "properties": {
52
+ "member": { "type": "string" },
53
+ "address": { "type": "string" },
54
+ "type": { "type": "string" },
55
+ "trigger": { "type": "string" },
56
+ "event": { "type": "string" }
57
+ }
58
+ }
59
+ },
60
+ "summary": {
61
+ "$ref": "#/$defs/summary"
62
+ }
63
+ },
64
+ "$defs": {
65
+ "member": {
66
+ "type": "object",
67
+ "required": [
68
+ "member",
69
+ "lexicon",
70
+ "planner",
71
+ "status",
72
+ "planDigest",
73
+ "holes"
74
+ ],
75
+ "properties": {
76
+ "member": {
77
+ "type": "string",
78
+ "minLength": 1,
79
+ "description": "The workspace member, or the root a set plan names."
80
+ },
81
+ "lexicon": {
82
+ "type": "string"
83
+ },
84
+ "planner": {
85
+ "enum": [
86
+ "terraform",
87
+ "tofu",
88
+ "choudoufu",
89
+ "chant",
90
+ "warden"
91
+ ]
92
+ },
93
+ "scope": {
94
+ "type": "string",
95
+ "description": "The estate, environment or org the member plans into."
96
+ },
97
+ "status": {
98
+ "enum": [
99
+ "planned",
100
+ "failed"
101
+ ]
102
+ },
103
+ "error": {
104
+ "type": "string"
105
+ },
106
+ "planDigest": {
107
+ "oneOf": [
108
+ {
109
+ "type": "string",
110
+ "pattern": "^(?:jcs1-)?sha256:[0-9a-f]{64}$"
111
+ },
112
+ {
113
+ "type": "null"
114
+ }
115
+ ],
116
+ "description": "What a gate on this member alone binds. null when it failed to plan."
117
+ },
118
+ "nativeDigest": {
119
+ "type": "string",
120
+ "description": "The planner's own digest of the same plan, such as choudoufu's per-root digest."
121
+ },
122
+ "provisional": {
123
+ "const": true,
124
+ "description": "Planned before what it reads applied, so it may hold stand-in values (a Terragrunt dependent planned on mock_outputs). Left out of the document's digest, refused by a wave's set digest, and never grouped with real plans."
125
+ },
126
+ "holes": {
127
+ "type": "array",
128
+ "description": "What the planner could not read, so the plan says nothing about it.",
129
+ "items": {
130
+ "type": "object",
131
+ "required": [
132
+ "address",
133
+ "reason"
134
+ ],
135
+ "properties": {
136
+ "address": {
137
+ "type": "string"
138
+ },
139
+ "type": {
140
+ "type": "string"
141
+ },
142
+ "reason": {
143
+ "type": "string"
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ },
150
+ "entry": {
151
+ "type": "object",
152
+ "required": [
153
+ "member",
154
+ "lexicon",
155
+ "planner",
156
+ "address",
157
+ "type",
158
+ "action",
159
+ "attributes"
160
+ ],
161
+ "properties": {
162
+ "member": {
163
+ "type": "string"
164
+ },
165
+ "lexicon": {
166
+ "type": "string"
167
+ },
168
+ "planner": {
169
+ "enum": [
170
+ "terraform",
171
+ "tofu",
172
+ "choudoufu",
173
+ "chant",
174
+ "warden"
175
+ ]
176
+ },
177
+ "address": {
178
+ "type": "string",
179
+ "description": "The planner's address, unique within the member with deposed."
180
+ },
181
+ "type": {
182
+ "type": "string"
183
+ },
184
+ "name": {
185
+ "type": "string",
186
+ "description": "The resource name without module path or index."
187
+ },
188
+ "index": {
189
+ "oneOf": [
190
+ {
191
+ "type": "string"
192
+ },
193
+ {
194
+ "type": "integer"
195
+ }
196
+ ],
197
+ "description": "A count or for_each index."
198
+ },
199
+ "module": {
200
+ "type": "string"
201
+ },
202
+ "deposed": {
203
+ "type": "string"
204
+ },
205
+ "id": {
206
+ "type": "string",
207
+ "description": "The provider's id, when the planner reports one."
208
+ },
209
+ "importing": {
210
+ "const": true,
211
+ "description": "The entry also imports the object into state; action is what else the plan does to it."
212
+ },
213
+ "action": {
214
+ "enum": [
215
+ "create",
216
+ "update",
217
+ "replace",
218
+ "delete",
219
+ "read",
220
+ "no-op",
221
+ "forget"
222
+ ]
223
+ },
224
+ "disruption": {
225
+ "enum": [
226
+ "in-place",
227
+ "rolling",
228
+ "replace",
229
+ "destroy",
230
+ "unknown"
231
+ ],
232
+ "description": "Set on update, replace and delete."
233
+ },
234
+ "region": {
235
+ "type": "string"
236
+ },
237
+ "scope": {
238
+ "type": "string"
239
+ },
240
+ "attributes": {
241
+ "type": "array",
242
+ "items": {
243
+ "$ref": "#/$defs/attribute"
244
+ }
245
+ }
246
+ }
247
+ },
248
+ "attribute": {
249
+ "type": "object",
250
+ "required": [
251
+ "path"
252
+ ],
253
+ "properties": {
254
+ "path": {
255
+ "type": "string"
256
+ },
257
+ "before": {},
258
+ "after": {},
259
+ "unknown": {
260
+ "const": true,
261
+ "description": "The value is known only after apply."
262
+ },
263
+ "sensitive": {
264
+ "const": true,
265
+ "description": "Marked sensitive: neither value is carried."
266
+ },
267
+ "forcesReplacement": {
268
+ "const": true
269
+ }
270
+ }
271
+ },
272
+ "summary": {
273
+ "type": "object",
274
+ "required": [
275
+ "members",
276
+ "entries",
277
+ "actions",
278
+ "types",
279
+ "byMember",
280
+ "deletes",
281
+ "replacements",
282
+ "failed",
283
+ "holes"
284
+ ],
285
+ "properties": {
286
+ "members": {
287
+ "type": "integer",
288
+ "minimum": 0
289
+ },
290
+ "entries": {
291
+ "type": "integer",
292
+ "minimum": 0
293
+ },
294
+ "actions": {
295
+ "type": "object",
296
+ "required": [
297
+ "create",
298
+ "update",
299
+ "replace",
300
+ "delete",
301
+ "read",
302
+ "no-op",
303
+ "forget"
304
+ ],
305
+ "properties": {
306
+ "create": {
307
+ "type": "integer",
308
+ "minimum": 0
309
+ },
310
+ "update": {
311
+ "type": "integer",
312
+ "minimum": 0
313
+ },
314
+ "replace": {
315
+ "type": "integer",
316
+ "minimum": 0
317
+ },
318
+ "delete": {
319
+ "type": "integer",
320
+ "minimum": 0
321
+ },
322
+ "read": {
323
+ "type": "integer",
324
+ "minimum": 0
325
+ },
326
+ "no-op": {
327
+ "type": "integer",
328
+ "minimum": 0
329
+ },
330
+ "forget": {
331
+ "type": "integer",
332
+ "minimum": 0
333
+ }
334
+ },
335
+ "additionalProperties": false
336
+ },
337
+ "types": {
338
+ "type": "object",
339
+ "additionalProperties": {
340
+ "type": "object",
341
+ "propertyNames": {
342
+ "enum": [
343
+ "create",
344
+ "update",
345
+ "replace",
346
+ "delete",
347
+ "read",
348
+ "no-op",
349
+ "forget"
350
+ ]
351
+ },
352
+ "additionalProperties": {
353
+ "type": "integer",
354
+ "minimum": 1
355
+ }
356
+ }
357
+ },
358
+ "byMember": {
359
+ "type": "object",
360
+ "additionalProperties": {
361
+ "type": "object",
362
+ "propertyNames": {
363
+ "enum": [
364
+ "create",
365
+ "update",
366
+ "replace",
367
+ "delete",
368
+ "read",
369
+ "no-op",
370
+ "forget"
371
+ ]
372
+ },
373
+ "additionalProperties": {
374
+ "type": "integer",
375
+ "minimum": 1
376
+ }
377
+ }
378
+ },
379
+ "deletes": {
380
+ "type": "array",
381
+ "items": {
382
+ "type": "object",
383
+ "required": [
384
+ "member",
385
+ "address",
386
+ "type"
387
+ ],
388
+ "properties": {
389
+ "member": {
390
+ "type": "string"
391
+ },
392
+ "address": {
393
+ "type": "string"
394
+ },
395
+ "type": {
396
+ "type": "string"
397
+ },
398
+ "deposed": {
399
+ "type": "string"
400
+ },
401
+ "disruption": {
402
+ "enum": [
403
+ "in-place",
404
+ "rolling",
405
+ "replace",
406
+ "destroy",
407
+ "unknown"
408
+ ]
409
+ }
410
+ }
411
+ }
412
+ },
413
+ "replacements": {
414
+ "type": "array",
415
+ "items": {
416
+ "type": "object",
417
+ "required": [
418
+ "member",
419
+ "address",
420
+ "type"
421
+ ],
422
+ "properties": {
423
+ "member": {
424
+ "type": "string"
425
+ },
426
+ "address": {
427
+ "type": "string"
428
+ },
429
+ "type": {
430
+ "type": "string"
431
+ },
432
+ "deposed": {
433
+ "type": "string"
434
+ },
435
+ "disruption": {
436
+ "enum": [
437
+ "in-place",
438
+ "rolling",
439
+ "replace",
440
+ "destroy",
441
+ "unknown"
442
+ ]
443
+ }
444
+ }
445
+ }
446
+ },
447
+ "failed": {
448
+ "type": "array",
449
+ "items": {
450
+ "type": "string"
451
+ }
452
+ },
453
+ "holes": {
454
+ "type": "integer",
455
+ "minimum": 0
456
+ }
457
+ }
458
+ }
459
+ }
460
+ }
@@ -105,14 +105,15 @@ function ledger(): GateLedgerPort & { approve(digest: string): void } {
105
105
  const passing: ChantRunner = async () => ({ exitCode: 0, output: "" });
106
106
 
107
107
  /** Stage, approve and apply the upgrade, and commit it. */
108
- async function upgrade(): Promise<void> {
108
+ async function upgrade(runChant: ChantRunner = passing): Promise<NonNullable<Awaited<ReturnType<typeof upgradeCommand>>["staged"]>> {
109
109
  const l = ledger();
110
- const first = await upgradeCommand({ root: proj, to: target(), runChant: passing, ledger: l, now: "2026-09-25T00:00:00Z" });
110
+ const first = await upgradeCommand({ root: proj, to: target(), runChant, ledger: l, now: "2026-09-25T00:00:00Z" });
111
111
  expect(first.outcome).toBe("gated");
112
112
  l.approve(first.staged!.digest);
113
- const second = await upgradeCommand({ root: proj, to: target(), runChant: passing, ledger: l, now: "2026-09-25T00:00:00Z" });
113
+ const second = await upgradeCommand({ root: proj, to: target(), runChant, ledger: l, now: "2026-09-25T00:00:00Z" });
114
114
  expect(second.outcome).toBe("applied");
115
115
  commit("chud-lexicon-exit");
116
+ return second.staged!;
116
117
  }
117
118
 
118
119
  async function makeProject(from: "dir" | "git"): Promise<void> {
@@ -763,10 +764,21 @@ describe("the migrated delivery project, with this checkout's chant", () => {
763
764
  });
764
765
 
765
766
  test("builds, lints, rebuilds its CI, stops at the ship gate, ships each approved plan to Fly and records it once, and rolls back to the previous release", { timeout: 1_800_000 }, async () => {
766
- await upgrade();
767
767
  const delivery = join(proj, "delivery");
768
- symlinkSync(join(repoRoot, "node_modules"), join(delivery, "node_modules"));
769
768
  writeFileSync(join(proj, ".git/info/exclude"), "node_modules\n");
769
+ symlinkSync(join(repoRoot, "node_modules"), join(delivery, "node_modules"));
770
+ // The template's ci.yml was built by the chant of 84c8b21 (actions/checkout@v4). The upgrade rebuilds it with
771
+ // this chant (#3244), so its ci:check passes without anyone running ci:build: build and lint stay stubbed,
772
+ // and the workflow rebuild runs this checkout's chant.
773
+ expect(read(proj, ".github/workflows/ci.yml")).toContain("actions/checkout@v4");
774
+ const rebuilding: ChantRunner = async (command, cwd, args) => {
775
+ if (!args?.length) return passing(command, cwd);
776
+ const r = await chant(cwd, {}, command, ...args);
777
+ return { exitCode: r.status ?? 1, output: r.out };
778
+ };
779
+ const staged = await upgrade(rebuilding);
780
+ expect(staged.workflows).toEqual([expect.objectContaining({ member: "delivery", script: "ci:build", path: ".github/workflows/ci.yml", status: "rebuilt" })]);
781
+ expect(read(proj, ".github/workflows/ci.yml")).not.toContain("actions/checkout@v4");
770
782
  const fly = await flaps(join(root, "fly"));
771
783
  const env = { FLY_FLAPS_BASE_URL: fly.endpoint, FLY_API_TOKEN: "test", CHUD_FLY_APP_SECRET: "s3cret", GITHUB_ACTOR: "releaser" };
772
784
  /** The Machine's app over HTTP, on the host port its service is published on. */
@@ -160,6 +160,9 @@ describe("the box block in the declaration", () => {
160
160
  services: [],
161
161
  factory: null,
162
162
  listing: null,
163
+ publisher: null,
164
+ ship: null,
165
+ replicate: null,
163
166
  capabilities: [
164
167
  { name: "fountain", broker: "lobby", scope: ["agent", "vault"], pointer: "/members/0/box/capabilities/0" },
165
168
  { name: "inference", broker: null, scope: [], pointer: "/members/0/box/capabilities/1" },
@@ -45,7 +45,7 @@ import type { PostSynthDiagnostic } from "../lint/post-synth";
45
45
  import { readDeclaration, resolveGroups, WorkspaceReadError, type Declaration, type Entry, type ErrorLocation, type ResolvedGroup } from "./declaration";
46
46
  import type { ReasonCode } from "./reason-codes";
47
47
  import { parseJsonText, pointerToken, type TextLocation } from "./jsonc";
48
- import { loadKindRegistry, probeKind, resolveKind, type KindLoadProblem, type KindRegistry } from "./kinds";
48
+ import { loadKindRegistry, probeKind, resolveKind, resolveMemberFields, type KindLoadProblem, type KindRegistry } from "./kinds";
49
49
  import { coreClassRegistry, loadClassRegistry, unknownScopeClasses, type ClassRegistry } from "./principal-classes";
50
50
  import { gitTop, workingTree, type WorkspaceTree } from "./tree";
51
51
  import { LINK_CHECKS, linkTable } from "./checks/links";
@@ -239,13 +239,20 @@ export const WORKSPACE_CHECKS: readonly WorkspaceCheck[] = [
239
239
  {
240
240
  id: "WSP005",
241
241
  name: "kind-probe-failed",
242
- description: "Every member's directory is what its kind reads, such as a chant config for a chant member.",
242
+ description: "Every member's directory is what its kind reads, such as a chant config for a chant member, and its fields are ones its kind declares, of the declared types (#3151).",
243
243
  severity: "error",
244
244
  configurable: true,
245
245
  check(ctx) {
246
- return readableMembers(ctx)
246
+ const probes = readableMembers(ctx)
247
247
  .filter((m) => !probeKind(ctx.kinds.get(m.kind)!, ctx.tree, memberDir(m.dir)))
248
248
  .map((m) => entryFinding(this, m, "kind", `member ${m.name} (${m.dir}) is not ${ctx.kinds.get(m.kind)!.description}`));
249
+ // A member's fields (#3151): checked whether or not its directory exists, since they are the entry's own.
250
+ const fields = ctx.declaration.members.flatMap((m) =>
251
+ resolveMemberFields(ctx.kinds.get(m.kind), m.fields).problems.map((p) =>
252
+ entryFinding(this, m, p.path === "" ? "fields" : `fields/${p.path.split("/").map(pointerToken).join("/")}`, `member ${m.name}: ${p.message}`),
253
+ ),
254
+ );
255
+ return [...probes, ...fields];
249
256
  },
250
257
  },
251
258
  {
@@ -0,0 +1,105 @@
1
+ /**
2
+ * #3153, ws-095: a component declares where each release goes, by
3
+ * environment (the runtime that hosts it, its URL, a custom domain and the
4
+ * git remote its lifecycle records go to), replacing studio's
5
+ * `studio.sites` key in delivery's chant.config.ts. The contract validates
6
+ * it, `chant graph --components` carries it, and `graph --composites` lists
7
+ * each environment with its site.
8
+ */
9
+
10
+ import { mkdir, rm, writeFile } from "node:fs/promises";
11
+ import { tmpdir } from "node:os";
12
+ import { join } from "node:path";
13
+ import Ajv2020 from "ajv/dist/2020";
14
+ import { afterEach, beforeEach, describe, expect, test } from "vitest";
15
+ import { computeComponentGraph } from "../components/cli-support";
16
+ import componentSchema from "../components/component.schema.json";
17
+ import { componentEnvironments, memberEnvironments, type EnvironmentReason } from "./environments";
18
+ import type { MemberRuntimes } from "./runtimes";
19
+
20
+ const runtimes = (environments: MemberRuntimes["environments"], lexicons: string[] = []): MemberRuntimes => ({ lexicons, default: "local", reasons: [], environments });
21
+
22
+ const SITES = [
23
+ { name: "prod", runtime: "local" },
24
+ { name: "fly", runtime: "fly", lifecycle: "origin", url: "https://shop.fly.dev", domain: "shop.example.com" },
25
+ ];
26
+
27
+ describe("a component's environments in the contract (#3153)", () => {
28
+ const validate = new Ajv2020({ strict: false }).compile(componentSchema);
29
+ const base = { name: "app", dependsOn: [], deploy: [{ phase: "Apply", steps: [{ kind: "cfn-deploy" }] }] };
30
+
31
+ test("are optional, each a name with an optional runtime, url, domain and lifecycle", () => {
32
+ expect(validate(base)).toBe(true);
33
+ expect(validate({ ...base, environments: SITES })).toBe(true);
34
+ });
35
+
36
+ test("refuse an empty list, an entry with no name, a url that isn't http and a field nobody reads", () => {
37
+ expect(validate({ ...base, environments: [] })).toBe(false);
38
+ expect(validate({ ...base, environments: [{ runtime: "fly" }] })).toBe(false);
39
+ expect(validate({ ...base, environments: [{ name: "fly", url: "shop.fly.dev" }] })).toBe(false);
40
+ expect(validate({ ...base, environments: [{ name: "fly", region: "ams" }] })).toBe(false);
41
+ });
42
+ });
43
+
44
+ describe("chant graph --components carries them (#3153)", () => {
45
+ let dir: string;
46
+ beforeEach(async () => {
47
+ dir = join(tmpdir(), `chant-3153-${Date.now()}-${Math.random()}`);
48
+ await mkdir(dir, { recursive: true });
49
+ });
50
+ afterEach(async () => {
51
+ await rm(dir, { recursive: true, force: true });
52
+ });
53
+
54
+ test("for a component that declares them, and not for one that doesn't", async () => {
55
+ await writeFile(
56
+ join(dir, "app.component.ts"),
57
+ `export const app = { name: "app", dependsOn: [], environments: ${JSON.stringify(SITES)}, deploy: [{ phase: "Apply", steps: [{ kind: "cfn-deploy" }] }] };\n` +
58
+ `export const db = { name: "db", dependsOn: [], deploy: [{ phase: "Apply", steps: [{ kind: "cfn-deploy" }] }] };\n`,
59
+ );
60
+ const graph = await computeComponentGraph(dir);
61
+ expect(graph.success, graph.error).toBe(true);
62
+ expect(graph.environments).toEqual({ app: SITES });
63
+ });
64
+ });
65
+
66
+ describe("graph --composites lists each environment with the component's site (#3153)", () => {
67
+ test("an environment the config names takes the site, and the command runs on the site's runtime when the member hosts it", () => {
68
+ const member = memberEnvironments(runtimes(["prod", "fly"], ["fly"]), { envs: [], reason: null });
69
+ const envs = componentEnvironments("app", member, "local", SITES, ["fly"]);
70
+ expect(envs).toEqual([
71
+ { name: "local", default: true, source: "builtin", site: null, command: "chant run --components app" },
72
+ { name: "prod", default: false, source: "config", site: { runtime: "local", url: null, domain: null, lifecycle: null }, command: "chant run --components app --env prod" },
73
+ {
74
+ name: "fly",
75
+ default: false,
76
+ source: "config",
77
+ site: { runtime: "fly", url: "https://shop.fly.dev", domain: "shop.example.com", lifecycle: "origin" },
78
+ command: "chant run --components app --on fly --env fly",
79
+ },
80
+ ]);
81
+ });
82
+
83
+ test("a site whose runtime the member doesn't host runs on the default runtime", () => {
84
+ const member = memberEnvironments(runtimes(["fly"]), { envs: [], reason: null });
85
+ const fly = componentEnvironments("app", member, "local", SITES, []).find((e) => e.name === "fly")!;
86
+ expect(fly.command).toBe("chant run --components app --env fly");
87
+ expect(fly.site?.runtime).toBe("fly");
88
+ });
89
+
90
+ test("an environment only the component names is added when the config declares none, and left out with a reason when the config doesn't cover it", () => {
91
+ const open = memberEnvironments(runtimes([]), { envs: [], reason: null });
92
+ expect(componentEnvironments("app", open, "local", SITES).map((e) => `${e.name}:${e.source}`)).toEqual(["local:builtin", "prod:component", "fly:component"]);
93
+
94
+ const reasons: EnvironmentReason[] = [];
95
+ const closed = memberEnvironments(runtimes(["prod"]), { envs: [], reason: null });
96
+ expect(componentEnvironments("app", closed, "local", SITES, [], reasons).map((e) => e.name)).toEqual(["local", "prod"]);
97
+ expect(reasons).toEqual([{ code: "environments-component-undeclared", message: expect.stringMatching(/component app declares environment fly/) }]);
98
+ });
99
+
100
+ test("a pattern in the config covers a declared name", () => {
101
+ const member = memberEnvironments(runtimes(["pr-*"]), { envs: [], reason: null });
102
+ const envs = componentEnvironments("app", member, "local", [{ name: "pr-7", url: "https://pr-7.example.com" }]);
103
+ expect(envs.find((e) => e.name === "pr-7")).toMatchObject({ source: "component", site: { url: "https://pr-7.example.com" } });
104
+ });
105
+ });