@intentius/chant 0.79.0 → 0.81.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 (462) hide show
  1. package/dist/audit/core.d.ts.map +1 -1
  2. package/dist/audit/discover.d.ts +30 -0
  3. package/dist/audit/discover.d.ts.map +1 -1
  4. package/dist/audit/report-html.d.ts +5 -0
  5. package/dist/audit/report-html.d.ts.map +1 -1
  6. package/dist/audit/report-model.d.ts +13 -0
  7. package/dist/audit/report-model.d.ts.map +1 -1
  8. package/dist/audit/terraform-state.d.ts +13 -0
  9. package/dist/audit/terraform-state.d.ts.map +1 -1
  10. package/dist/cli/command-group.d.ts +6 -0
  11. package/dist/cli/command-group.d.ts.map +1 -1
  12. package/dist/cli/commands/audit.d.ts +44 -3
  13. package/dist/cli/commands/audit.d.ts.map +1 -1
  14. package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
  15. package/dist/cli/commands/check-lexicon.d.ts +8 -0
  16. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  17. package/dist/cli/commands/doctor.d.ts.map +1 -1
  18. package/dist/cli/commands/import-agents.d.ts.map +1 -1
  19. package/dist/cli/commands/init.d.ts +6 -0
  20. package/dist/cli/commands/init.d.ts.map +1 -1
  21. package/dist/cli/commands/lint.d.ts.map +1 -1
  22. package/dist/cli/commands/onboard.d.ts.map +1 -1
  23. package/dist/cli/commands/update.d.ts +6 -0
  24. package/dist/cli/commands/update.d.ts.map +1 -1
  25. package/dist/cli/commands/vendor.d.ts +5 -0
  26. package/dist/cli/commands/vendor.d.ts.map +1 -1
  27. package/dist/cli/conflict-check.d.ts +6 -0
  28. package/dist/cli/conflict-check.d.ts.map +1 -1
  29. package/dist/cli/handlers/build.d.ts.map +1 -1
  30. package/dist/cli/handlers/components.d.ts.map +1 -1
  31. package/dist/cli/handlers/dev.d.ts.map +1 -1
  32. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  33. package/dist/cli/handlers/init.d.ts.map +1 -1
  34. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  35. package/dist/cli/handlers/misc.d.ts.map +1 -1
  36. package/dist/cli/handlers/operator.d.ts +7 -0
  37. package/dist/cli/handlers/operator.d.ts.map +1 -1
  38. package/dist/cli/handlers/promote.d.ts +20 -0
  39. package/dist/cli/handlers/promote.d.ts.map +1 -0
  40. package/dist/cli/handlers/run-generate.d.ts +39 -0
  41. package/dist/cli/handlers/run-generate.d.ts.map +1 -0
  42. package/dist/cli/handlers/run.d.ts +4 -1
  43. package/dist/cli/handlers/run.d.ts.map +1 -1
  44. package/dist/cli/handlers/vendor.d.ts +8 -3
  45. package/dist/cli/handlers/vendor.d.ts.map +1 -1
  46. package/dist/cli/main.d.ts +12 -0
  47. package/dist/cli/main.d.ts.map +1 -1
  48. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  49. package/dist/cli/plugins.d.ts +14 -0
  50. package/dist/cli/plugins.d.ts.map +1 -1
  51. package/dist/cli/registry.d.ts +46 -1
  52. package/dist/cli/registry.d.ts.map +1 -1
  53. package/dist/codegen/fetch.d.ts +10 -0
  54. package/dist/codegen/fetch.d.ts.map +1 -1
  55. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  56. package/dist/components/cli-support.d.ts +3 -1
  57. package/dist/components/cli-support.d.ts.map +1 -1
  58. package/dist/components/discover.d.ts.map +1 -1
  59. package/dist/components/driver.d.ts +16 -2
  60. package/dist/components/driver.d.ts.map +1 -1
  61. package/dist/components/fan-out-support.d.ts.map +1 -1
  62. package/dist/components/gate-plan.d.ts +40 -0
  63. package/dist/components/gate-plan.d.ts.map +1 -0
  64. package/dist/components/pilots/alb-ecs.pilot.d.ts +7 -1
  65. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -1
  66. package/dist/components/presets/ecs-fargate.d.ts +10 -4
  67. package/dist/components/presets/ecs-fargate.d.ts.map +1 -1
  68. package/dist/components/promote.d.ts +264 -0
  69. package/dist/components/promote.d.ts.map +1 -0
  70. package/dist/components/sandbox/driver.d.ts.map +1 -1
  71. package/dist/components/sandbox/run.d.ts.map +1 -1
  72. package/dist/components/verbs/build-archive.d.ts +22 -11
  73. package/dist/components/verbs/build-archive.d.ts.map +1 -1
  74. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  75. package/dist/config-static.d.ts +59 -0
  76. package/dist/config-static.d.ts.map +1 -0
  77. package/dist/config.d.ts +104 -5
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/content-digest.d.ts +17 -0
  80. package/dist/content-digest.d.ts.map +1 -0
  81. package/dist/discovery/files.d.ts +48 -4
  82. package/dist/discovery/files.d.ts.map +1 -1
  83. package/dist/discovery/fold-import.d.ts +32 -1
  84. package/dist/discovery/fold-import.d.ts.map +1 -1
  85. package/dist/discovery/index.d.ts.map +1 -1
  86. package/dist/discovery/sandbox/driver.d.ts +20 -0
  87. package/dist/discovery/sandbox/driver.d.ts.map +1 -1
  88. package/dist/discovery/sandbox/fork.d.ts +20 -0
  89. package/dist/discovery/sandbox/fork.d.ts.map +1 -1
  90. package/dist/discovery/walk.d.ts +119 -0
  91. package/dist/discovery/walk.d.ts.map +1 -0
  92. package/dist/graph-ir.d.ts +17 -1
  93. package/dist/graph-ir.d.ts.map +1 -1
  94. package/dist/join-key.d.ts +31 -0
  95. package/dist/join-key.d.ts.map +1 -0
  96. package/dist/lexicon-module.d.ts +110 -0
  97. package/dist/lexicon-module.d.ts.map +1 -0
  98. package/dist/lexicon.d.ts +82 -1
  99. package/dist/lexicon.d.ts.map +1 -1
  100. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -1
  101. package/dist/lifecycle/digest.d.ts +5 -1
  102. package/dist/lifecycle/digest.d.ts.map +1 -1
  103. package/dist/lifecycle/gate-ledger.d.ts +20 -5
  104. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  105. package/dist/lifecycle/git.d.ts +64 -0
  106. package/dist/lifecycle/git.d.ts.map +1 -1
  107. package/dist/lifecycle/lease.d.ts +8 -1
  108. package/dist/lifecycle/lease.d.ts.map +1 -1
  109. package/dist/lifecycle/legacy-digest.d.ts +59 -0
  110. package/dist/lifecycle/legacy-digest.d.ts.map +1 -0
  111. package/dist/lifecycle/member-ledger.d.ts +67 -0
  112. package/dist/lifecycle/member-ledger.d.ts.map +1 -0
  113. package/dist/lifecycle/plan-digest.d.ts +4 -3
  114. package/dist/lifecycle/plan-digest.d.ts.map +1 -1
  115. package/dist/lifecycle/release-ledger.d.ts +42 -1
  116. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  117. package/dist/lifecycle/status.d.ts +90 -5
  118. package/dist/lifecycle/status.d.ts.map +1 -1
  119. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +2 -3
  120. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -1
  121. package/dist/op/activities/activity-contracts.d.ts +32 -0
  122. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  123. package/dist/op/activities/index.d.ts +2 -0
  124. package/dist/op/activities/index.d.ts.map +1 -1
  125. package/dist/op/activities/propose-upgrade.d.ts +75 -0
  126. package/dist/op/activities/propose-upgrade.d.ts.map +1 -0
  127. package/dist/op/activity-contract-registry.d.ts.map +1 -1
  128. package/dist/op/activity-registry.d.ts.map +1 -1
  129. package/dist/op/discover.d.ts.map +1 -1
  130. package/dist/op/gate-approval.d.ts.map +1 -1
  131. package/dist/op/gate-name.d.ts +7 -0
  132. package/dist/op/gate-name.d.ts.map +1 -1
  133. package/dist/op/gate-summary.d.ts +16 -0
  134. package/dist/op/gate-summary.d.ts.map +1 -1
  135. package/dist/op/gate.d.ts +16 -2
  136. package/dist/op/gate.d.ts.map +1 -1
  137. package/dist/op/generate-pipeline.d.ts.map +1 -1
  138. package/dist/op/runtimes/local.d.ts.map +1 -1
  139. package/dist/project-root.d.ts +26 -0
  140. package/dist/project-root.d.ts.map +1 -1
  141. package/dist/workspace/__fixtures__/contract-repo.d.ts +37 -0
  142. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -0
  143. package/dist/workspace/__fixtures__/two-member-workspace.d.ts +11 -0
  144. package/dist/workspace/__fixtures__/two-member-workspace.d.ts.map +1 -0
  145. package/dist/workspace/checks/generated.d.ts +156 -0
  146. package/dist/workspace/checks/generated.d.ts.map +1 -0
  147. package/dist/workspace/checks/ledgers.d.ts +78 -0
  148. package/dist/workspace/checks/ledgers.d.ts.map +1 -0
  149. package/dist/workspace/checks/links.d.ts +25 -0
  150. package/dist/workspace/checks/links.d.ts.map +1 -0
  151. package/dist/workspace/checks/pipelines.d.ts +76 -0
  152. package/dist/workspace/checks/pipelines.d.ts.map +1 -0
  153. package/dist/workspace/checks.d.ts +161 -0
  154. package/dist/workspace/checks.d.ts.map +1 -0
  155. package/dist/workspace/compose-graph.d.ts +115 -0
  156. package/dist/workspace/compose-graph.d.ts.map +1 -0
  157. package/dist/workspace/compose-reports.d.ts +68 -0
  158. package/dist/workspace/compose-reports.d.ts.map +1 -0
  159. package/dist/workspace/declaration.d.ts +220 -0
  160. package/dist/workspace/declaration.d.ts.map +1 -0
  161. package/dist/workspace/declaration.schema.json +434 -0
  162. package/dist/workspace/generated-files.d.ts +65 -0
  163. package/dist/workspace/generated-files.d.ts.map +1 -0
  164. package/dist/workspace/glob.d.ts +13 -0
  165. package/dist/workspace/glob.d.ts.map +1 -0
  166. package/dist/workspace/graph-cli.d.ts +75 -0
  167. package/dist/workspace/graph-cli.d.ts.map +1 -0
  168. package/dist/workspace/init.d.ts +96 -0
  169. package/dist/workspace/init.d.ts.map +1 -0
  170. package/dist/workspace/jsonc.d.ts +38 -0
  171. package/dist/workspace/jsonc.d.ts.map +1 -0
  172. package/dist/workspace/kinds.d.ts +192 -0
  173. package/dist/workspace/kinds.d.ts.map +1 -0
  174. package/dist/workspace/lineage-check.d.ts +84 -0
  175. package/dist/workspace/lineage-check.d.ts.map +1 -0
  176. package/dist/workspace/lineage-cli.d.ts +31 -0
  177. package/dist/workspace/lineage-cli.d.ts.map +1 -0
  178. package/dist/workspace/lineage-init.d.ts +101 -0
  179. package/dist/workspace/lineage-init.d.ts.map +1 -0
  180. package/dist/workspace/lineage-lock.d.ts +258 -0
  181. package/dist/workspace/lineage-lock.d.ts.map +1 -0
  182. package/dist/workspace/lineage-merge.d.ts +14 -0
  183. package/dist/workspace/lineage-merge.d.ts.map +1 -0
  184. package/dist/workspace/lineage-migrations.d.ts +178 -0
  185. package/dist/workspace/lineage-migrations.d.ts.map +1 -0
  186. package/dist/workspace/lineage-update.d.ts +59 -0
  187. package/dist/workspace/lineage-update.d.ts.map +1 -0
  188. package/dist/workspace/lineage-upgrade-cli.d.ts +40 -0
  189. package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -0
  190. package/dist/workspace/lineage-upgrade.d.ts +146 -0
  191. package/dist/workspace/lineage-upgrade.d.ts.map +1 -0
  192. package/dist/workspace/lineage-vendor.d.ts +63 -0
  193. package/dist/workspace/lineage-vendor.d.ts.map +1 -0
  194. package/dist/workspace/lineage-version.d.ts +32 -0
  195. package/dist/workspace/lineage-version.d.ts.map +1 -0
  196. package/dist/workspace/links.d.ts +150 -0
  197. package/dist/workspace/links.d.ts.map +1 -0
  198. package/dist/workspace/ls.d.ts +99 -0
  199. package/dist/workspace/ls.d.ts.map +1 -0
  200. package/dist/workspace/member-commands.d.ts +139 -0
  201. package/dist/workspace/member-commands.d.ts.map +1 -0
  202. package/dist/workspace/member-handles.d.ts +54 -0
  203. package/dist/workspace/member-handles.d.ts.map +1 -0
  204. package/dist/workspace/member-pipeline.d.ts +143 -0
  205. package/dist/workspace/member-pipeline.d.ts.map +1 -0
  206. package/dist/workspace/member-run.d.ts +67 -0
  207. package/dist/workspace/member-run.d.ts.map +1 -0
  208. package/dist/workspace/reason-codes.d.ts +65 -0
  209. package/dist/workspace/reason-codes.d.ts.map +1 -0
  210. package/dist/workspace/record-source.d.ts +22 -0
  211. package/dist/workspace/record-source.d.ts.map +1 -0
  212. package/dist/workspace/records-cli.d.ts +81 -0
  213. package/dist/workspace/records-cli.d.ts.map +1 -0
  214. package/dist/workspace/records.d.ts +118 -0
  215. package/dist/workspace/records.d.ts.map +1 -0
  216. package/dist/workspace/root-refusal.d.ts +53 -0
  217. package/dist/workspace/root-refusal.d.ts.map +1 -0
  218. package/dist/workspace/status.d.ts +150 -0
  219. package/dist/workspace/status.d.ts.map +1 -0
  220. package/dist/workspace/template-manifest.d.ts +90 -0
  221. package/dist/workspace/template-manifest.d.ts.map +1 -0
  222. package/dist/workspace/tree.d.ts +36 -0
  223. package/dist/workspace/tree.d.ts.map +1 -0
  224. package/dist/workspace/trust/attestor.d.ts +67 -0
  225. package/dist/workspace/trust/attestor.d.ts.map +1 -0
  226. package/dist/workspace/trust/policy.d.ts +111 -0
  227. package/dist/workspace/trust/policy.d.ts.map +1 -0
  228. package/dist/workspace/trust/provenance.d.ts +67 -0
  229. package/dist/workspace/trust/provenance.d.ts.map +1 -0
  230. package/dist/workspace/trust/ssh-commit.d.ts +43 -0
  231. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -0
  232. package/dist/workspace/trust/test-repo.d.ts +42 -0
  233. package/dist/workspace/trust/test-repo.d.ts.map +1 -0
  234. package/dist/workspace/trust/verify-cli.d.ts +9 -0
  235. package/dist/workspace/trust/verify-cli.d.ts.map +1 -0
  236. package/dist/workspace/trust/verify.d.ts +66 -0
  237. package/dist/workspace/trust/verify.d.ts.map +1 -0
  238. package/dist/workspace/which-chant.d.ts +58 -0
  239. package/dist/workspace/which-chant.d.ts.map +1 -0
  240. package/dist/workspace/workspace-kinds.schema.json +133 -0
  241. package/package.json +4 -3
  242. package/src/audit/core.ts +13 -2
  243. package/src/audit/discover.ts +102 -36
  244. package/src/audit/report-html.ts +3 -1
  245. package/src/audit/report-model.ts +14 -1
  246. package/src/audit/terraform-state.test.ts +81 -1
  247. package/src/audit/terraform-state.ts +25 -0
  248. package/src/cli/command-group.ts +7 -0
  249. package/src/cli/commands/audit-truncation.test.ts +167 -0
  250. package/src/cli/commands/audit.ts +132 -29
  251. package/src/cli/commands/check-lexicon-examples.ts +2 -1
  252. package/src/cli/commands/check-lexicon.ts +24 -0
  253. package/src/cli/commands/doctor.test.ts +30 -0
  254. package/src/cli/commands/doctor.ts +21 -0
  255. package/src/cli/commands/import-agents.ts +15 -4
  256. package/src/cli/commands/init.ts +76 -25
  257. package/src/cli/commands/lint.test.ts +52 -1
  258. package/src/cli/commands/lint.ts +41 -71
  259. package/src/cli/commands/onboard.ts +15 -0
  260. package/src/cli/commands/update.ts +18 -5
  261. package/src/cli/commands/vendor.ts +11 -6
  262. package/src/cli/conflict-check.test.ts +18 -1
  263. package/src/cli/conflict-check.ts +13 -0
  264. package/src/cli/discovery-skip.test.ts +168 -0
  265. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +38 -0
  266. package/src/cli/handlers/build-member.test.ts +127 -0
  267. package/src/cli/handlers/build.test.ts +11 -0
  268. package/src/cli/handlers/build.ts +35 -1
  269. package/src/cli/handlers/components.test.ts +127 -0
  270. package/src/cli/handlers/components.ts +70 -8
  271. package/src/cli/handlers/dev.ts +6 -1
  272. package/src/cli/handlers/fan-out.ts +9 -2
  273. package/src/cli/handlers/graph.test.ts +20 -0
  274. package/src/cli/handlers/graph.ts +4 -2
  275. package/src/cli/handlers/init.ts +54 -1
  276. package/src/cli/handlers/lifecycle.ts +2 -1
  277. package/src/cli/handlers/misc.ts +16 -0
  278. package/src/cli/handlers/operator.test.ts +68 -0
  279. package/src/cli/handlers/operator.ts +39 -10
  280. package/src/cli/handlers/promote.test.ts +377 -0
  281. package/src/cli/handlers/promote.ts +391 -0
  282. package/src/cli/handlers/run-generate-member.test.ts +83 -0
  283. package/src/cli/handlers/run-generate.test.ts +158 -0
  284. package/src/cli/handlers/run-generate.ts +168 -0
  285. package/src/cli/handlers/run.test.ts +47 -0
  286. package/src/cli/handlers/run.ts +41 -6
  287. package/src/cli/handlers/vendor.ts +147 -43
  288. package/src/cli/main.test.ts +137 -1
  289. package/src/cli/main.ts +290 -24
  290. package/src/cli/mcp/op-tools.ts +2 -1
  291. package/src/cli/path-lexicon-messages.test.ts +152 -0
  292. package/src/cli/plugins.ts +43 -5
  293. package/src/cli/registry.ts +46 -1
  294. package/src/cli/static-config-read.test.ts +208 -0
  295. package/src/codegen/fetch.test.ts +63 -1
  296. package/src/codegen/fetch.ts +30 -1
  297. package/src/components/__fixtures__/alb-ecs-service.json +0 -8
  298. package/src/components/capability-plugin-loader.ts +3 -1
  299. package/src/components/cli-support.ts +9 -3
  300. package/src/components/discover.test.ts +27 -57
  301. package/src/components/discover.ts +20 -51
  302. package/src/components/driver.test.ts +90 -12
  303. package/src/components/driver.ts +43 -5
  304. package/src/components/fan-out-support.ts +2 -1
  305. package/src/components/gate-plan.ts +53 -0
  306. package/src/components/pilots/README.md +1 -1
  307. package/src/components/pilots/alb-ecs.pilot.ts +7 -7
  308. package/src/components/presets/ecs-fargate.ts +10 -5
  309. package/src/components/promote.test.ts +645 -0
  310. package/src/components/promote.ts +641 -0
  311. package/src/components/sandbox/driver.ts +8 -8
  312. package/src/components/sandbox/run.ts +4 -1
  313. package/src/components/verbs/build-archive.ts +27 -21
  314. package/src/components/verbs/run-agent.ts +3 -5
  315. package/src/config-static.test.ts +136 -0
  316. package/src/config-static.ts +232 -0
  317. package/src/config.test.ts +40 -0
  318. package/src/config.ts +161 -11
  319. package/src/content-digest.test.ts +120 -0
  320. package/src/content-digest.ts +21 -0
  321. package/src/discovery/files.test.ts +127 -1
  322. package/src/discovery/files.ts +91 -59
  323. package/src/discovery/fold-import.ts +127 -9
  324. package/src/discovery/index.ts +1 -0
  325. package/src/discovery/sandbox/driver.ts +73 -35
  326. package/src/discovery/sandbox/fork-diagnostic.test.ts +136 -13
  327. package/src/discovery/sandbox/fork.ts +83 -43
  328. package/src/discovery/sandbox/path-lexicon-multifile.test.ts +285 -0
  329. package/src/discovery/sandbox/path-lexicon-parity.test.ts +162 -0
  330. package/src/discovery/walk.test.ts +263 -0
  331. package/src/discovery/walk.ts +334 -0
  332. package/src/effect-receipt.ts +2 -2
  333. package/src/graph-ir.ts +18 -1
  334. package/src/join-key.test.ts +25 -0
  335. package/src/join-key.ts +39 -0
  336. package/src/lexicon-module.test.ts +203 -0
  337. package/src/lexicon-module.ts +215 -0
  338. package/src/lexicon.ts +105 -1
  339. package/src/lifecycle/build-ledger-store.ts +13 -2
  340. package/src/lifecycle/digest.ts +9 -5
  341. package/src/lifecycle/gate-ledger.test.ts +20 -0
  342. package/src/lifecycle/gate-ledger.ts +28 -6
  343. package/src/lifecycle/git.test.ts +13 -1
  344. package/src/lifecycle/git.ts +221 -176
  345. package/src/lifecycle/lease.ts +25 -10
  346. package/src/lifecycle/legacy-digest.test.ts +206 -0
  347. package/src/lifecycle/legacy-digest.ts +103 -0
  348. package/src/lifecycle/member-ledger.test.ts +319 -0
  349. package/src/lifecycle/member-ledger.ts +145 -0
  350. package/src/lifecycle/plan-digest.ts +7 -7
  351. package/src/lifecycle/release-ledger.test.ts +20 -0
  352. package/src/lifecycle/release-ledger.ts +53 -3
  353. package/src/lifecycle/status.test.ts +151 -1
  354. package/src/lifecycle/status.ts +228 -7
  355. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +2 -3
  356. package/src/op/activities/activity-contracts.ts +37 -0
  357. package/src/op/activities/index.ts +10 -0
  358. package/src/op/activities/propose-upgrade.ts +206 -0
  359. package/src/op/activity-contract-registry.ts +18 -4
  360. package/src/op/activity-registry.ts +26 -0
  361. package/src/op/discover.test.ts +14 -4
  362. package/src/op/discover.ts +19 -23
  363. package/src/op/gate-approval.ts +3 -1
  364. package/src/op/gate-name.ts +8 -0
  365. package/src/op/gate-summary.test.ts +14 -0
  366. package/src/op/gate-summary.ts +25 -2
  367. package/src/op/gate.ts +36 -7
  368. package/src/op/generate-pipeline.test.ts +14 -5
  369. package/src/op/generate-pipeline.ts +2 -1
  370. package/src/op/runtimes/local.ts +2 -1
  371. package/src/project-root.test.ts +66 -1
  372. package/src/project-root.ts +48 -0
  373. package/src/workspace/__fixtures__/contract-repo.ts +100 -0
  374. package/src/workspace/__fixtures__/two-member-workspace.ts +35 -0
  375. package/src/workspace/behold-kinds.test.ts +162 -0
  376. package/src/workspace/check-contract.test.ts +127 -0
  377. package/src/workspace/check.schema.json +347 -0
  378. package/src/workspace/checks/generated.test.ts +287 -0
  379. package/src/workspace/checks/generated.ts +475 -0
  380. package/src/workspace/checks/ledgers.test.ts +139 -0
  381. package/src/workspace/checks/ledgers.ts +246 -0
  382. package/src/workspace/checks/links.ts +183 -0
  383. package/src/workspace/checks/pipelines.test.ts +133 -0
  384. package/src/workspace/checks/pipelines.ts +225 -0
  385. package/src/workspace/checks-repo.test.ts +71 -0
  386. package/src/workspace/checks.test.ts +450 -0
  387. package/src/workspace/checks.ts +461 -0
  388. package/src/workspace/compose-graph.test.ts +146 -0
  389. package/src/workspace/compose-graph.ts +228 -0
  390. package/src/workspace/compose-reports.test.ts +109 -0
  391. package/src/workspace/compose-reports.ts +186 -0
  392. package/src/workspace/declaration.schema.json +434 -0
  393. package/src/workspace/declaration.test.ts +347 -0
  394. package/src/workspace/declaration.ts +623 -0
  395. package/src/workspace/generated-files.test.ts +114 -0
  396. package/src/workspace/generated-files.ts +94 -0
  397. package/src/workspace/glob.ts +49 -0
  398. package/src/workspace/graph-cli.ts +220 -0
  399. package/src/workspace/graph-contract.test.ts +204 -0
  400. package/src/workspace/graph.schema.json +662 -0
  401. package/src/workspace/init.test.ts +223 -0
  402. package/src/workspace/init.ts +585 -0
  403. package/src/workspace/jsonc.test.ts +65 -0
  404. package/src/workspace/jsonc.ts +231 -0
  405. package/src/workspace/kinds.test.ts +288 -0
  406. package/src/workspace/kinds.ts +506 -0
  407. package/src/workspace/lineage-check.ts +264 -0
  408. package/src/workspace/lineage-cli.ts +114 -0
  409. package/src/workspace/lineage-init.test.ts +231 -0
  410. package/src/workspace/lineage-init.ts +365 -0
  411. package/src/workspace/lineage-lock.test.ts +224 -0
  412. package/src/workspace/lineage-lock.ts +357 -0
  413. package/src/workspace/lineage-merge.ts +44 -0
  414. package/src/workspace/lineage-migrations.test.ts +178 -0
  415. package/src/workspace/lineage-migrations.ts +343 -0
  416. package/src/workspace/lineage-update.ts +160 -0
  417. package/src/workspace/lineage-upgrade-cli.ts +151 -0
  418. package/src/workspace/lineage-upgrade.test.ts +474 -0
  419. package/src/workspace/lineage-upgrade.ts +624 -0
  420. package/src/workspace/lineage-vendor.test.ts +126 -0
  421. package/src/workspace/lineage-vendor.ts +215 -0
  422. package/src/workspace/lineage-version.ts +127 -0
  423. package/src/workspace/links.test.ts +344 -0
  424. package/src/workspace/links.ts +331 -0
  425. package/src/workspace/ls-contract.test.ts +200 -0
  426. package/src/workspace/ls.schema.json +190 -0
  427. package/src/workspace/ls.ts +254 -0
  428. package/src/workspace/member-commands.e2e.test.ts +244 -0
  429. package/src/workspace/member-commands.test.ts +217 -0
  430. package/src/workspace/member-commands.ts +540 -0
  431. package/src/workspace/member-handles.test.ts +76 -0
  432. package/src/workspace/member-handles.ts +228 -0
  433. package/src/workspace/member-pipeline.test.ts +135 -0
  434. package/src/workspace/member-pipeline.ts +317 -0
  435. package/src/workspace/member-run.ts +146 -0
  436. package/src/workspace/read-contract.test.ts +129 -0
  437. package/src/workspace/reason-codes.test.ts +113 -0
  438. package/src/workspace/reason-codes.ts +81 -0
  439. package/src/workspace/record-source.ts +117 -0
  440. package/src/workspace/records-cli.ts +198 -0
  441. package/src/workspace/records-contract.test.ts +93 -0
  442. package/src/workspace/records.schema.json +150 -0
  443. package/src/workspace/records.test.ts +243 -0
  444. package/src/workspace/records.ts +384 -0
  445. package/src/workspace/root-refusal.ts +97 -0
  446. package/src/workspace/status-contract.test.ts +308 -0
  447. package/src/workspace/status.schema.json +210 -0
  448. package/src/workspace/status.ts +412 -0
  449. package/src/workspace/template-manifest.test.ts +79 -0
  450. package/src/workspace/template-manifest.ts +221 -0
  451. package/src/workspace/tree.ts +132 -0
  452. package/src/workspace/trust/attestor.ts +93 -0
  453. package/src/workspace/trust/policy.ts +306 -0
  454. package/src/workspace/trust/provenance.ts +181 -0
  455. package/src/workspace/trust/ssh-commit.ts +138 -0
  456. package/src/workspace/trust/test-repo.ts +138 -0
  457. package/src/workspace/trust/trust.test.ts +397 -0
  458. package/src/workspace/trust/verify-cli.ts +56 -0
  459. package/src/workspace/trust/verify.ts +194 -0
  460. package/src/workspace/which-chant.test.ts +117 -0
  461. package/src/workspace/which-chant.ts +151 -0
  462. package/src/workspace/workspace-kinds.schema.json +133 -0
@@ -0,0 +1,126 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "vitest";
2
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { MANIFEST_FILE, loadManifest, vendorPull } from "../cli/commands/vendor";
6
+ import { LOCK_FILE, readLock, resolveManualStep, writeLock } from "./lineage-lock";
7
+ import { checkLockedScopes, migrateVendorManifest, pullLockedScopes } from "./lineage-vendor";
8
+
9
+ let root: string;
10
+
11
+ function put(rel: string, content: string): void {
12
+ mkdirSync(dirname(join(root, rel)), { recursive: true });
13
+ writeFileSync(join(root, rel), content);
14
+ }
15
+ const read = (rel: string) => readFileSync(join(root, rel), "utf-8");
16
+
17
+ beforeEach(() => {
18
+ root = mkdtempSync(join(tmpdir(), "chant-lineage-vendor-"));
19
+ put("shared/web/index.ts", "export const v = 1;\n");
20
+ put("shared/web/README.md", "# web\n");
21
+ put(
22
+ MANIFEST_FILE,
23
+ JSON.stringify({
24
+ vendored: [
25
+ { name: "web", source: { type: "local", path: "shared/web" }, target: "vendor/web", ref: "v1" },
26
+ { name: "later", source: { type: "local", path: "shared/web" }, target: "vendor/later" },
27
+ ],
28
+ }),
29
+ );
30
+ });
31
+ afterEach(() => {
32
+ rmSync(root, { recursive: true, force: true });
33
+ });
34
+
35
+ describe("chant vendor migrate", () => {
36
+ test("moves every entry into the lock as a vendor scope and removes vendor.json", async () => {
37
+ await vendorPull(root, "web");
38
+ const checksum = loadManifest(root).manifest.vendored[0].checksum;
39
+ const result = await migrateVendorManifest(root);
40
+ expect(result).toEqual({
41
+ migrated: [
42
+ { name: "web", target: "vendor/web", files: 2, pinned: true },
43
+ { name: "later", target: "vendor/later", files: 0, pinned: false },
44
+ ],
45
+ lockCreated: true,
46
+ });
47
+ expect(existsSync(join(root, MANIFEST_FILE))).toBe(false);
48
+ const lock = readLock(root)!;
49
+ expect(lock.scopes["vendor/web"]).toMatchObject({
50
+ kind: "vendor",
51
+ name: "web",
52
+ template: "local:shared/web",
53
+ source: { type: "local", path: "shared/web" },
54
+ ref: "v1",
55
+ address: { digest: checksum },
56
+ parameters: {},
57
+ migrations: [],
58
+ });
59
+ expect(Object.keys(lock.scopes["vendor/web"].files)).toEqual(["README.md", "index.ts"]);
60
+ expect(lock.scopes["vendor/later"].address).toBeNull();
61
+ });
62
+
63
+ test("an edited target takes its merge bases from the source when the source still matches", async () => {
64
+ await vendorPull(root, "web");
65
+ put("vendor/web/index.ts", "mine\n");
66
+ await migrateVendorManifest(root);
67
+ expect(checkLockedScopes(root).find((c) => c.name === "web")).toMatchObject({ status: "customised", customised: ["index.ts"] });
68
+ });
69
+
70
+ test("refuses, writing nothing, when the pinned content cannot be recovered", async () => {
71
+ await vendorPull(root, "web");
72
+ put("vendor/web/index.ts", "mine\n");
73
+ put("shared/web/index.ts", "moved on\n");
74
+ await expect(migrateVendorManifest(root)).rejects.toThrow(/cannot be recovered/);
75
+ expect(existsSync(join(root, MANIFEST_FILE))).toBe(true);
76
+ expect(existsSync(join(root, LOCK_FILE))).toBe(false);
77
+ });
78
+
79
+ test("keeps scopes already in the lock and refuses a clash", async () => {
80
+ await migrateVendorManifest(root);
81
+ put(MANIFEST_FILE, JSON.stringify({ vendored: [{ name: "web", source: { type: "local", path: "shared/web" }, target: "vendor/other" }] }));
82
+ await expect(migrateVendorManifest(root)).rejects.toThrow(/already has a vendor scope with that name/);
83
+ put(MANIFEST_FILE, JSON.stringify({ vendored: [{ name: "x", source: { type: "local", path: "shared/web" }, target: "vendor/web/" }] }));
84
+ await expect(migrateVendorManifest(root)).rejects.toThrow(/already has a scope at vendor\/web/);
85
+ });
86
+ });
87
+
88
+ describe("chant vendor pull through the lock", () => {
89
+ test("keeps local edits, applies clean updates and records conflicts as manual steps", async () => {
90
+ await vendorPull(root);
91
+ await migrateVendorManifest(root);
92
+ put("vendor/web/index.ts", "mine\n");
93
+ put("vendor/web/local-only.ts", "mine\n");
94
+ put("shared/web/index.ts", "export const v = 2;\n");
95
+ put("shared/web/README.md", "# web v2\n");
96
+
97
+ const [web] = await pullLockedScopes(root, "web");
98
+ expect(web).toMatchObject({ name: "web", target: "vendor/web", written: 1, kept: 1 });
99
+ expect(web.manualSteps.map((s) => [s.path, s.reason])).toEqual([["index.ts", "changed-locally"]]);
100
+ expect(read("vendor/web/index.ts")).toBe("mine\n");
101
+ expect(read("vendor/web/README.md")).toBe("# web v2\n");
102
+ expect(read("vendor/web/local-only.ts")).toBe("mine\n");
103
+
104
+ expect(checkLockedScopes(root).find((c) => c.name === "web")?.status).toBe("manual");
105
+
106
+ const lock = readLock(root)!;
107
+ resolveManualStep(lock, "vendor/web/index.ts");
108
+ writeLock(root, lock);
109
+ expect(checkLockedScopes(root).find((c) => c.name === "web")).toMatchObject({ status: "customised", customised: ["index.ts"] });
110
+ });
111
+
112
+ test("an unpinned scope is populated by its first pull", async () => {
113
+ await migrateVendorManifest(root);
114
+ expect(checkLockedScopes(root).find((c) => c.name === "later")?.status).toBe("unpinned");
115
+ await pullLockedScopes(root, "later");
116
+ expect(read("vendor/later/index.ts")).toBe("export const v = 1;\n");
117
+ expect(checkLockedScopes(root).find((c) => c.name === "later")?.status).toBe("ok");
118
+ });
119
+
120
+ test("a deleted target is missing", async () => {
121
+ await vendorPull(root, "web");
122
+ await migrateVendorManifest(root);
123
+ rmSync(join(root, "vendor/web"), { recursive: true });
124
+ expect(checkLockedScopes(root).find((c) => c.name === "web")?.status).toBe("missing");
125
+ });
126
+ });
@@ -0,0 +1,215 @@
1
+ /**
2
+ * `chant vendor` over the lineage lock (#2540, ws-038).
3
+ *
4
+ * A vendored target is one lineage scope of kind `vendor`: copied, with no
5
+ * parameters. `pull` updates it file by file through {@link applyUpstream}, so
6
+ * local edits survive and a file both sides changed becomes a manual step.
7
+ * `check` reports edits and fails on open manual steps.
8
+ *
9
+ * `vendor.json` is still read. A project whose lock has no vendor scopes and
10
+ * which never ran `chant vendor migrate` keeps today's `vendor.json` behaviour
11
+ * byte for byte (#2525 rule 2): this module loads only when a lock exists or
12
+ * `migrate` runs.
13
+ */
14
+
15
+ import { existsSync, rmSync } from "node:fs";
16
+ import { join, resolve } from "node:path";
17
+ import {
18
+ MANIFEST_FILE,
19
+ contentHash,
20
+ loadManifest,
21
+ readTarget,
22
+ resolveVendorSource,
23
+ type VendorEntry,
24
+ } from "../cli/commands/vendor";
25
+ import { LOCK_FILE, LockError, declaredFilesAt, emptyLock, fileEntries, readLock, scopeKey, scopeStatus, writeLock, type Lineage, type LineageLock, type ManualStep } from "./lineage-lock";
26
+ import { applyUpstream } from "./lineage-update";
27
+
28
+ /** The template id a vendor source is known by. */
29
+ function vendorTemplateId(source: VendorEntry["source"]): string {
30
+ if (source.type === "local") return `local:${source.path}`;
31
+ return source.subpath ? `${source.url}#${source.subpath}` : source.url;
32
+ }
33
+
34
+ /** Vendor scopes in the lock, by scope key. */
35
+ export function vendorScopes(lock: LineageLock): Array<[string, Lineage]> {
36
+ return Object.entries(lock.scopes).filter(([, l]) => l.kind === "vendor");
37
+ }
38
+
39
+ function vendorSource(lineage: Lineage): VendorEntry["source"] {
40
+ const s = lineage.source;
41
+ if (s.type === "local" || s.type === "archive") return s;
42
+ throw new LockError(`vendor scope "${lineage.name}" has a ${s.type} source; vendor scopes take local or archive sources`);
43
+ }
44
+
45
+ // ── pull ─────────────────────────────────────────────────────────────────────
46
+
47
+ export interface LockedPull {
48
+ name: string;
49
+ target: string;
50
+ digest: string;
51
+ fileCount: number;
52
+ written: number;
53
+ kept: number;
54
+ removed: number;
55
+ manualSteps: ManualStep[];
56
+ }
57
+
58
+ /** Pull the lock's vendor scopes (or just `only`). Writes the lock. */
59
+ export async function pullLockedScopes(root: string, only?: string): Promise<LockedPull[]> {
60
+ const lock = readLock(root) ?? emptyLock();
61
+ const pulled: LockedPull[] = [];
62
+ for (const [scope, lineage] of vendorScopes(lock)) {
63
+ if (only && lineage.name !== only) continue;
64
+ const files = await resolveVendorSource(vendorSource(lineage), root);
65
+ const result = applyUpstream(resolve(root, scope), lineage, files);
66
+ pulled.push({
67
+ name: lineage.name ?? scope,
68
+ target: scope,
69
+ digest: lineage.address!.digest,
70
+ fileCount: files.size,
71
+ written: result.written.length,
72
+ kept: result.kept.length,
73
+ removed: result.removed.length,
74
+ manualSteps: result.manualSteps,
75
+ });
76
+ }
77
+ if (pulled.length > 0) writeLock(root, lock);
78
+ return pulled;
79
+ }
80
+
81
+ export function formatLockedPull(p: LockedPull): string {
82
+ const lines = [` ${p.name} → ${p.target} (${p.fileCount} file(s), ${p.digest.slice(0, 19)}…)`];
83
+ if (p.kept > 0) lines.push(` kept ${p.kept} locally edited file(s)`);
84
+ for (const s of p.manualSteps) lines.push(` manual step: ${s.path} (${s.reason})`);
85
+ return lines.join("\n");
86
+ }
87
+
88
+ // ── check ────────────────────────────────────────────────────────────────────
89
+
90
+ export type LockedCheckStatus = "ok" | "customised" | "manual" | "unpinned" | "missing";
91
+
92
+ export interface LockedCheck {
93
+ name: string;
94
+ status: LockedCheckStatus;
95
+ customised: string[];
96
+ manualSteps: ManualStep[];
97
+ }
98
+
99
+ /** Check each vendor scope in the lock against the tree. */
100
+ export function checkLockedScopes(root: string): LockedCheck[] {
101
+ const lock = readLock(root);
102
+ if (!lock) return [];
103
+ const out: LockedCheck[] = [];
104
+ for (const [scope, lineage] of vendorScopes(lock)) {
105
+ const name = lineage.name ?? scope;
106
+ if (!lineage.address) {
107
+ out.push({ name, status: "unpinned", customised: [], manualSteps: [] });
108
+ continue;
109
+ }
110
+ if (!existsSync(resolve(root, scope))) {
111
+ out.push({ name, status: "missing", customised: [], manualSteps: [] });
112
+ continue;
113
+ }
114
+ const st = scopeStatus(root, scope, lineage);
115
+ const customised = [...st.customised, ...st.missing].sort();
116
+ const status: LockedCheckStatus = lineage.manualSteps.length > 0 ? "manual" : customised.length > 0 ? "customised" : "ok";
117
+ out.push({ name, status, customised, manualSteps: lineage.manualSteps });
118
+ }
119
+ return out;
120
+ }
121
+
122
+ export function formatLockedCheck(c: LockedCheck): string {
123
+ switch (c.status) {
124
+ case "ok":
125
+ return ` ${c.name}: ok`;
126
+ case "customised":
127
+ return ` ${c.name}: ok, ${c.customised.length} file(s) edited locally`;
128
+ case "manual":
129
+ return [
130
+ ` ${c.name}: ${c.manualSteps.length} manual step(s) open`,
131
+ ...c.manualSteps.map((s) => ` ${s.path} (${s.reason})`),
132
+ ].join("\n");
133
+ case "unpinned":
134
+ return ` ${c.name}: unpinned — run \`chant vendor pull\` to record it`;
135
+ case "missing":
136
+ return ` ${c.name}: MISSING — target not found; run \`chant vendor pull\``;
137
+ }
138
+ }
139
+
140
+ /** Whether a check result fails the check the way drift does for `vendor.json`. */
141
+ export function lockedCheckFails(c: LockedCheck): boolean {
142
+ return c.status === "manual" || c.status === "missing";
143
+ }
144
+
145
+ // ── migrate ──────────────────────────────────────────────────────────────────
146
+
147
+ export interface MigrateResult {
148
+ migrated: Array<{ name: string; target: string; files: number; pinned: boolean }>;
149
+ lockCreated: boolean;
150
+ }
151
+
152
+ /**
153
+ * Move every `vendor.json` entry into the lock as a vendor scope, then delete
154
+ * `vendor.json`. An entry's checksum becomes the scope's digest.
155
+ *
156
+ * Per-file merge bases come from the target when it still matches the
157
+ * checksum. When it has been edited, they come from the source instead, which
158
+ * must still hash to the checksum; otherwise the pinned content is gone and the
159
+ * entry is refused. Nothing is written unless every entry migrates.
160
+ */
161
+ export async function migrateVendorManifest(root: string): Promise<MigrateResult> {
162
+ const { manifest, path: manifestPath } = loadManifest(root);
163
+ const existing = readLock(root);
164
+ const lock = existing ?? emptyLock();
165
+ const migrated: MigrateResult["migrated"] = [];
166
+ const names = new Set(vendorScopes(lock).map(([, l]) => l.name));
167
+
168
+ for (const entry of manifest.vendored) {
169
+ const scope = scopeKey(entry.target);
170
+ if (scope === ".") throw new LockError(`vendor entry "${entry.name}" targets the project root; a vendor scope must be a subdirectory`);
171
+ if (lock.scopes[scope]) throw new LockError(`vendor entry "${entry.name}": ${LOCK_FILE} already has a scope at ${scope}`);
172
+ if (names.has(entry.name)) throw new LockError(`vendor entry "${entry.name}": ${LOCK_FILE} already has a vendor scope with that name`);
173
+ names.add(entry.name);
174
+
175
+ let files: Lineage["files"] = {};
176
+ if (entry.checksum) {
177
+ const targetAbs = resolve(root, entry.target);
178
+ const local = readTarget(targetAbs);
179
+ if (local.size > 0 && contentHash(local) === entry.checksum) {
180
+ files = fileEntries(local, declaredFilesAt(targetAbs));
181
+ } else {
182
+ const source = await resolveVendorSource(entry.source, root);
183
+ if (contentHash(source) !== entry.checksum) {
184
+ throw new LockError(
185
+ `vendor entry "${entry.name}": ${entry.target} has been edited and its source no longer matches the recorded checksum, so the pinned files cannot be recovered. Run \`chant vendor pull ${entry.name}\` first (it overwrites ${entry.target}), or restore the pinned content.`,
186
+ );
187
+ }
188
+ files = fileEntries(source, declaredFilesAt(targetAbs));
189
+ }
190
+ }
191
+
192
+ lock.scopes[scope] = {
193
+ kind: "vendor",
194
+ name: entry.name,
195
+ template: vendorTemplateId(entry.source),
196
+ source: entry.source,
197
+ ...(entry.ref !== undefined ? { ref: entry.ref } : {}),
198
+ address: entry.checksum ? { digest: entry.checksum } : null,
199
+ parameters: {},
200
+ migrations: [],
201
+ files,
202
+ manualSteps: [],
203
+ };
204
+ migrated.push({ name: entry.name, target: scope, files: Object.keys(files).length, pinned: !!entry.checksum });
205
+ }
206
+
207
+ writeLock(root, lock);
208
+ rmSync(manifestPath);
209
+ return { migrated, lockCreated: existing === null };
210
+ }
211
+
212
+ /** Whether `vendor.json` sits next to the lock. */
213
+ export function manifestPresent(root: string): boolean {
214
+ return existsSync(join(root, MANIFEST_FILE));
215
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Template versions and version ranges, for migration chains (#2550, D9).
3
+ *
4
+ * A template's version is read from the ref it was pinned at: `v1.4.0`,
5
+ * `1.4`, or a prefixed release tag such as `chant-v0.80.0`. Missing minor and
6
+ * patch numbers read as 0. A ref that is not a version (a branch, a commit)
7
+ * has none, and a chain of migrations cannot be planned from it.
8
+ *
9
+ * Ranges use the familiar npm subset: comparators (`>=1.0.0 <2.0.0`), `^`,
10
+ * `~`, `x` wildcards, a bare version for an exact match, `*` for any, and
11
+ * `||` between alternatives. Pre-release tags compare below their release,
12
+ * and a range matches a pre-release only through an exact comparator.
13
+ */
14
+
15
+ export interface Version {
16
+ major: number;
17
+ minor: number;
18
+ patch: number;
19
+ /** The pre-release label after `-`, or empty for a release. */
20
+ pre: string;
21
+ }
22
+
23
+ const VERSION_TAIL = /(?:^|[-_/@])v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
24
+
25
+ /** The version a ref names, or null when it names none. */
26
+ export function parseVersion(ref: string | undefined | null): Version | null {
27
+ if (!ref) return null;
28
+ const m = VERSION_TAIL.exec(ref.trim());
29
+ if (!m) return null;
30
+ return { major: Number(m[1]), minor: Number(m[2] ?? 0), patch: Number(m[3] ?? 0), pre: m[4] ?? "" };
31
+ }
32
+
33
+ export function formatVersion(v: Version): string {
34
+ return `${v.major}.${v.minor}.${v.patch}${v.pre ? `-${v.pre}` : ""}`;
35
+ }
36
+
37
+ export function compareVersions(a: Version, b: Version): number {
38
+ for (const k of ["major", "minor", "patch"] as const) {
39
+ if (a[k] !== b[k]) return a[k] < b[k] ? -1 : 1;
40
+ }
41
+ if (a.pre === b.pre) return 0;
42
+ if (!a.pre) return 1;
43
+ if (!b.pre) return -1;
44
+ return a.pre < b.pre ? -1 : 1;
45
+ }
46
+
47
+ export class VersionRangeError extends Error {
48
+ override name = "VersionRangeError";
49
+ }
50
+
51
+ type Comparator = { op: "<" | "<=" | ">" | ">=" | "="; v: Version };
52
+
53
+ function partial(text: string, range: string): { v: Version; parts: number } {
54
+ const m = /^v?(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?(?:-([0-9A-Za-z.-]+))?$/.exec(text);
55
+ if (!m) throw new VersionRangeError(`"${range}" is not a version range: cannot read "${text}"`);
56
+ const nums = [m[1], m[2], m[3]];
57
+ let parts = 0;
58
+ for (const n of nums) {
59
+ if (n === undefined || /^[xX*]$/.test(n)) break;
60
+ parts++;
61
+ }
62
+ const at = (i: number) => (i < parts ? Number(nums[i]) : 0);
63
+ return { v: { major: at(0), minor: at(1), patch: at(2), pre: parts === 3 ? (m[4] ?? "") : "" }, parts };
64
+ }
65
+
66
+ function bump(v: Version, part: number): Version {
67
+ if (part === 0) return { major: v.major + 1, minor: 0, patch: 0, pre: "" };
68
+ if (part === 1) return { major: v.major, minor: v.minor + 1, patch: 0, pre: "" };
69
+ return { major: v.major, minor: v.minor, patch: v.patch + 1, pre: "" };
70
+ }
71
+
72
+ /** The comparators of one `||` alternative. */
73
+ function comparators(alt: string, range: string): Comparator[] {
74
+ const out: Comparator[] = [];
75
+ const tokens = alt.trim().replace(/(>=|<=|>|<|=|\^|~)\s+/g, "$1").split(/\s+/).filter(Boolean);
76
+ for (const token of tokens) {
77
+ if (token === "*" || /^[xX]$/.test(token)) continue;
78
+ const m = /^(>=|<=|>|<|=|\^|~)?(.*)$/.exec(token)!;
79
+ const op = m[1] ?? "";
80
+ const { v, parts } = partial(m[2], range);
81
+ if (op === "^") {
82
+ const upper = v.major > 0 || parts === 1 ? bump(v, 0) : v.minor > 0 || parts === 2 ? bump(v, 1) : bump(v, 2);
83
+ out.push({ op: ">=", v }, { op: "<", v: upper });
84
+ } else if (op === "~") {
85
+ out.push({ op: ">=", v }, { op: "<", v: bump(v, parts >= 2 ? 1 : 0) });
86
+ } else if (op === "" || op === "=") {
87
+ if (parts === 3) out.push({ op: "=", v });
88
+ else if (parts > 0) out.push({ op: ">=", v }, { op: "<", v: bump(v, parts - 1) });
89
+ } else if (parts < 3 && (op === ">" || op === "<=")) {
90
+ // `>1.2` means past every 1.2.x; `<=1.2` includes every 1.2.x.
91
+ out.push({ op: op === ">" ? ">=" : "<", v: bump(v, parts - 1) });
92
+ } else {
93
+ out.push({ op: op as Comparator["op"], v });
94
+ }
95
+ }
96
+ return out;
97
+ }
98
+
99
+ function test(v: Version, c: Comparator): boolean {
100
+ const d = compareVersions(v, c.v);
101
+ switch (c.op) {
102
+ case "<":
103
+ return d < 0;
104
+ case "<=":
105
+ return d <= 0;
106
+ case ">":
107
+ return d > 0;
108
+ case ">=":
109
+ return d >= 0;
110
+ case "=":
111
+ return d === 0;
112
+ }
113
+ }
114
+
115
+ /** Check a range's syntax, throwing {@link VersionRangeError} when it cannot be read. */
116
+ export function validateRange(range: string): void {
117
+ for (const alt of range.split("||")) comparators(alt, range);
118
+ }
119
+
120
+ /** Whether `version` falls in `range`. */
121
+ export function satisfies(version: Version, range: string): boolean {
122
+ return range.split("||").some((alt) => {
123
+ const cs = comparators(alt, range);
124
+ if (version.pre && !cs.some((c) => c.op === "=" && compareVersions(c.v, version) === 0)) return false;
125
+ return cs.every((c) => test(version, c));
126
+ });
127
+ }