@intentius/chant 0.80.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 (414) hide show
  1. package/dist/audit/discover.d.ts +8 -16
  2. package/dist/audit/discover.d.ts.map +1 -1
  3. package/dist/audit/report-html.d.ts +5 -0
  4. package/dist/audit/report-html.d.ts.map +1 -1
  5. package/dist/audit/report-model.d.ts +13 -0
  6. package/dist/audit/report-model.d.ts.map +1 -1
  7. package/dist/audit/terraform-state.d.ts +4 -5
  8. package/dist/audit/terraform-state.d.ts.map +1 -1
  9. package/dist/cli/commands/audit.d.ts +25 -9
  10. package/dist/cli/commands/audit.d.ts.map +1 -1
  11. package/dist/cli/commands/check-lexicon.d.ts +8 -0
  12. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  13. package/dist/cli/commands/doctor.d.ts.map +1 -1
  14. package/dist/cli/commands/import-agents.d.ts.map +1 -1
  15. package/dist/cli/commands/init.d.ts.map +1 -1
  16. package/dist/cli/commands/lint.d.ts.map +1 -1
  17. package/dist/cli/commands/update.d.ts +6 -0
  18. package/dist/cli/commands/update.d.ts.map +1 -1
  19. package/dist/cli/commands/vendor.d.ts +5 -0
  20. package/dist/cli/commands/vendor.d.ts.map +1 -1
  21. package/dist/cli/handlers/build.d.ts.map +1 -1
  22. package/dist/cli/handlers/components.d.ts.map +1 -1
  23. package/dist/cli/handlers/dev.d.ts.map +1 -1
  24. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  25. package/dist/cli/handlers/init.d.ts.map +1 -1
  26. package/dist/cli/handlers/operator.d.ts +7 -0
  27. package/dist/cli/handlers/operator.d.ts.map +1 -1
  28. package/dist/cli/handlers/promote.d.ts +7 -4
  29. package/dist/cli/handlers/promote.d.ts.map +1 -1
  30. package/dist/cli/handlers/run-generate.d.ts.map +1 -1
  31. package/dist/cli/handlers/run.d.ts +4 -1
  32. package/dist/cli/handlers/run.d.ts.map +1 -1
  33. package/dist/cli/handlers/vendor.d.ts +8 -3
  34. package/dist/cli/handlers/vendor.d.ts.map +1 -1
  35. package/dist/cli/main.d.ts +12 -0
  36. package/dist/cli/main.d.ts.map +1 -1
  37. package/dist/cli/plugins.d.ts +12 -7
  38. package/dist/cli/plugins.d.ts.map +1 -1
  39. package/dist/cli/registry.d.ts +32 -0
  40. package/dist/cli/registry.d.ts.map +1 -1
  41. package/dist/codegen/fetch.d.ts +10 -0
  42. package/dist/codegen/fetch.d.ts.map +1 -1
  43. package/dist/components/cli-support.d.ts +3 -1
  44. package/dist/components/cli-support.d.ts.map +1 -1
  45. package/dist/components/discover.d.ts.map +1 -1
  46. package/dist/components/driver.d.ts +16 -2
  47. package/dist/components/driver.d.ts.map +1 -1
  48. package/dist/components/gate-plan.d.ts +40 -0
  49. package/dist/components/gate-plan.d.ts.map +1 -0
  50. package/dist/components/promote.d.ts +60 -7
  51. package/dist/components/promote.d.ts.map +1 -1
  52. package/dist/components/sandbox/driver.d.ts.map +1 -1
  53. package/dist/components/sandbox/run.d.ts.map +1 -1
  54. package/dist/components/verbs/build-archive.d.ts +22 -11
  55. package/dist/components/verbs/build-archive.d.ts.map +1 -1
  56. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  57. package/dist/config-static.d.ts +59 -0
  58. package/dist/config-static.d.ts.map +1 -0
  59. package/dist/config.d.ts +32 -10
  60. package/dist/config.d.ts.map +1 -1
  61. package/dist/content-digest.d.ts +17 -0
  62. package/dist/content-digest.d.ts.map +1 -0
  63. package/dist/discovery/files.d.ts +10 -5
  64. package/dist/discovery/files.d.ts.map +1 -1
  65. package/dist/discovery/fold-import.d.ts +20 -4
  66. package/dist/discovery/fold-import.d.ts.map +1 -1
  67. package/dist/discovery/index.d.ts.map +1 -1
  68. package/dist/discovery/sandbox/driver.d.ts +20 -0
  69. package/dist/discovery/sandbox/driver.d.ts.map +1 -1
  70. package/dist/discovery/sandbox/fork.d.ts +20 -0
  71. package/dist/discovery/sandbox/fork.d.ts.map +1 -1
  72. package/dist/discovery/walk.d.ts +119 -0
  73. package/dist/discovery/walk.d.ts.map +1 -0
  74. package/dist/graph-ir.d.ts +4 -1
  75. package/dist/graph-ir.d.ts.map +1 -1
  76. package/dist/join-key.d.ts +31 -0
  77. package/dist/join-key.d.ts.map +1 -0
  78. package/dist/lexicon-module.d.ts +51 -6
  79. package/dist/lexicon-module.d.ts.map +1 -1
  80. package/dist/lexicon.d.ts +58 -1
  81. package/dist/lexicon.d.ts.map +1 -1
  82. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -1
  83. package/dist/lifecycle/digest.d.ts +5 -1
  84. package/dist/lifecycle/digest.d.ts.map +1 -1
  85. package/dist/lifecycle/gate-ledger.d.ts +20 -5
  86. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  87. package/dist/lifecycle/git.d.ts +64 -0
  88. package/dist/lifecycle/git.d.ts.map +1 -1
  89. package/dist/lifecycle/lease.d.ts +8 -1
  90. package/dist/lifecycle/lease.d.ts.map +1 -1
  91. package/dist/lifecycle/legacy-digest.d.ts +41 -8
  92. package/dist/lifecycle/legacy-digest.d.ts.map +1 -1
  93. package/dist/lifecycle/member-ledger.d.ts +67 -0
  94. package/dist/lifecycle/member-ledger.d.ts.map +1 -0
  95. package/dist/lifecycle/plan-digest.d.ts +4 -3
  96. package/dist/lifecycle/plan-digest.d.ts.map +1 -1
  97. package/dist/lifecycle/release-ledger.d.ts +18 -2
  98. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  99. package/dist/lifecycle/status.d.ts +90 -5
  100. package/dist/lifecycle/status.d.ts.map +1 -1
  101. package/dist/op/activities/activity-contracts.d.ts +32 -0
  102. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  103. package/dist/op/activities/index.d.ts +2 -0
  104. package/dist/op/activities/index.d.ts.map +1 -1
  105. package/dist/op/activities/propose-upgrade.d.ts +75 -0
  106. package/dist/op/activities/propose-upgrade.d.ts.map +1 -0
  107. package/dist/op/discover.d.ts.map +1 -1
  108. package/dist/op/gate-name.d.ts +7 -0
  109. package/dist/op/gate-name.d.ts.map +1 -1
  110. package/dist/op/gate-summary.d.ts +16 -0
  111. package/dist/op/gate-summary.d.ts.map +1 -1
  112. package/dist/op/gate.d.ts +16 -2
  113. package/dist/op/gate.d.ts.map +1 -1
  114. package/dist/project-root.d.ts +26 -0
  115. package/dist/project-root.d.ts.map +1 -1
  116. package/dist/workspace/__fixtures__/contract-repo.d.ts +37 -0
  117. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -0
  118. package/dist/workspace/__fixtures__/two-member-workspace.d.ts +11 -0
  119. package/dist/workspace/__fixtures__/two-member-workspace.d.ts.map +1 -0
  120. package/dist/workspace/checks/generated.d.ts +156 -0
  121. package/dist/workspace/checks/generated.d.ts.map +1 -0
  122. package/dist/workspace/checks/ledgers.d.ts +78 -0
  123. package/dist/workspace/checks/ledgers.d.ts.map +1 -0
  124. package/dist/workspace/checks/links.d.ts +25 -0
  125. package/dist/workspace/checks/links.d.ts.map +1 -0
  126. package/dist/workspace/checks/pipelines.d.ts +76 -0
  127. package/dist/workspace/checks/pipelines.d.ts.map +1 -0
  128. package/dist/workspace/checks.d.ts +161 -0
  129. package/dist/workspace/checks.d.ts.map +1 -0
  130. package/dist/workspace/compose-graph.d.ts +115 -0
  131. package/dist/workspace/compose-graph.d.ts.map +1 -0
  132. package/dist/workspace/compose-reports.d.ts +68 -0
  133. package/dist/workspace/compose-reports.d.ts.map +1 -0
  134. package/dist/workspace/declaration.d.ts +220 -0
  135. package/dist/workspace/declaration.d.ts.map +1 -0
  136. package/dist/workspace/declaration.schema.json +434 -0
  137. package/dist/workspace/generated-files.d.ts +65 -0
  138. package/dist/workspace/generated-files.d.ts.map +1 -0
  139. package/dist/workspace/glob.d.ts +13 -0
  140. package/dist/workspace/glob.d.ts.map +1 -0
  141. package/dist/workspace/graph-cli.d.ts +75 -0
  142. package/dist/workspace/graph-cli.d.ts.map +1 -0
  143. package/dist/workspace/init.d.ts +96 -0
  144. package/dist/workspace/init.d.ts.map +1 -0
  145. package/dist/workspace/jsonc.d.ts +38 -0
  146. package/dist/workspace/jsonc.d.ts.map +1 -0
  147. package/dist/workspace/kinds.d.ts +192 -0
  148. package/dist/workspace/kinds.d.ts.map +1 -0
  149. package/dist/workspace/lineage-check.d.ts +84 -0
  150. package/dist/workspace/lineage-check.d.ts.map +1 -0
  151. package/dist/workspace/lineage-cli.d.ts +31 -0
  152. package/dist/workspace/lineage-cli.d.ts.map +1 -0
  153. package/dist/workspace/lineage-init.d.ts +101 -0
  154. package/dist/workspace/lineage-init.d.ts.map +1 -0
  155. package/dist/workspace/lineage-lock.d.ts +258 -0
  156. package/dist/workspace/lineage-lock.d.ts.map +1 -0
  157. package/dist/workspace/lineage-merge.d.ts +14 -0
  158. package/dist/workspace/lineage-merge.d.ts.map +1 -0
  159. package/dist/workspace/lineage-migrations.d.ts +178 -0
  160. package/dist/workspace/lineage-migrations.d.ts.map +1 -0
  161. package/dist/workspace/lineage-update.d.ts +59 -0
  162. package/dist/workspace/lineage-update.d.ts.map +1 -0
  163. package/dist/workspace/lineage-upgrade-cli.d.ts +40 -0
  164. package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -0
  165. package/dist/workspace/lineage-upgrade.d.ts +146 -0
  166. package/dist/workspace/lineage-upgrade.d.ts.map +1 -0
  167. package/dist/workspace/lineage-vendor.d.ts +63 -0
  168. package/dist/workspace/lineage-vendor.d.ts.map +1 -0
  169. package/dist/workspace/lineage-version.d.ts +32 -0
  170. package/dist/workspace/lineage-version.d.ts.map +1 -0
  171. package/dist/workspace/links.d.ts +150 -0
  172. package/dist/workspace/links.d.ts.map +1 -0
  173. package/dist/workspace/ls.d.ts +99 -0
  174. package/dist/workspace/ls.d.ts.map +1 -0
  175. package/dist/workspace/member-commands.d.ts +139 -0
  176. package/dist/workspace/member-commands.d.ts.map +1 -0
  177. package/dist/workspace/member-handles.d.ts +54 -0
  178. package/dist/workspace/member-handles.d.ts.map +1 -0
  179. package/dist/workspace/member-pipeline.d.ts +143 -0
  180. package/dist/workspace/member-pipeline.d.ts.map +1 -0
  181. package/dist/workspace/member-run.d.ts +67 -0
  182. package/dist/workspace/member-run.d.ts.map +1 -0
  183. package/dist/workspace/reason-codes.d.ts +65 -0
  184. package/dist/workspace/reason-codes.d.ts.map +1 -0
  185. package/dist/workspace/records-cli.d.ts +28 -4
  186. package/dist/workspace/records-cli.d.ts.map +1 -1
  187. package/dist/workspace/records.d.ts.map +1 -1
  188. package/dist/workspace/root-refusal.d.ts +53 -0
  189. package/dist/workspace/root-refusal.d.ts.map +1 -0
  190. package/dist/workspace/status.d.ts +150 -0
  191. package/dist/workspace/status.d.ts.map +1 -0
  192. package/dist/workspace/template-manifest.d.ts +90 -0
  193. package/dist/workspace/template-manifest.d.ts.map +1 -0
  194. package/dist/workspace/tree.d.ts +36 -0
  195. package/dist/workspace/tree.d.ts.map +1 -0
  196. package/dist/workspace/trust/attestor.d.ts +67 -0
  197. package/dist/workspace/trust/attestor.d.ts.map +1 -0
  198. package/dist/workspace/trust/policy.d.ts +111 -0
  199. package/dist/workspace/trust/policy.d.ts.map +1 -0
  200. package/dist/workspace/trust/provenance.d.ts +67 -0
  201. package/dist/workspace/trust/provenance.d.ts.map +1 -0
  202. package/dist/workspace/trust/ssh-commit.d.ts +43 -0
  203. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -0
  204. package/dist/workspace/trust/test-repo.d.ts +42 -0
  205. package/dist/workspace/trust/test-repo.d.ts.map +1 -0
  206. package/dist/workspace/trust/verify-cli.d.ts +9 -0
  207. package/dist/workspace/trust/verify-cli.d.ts.map +1 -0
  208. package/dist/workspace/trust/verify.d.ts +66 -0
  209. package/dist/workspace/trust/verify.d.ts.map +1 -0
  210. package/dist/workspace/which-chant.d.ts +58 -0
  211. package/dist/workspace/which-chant.d.ts.map +1 -0
  212. package/dist/workspace/workspace-kinds.schema.json +133 -0
  213. package/package.json +2 -1
  214. package/src/audit/discover.ts +66 -78
  215. package/src/audit/report-html.ts +3 -1
  216. package/src/audit/report-model.ts +14 -1
  217. package/src/audit/terraform-state.test.ts +4 -9
  218. package/src/audit/terraform-state.ts +4 -5
  219. package/src/cli/commands/audit-truncation.test.ts +167 -0
  220. package/src/cli/commands/audit.ts +89 -60
  221. package/src/cli/commands/check-lexicon.ts +24 -0
  222. package/src/cli/commands/doctor.test.ts +30 -0
  223. package/src/cli/commands/doctor.ts +18 -0
  224. package/src/cli/commands/import-agents.ts +6 -2
  225. package/src/cli/commands/init.ts +22 -3
  226. package/src/cli/commands/lint.test.ts +17 -23
  227. package/src/cli/commands/lint.ts +24 -84
  228. package/src/cli/commands/update.ts +13 -4
  229. package/src/cli/commands/vendor.ts +11 -6
  230. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +38 -0
  231. package/src/cli/handlers/build-member.test.ts +127 -0
  232. package/src/cli/handlers/build.ts +35 -1
  233. package/src/cli/handlers/components.test.ts +127 -0
  234. package/src/cli/handlers/components.ts +70 -8
  235. package/src/cli/handlers/dev.ts +5 -3
  236. package/src/cli/handlers/fan-out.ts +9 -2
  237. package/src/cli/handlers/init.ts +54 -1
  238. package/src/cli/handlers/operator.test.ts +68 -0
  239. package/src/cli/handlers/operator.ts +37 -9
  240. package/src/cli/handlers/promote.test.ts +118 -2
  241. package/src/cli/handlers/promote.ts +82 -16
  242. package/src/cli/handlers/run-generate-member.test.ts +83 -0
  243. package/src/cli/handlers/run-generate.test.ts +6 -8
  244. package/src/cli/handlers/run-generate.ts +36 -1
  245. package/src/cli/handlers/run.test.ts +47 -0
  246. package/src/cli/handlers/run.ts +28 -5
  247. package/src/cli/handlers/vendor.ts +147 -43
  248. package/src/cli/main.test.ts +105 -1
  249. package/src/cli/main.ts +230 -17
  250. package/src/cli/plugins.ts +17 -17
  251. package/src/cli/registry.ts +32 -0
  252. package/src/cli/static-config-read.test.ts +208 -0
  253. package/src/codegen/fetch.test.ts +63 -1
  254. package/src/codegen/fetch.ts +30 -1
  255. package/src/components/cli-support.ts +6 -1
  256. package/src/components/discover.test.ts +27 -57
  257. package/src/components/discover.ts +13 -68
  258. package/src/components/driver.test.ts +78 -1
  259. package/src/components/driver.ts +43 -7
  260. package/src/components/gate-plan.ts +53 -0
  261. package/src/components/promote.test.ts +276 -2
  262. package/src/components/promote.ts +119 -15
  263. package/src/components/sandbox/driver.ts +8 -8
  264. package/src/components/sandbox/run.ts +4 -1
  265. package/src/components/verbs/build-archive.ts +27 -21
  266. package/src/components/verbs/run-agent.ts +3 -5
  267. package/src/config-static.test.ts +136 -0
  268. package/src/config-static.ts +232 -0
  269. package/src/config.test.ts +2 -2
  270. package/src/config.ts +48 -15
  271. package/src/content-digest.test.ts +120 -0
  272. package/src/content-digest.ts +21 -0
  273. package/src/discovery/files.test.ts +10 -10
  274. package/src/discovery/files.ts +25 -81
  275. package/src/discovery/fold-import.ts +49 -5
  276. package/src/discovery/index.ts +1 -0
  277. package/src/discovery/sandbox/driver.ts +73 -35
  278. package/src/discovery/sandbox/fork-diagnostic.test.ts +136 -13
  279. package/src/discovery/sandbox/fork.ts +83 -43
  280. package/src/discovery/sandbox/path-lexicon-multifile.test.ts +285 -0
  281. package/src/discovery/walk.test.ts +263 -0
  282. package/src/discovery/walk.ts +334 -0
  283. package/src/effect-receipt.ts +2 -2
  284. package/src/graph-ir.ts +4 -1
  285. package/src/join-key.test.ts +25 -0
  286. package/src/join-key.ts +39 -0
  287. package/src/lexicon-module.ts +108 -10
  288. package/src/lexicon.ts +79 -1
  289. package/src/lifecycle/build-ledger-store.ts +11 -10
  290. package/src/lifecycle/digest.ts +9 -5
  291. package/src/lifecycle/gate-ledger.test.ts +20 -0
  292. package/src/lifecycle/gate-ledger.ts +28 -6
  293. package/src/lifecycle/git.test.ts +13 -1
  294. package/src/lifecycle/git.ts +221 -176
  295. package/src/lifecycle/lease.ts +25 -10
  296. package/src/lifecycle/legacy-digest.test.ts +115 -23
  297. package/src/lifecycle/legacy-digest.ts +60 -19
  298. package/src/lifecycle/member-ledger.test.ts +319 -0
  299. package/src/lifecycle/member-ledger.ts +145 -0
  300. package/src/lifecycle/plan-digest.ts +7 -7
  301. package/src/lifecycle/release-ledger.test.ts +20 -0
  302. package/src/lifecycle/release-ledger.ts +23 -7
  303. package/src/lifecycle/status.test.ts +151 -1
  304. package/src/lifecycle/status.ts +228 -7
  305. package/src/op/activities/activity-contracts.ts +37 -0
  306. package/src/op/activities/index.ts +10 -0
  307. package/src/op/activities/propose-upgrade.ts +206 -0
  308. package/src/op/discover.test.ts +14 -4
  309. package/src/op/discover.ts +19 -27
  310. package/src/op/gate-name.ts +8 -0
  311. package/src/op/gate-summary.test.ts +14 -0
  312. package/src/op/gate-summary.ts +25 -2
  313. package/src/op/gate.ts +36 -7
  314. package/src/op/generate-pipeline.test.ts +14 -5
  315. package/src/project-root.test.ts +66 -1
  316. package/src/project-root.ts +48 -0
  317. package/src/workspace/__fixtures__/contract-repo.ts +100 -0
  318. package/src/workspace/__fixtures__/two-member-workspace.ts +35 -0
  319. package/src/workspace/behold-kinds.test.ts +162 -0
  320. package/src/workspace/check-contract.test.ts +127 -0
  321. package/src/workspace/check.schema.json +347 -0
  322. package/src/workspace/checks/generated.test.ts +287 -0
  323. package/src/workspace/checks/generated.ts +475 -0
  324. package/src/workspace/checks/ledgers.test.ts +139 -0
  325. package/src/workspace/checks/ledgers.ts +246 -0
  326. package/src/workspace/checks/links.ts +183 -0
  327. package/src/workspace/checks/pipelines.test.ts +133 -0
  328. package/src/workspace/checks/pipelines.ts +225 -0
  329. package/src/workspace/checks-repo.test.ts +71 -0
  330. package/src/workspace/checks.test.ts +450 -0
  331. package/src/workspace/checks.ts +461 -0
  332. package/src/workspace/compose-graph.test.ts +146 -0
  333. package/src/workspace/compose-graph.ts +228 -0
  334. package/src/workspace/compose-reports.test.ts +109 -0
  335. package/src/workspace/compose-reports.ts +186 -0
  336. package/src/workspace/declaration.schema.json +434 -0
  337. package/src/workspace/declaration.test.ts +347 -0
  338. package/src/workspace/declaration.ts +623 -0
  339. package/src/workspace/generated-files.test.ts +114 -0
  340. package/src/workspace/generated-files.ts +94 -0
  341. package/src/workspace/glob.ts +49 -0
  342. package/src/workspace/graph-cli.ts +220 -0
  343. package/src/workspace/graph-contract.test.ts +204 -0
  344. package/src/workspace/graph.schema.json +662 -0
  345. package/src/workspace/init.test.ts +223 -0
  346. package/src/workspace/init.ts +585 -0
  347. package/src/workspace/jsonc.test.ts +65 -0
  348. package/src/workspace/jsonc.ts +231 -0
  349. package/src/workspace/kinds.test.ts +288 -0
  350. package/src/workspace/kinds.ts +506 -0
  351. package/src/workspace/lineage-check.ts +264 -0
  352. package/src/workspace/lineage-cli.ts +114 -0
  353. package/src/workspace/lineage-init.test.ts +231 -0
  354. package/src/workspace/lineage-init.ts +365 -0
  355. package/src/workspace/lineage-lock.test.ts +224 -0
  356. package/src/workspace/lineage-lock.ts +357 -0
  357. package/src/workspace/lineage-merge.ts +44 -0
  358. package/src/workspace/lineage-migrations.test.ts +178 -0
  359. package/src/workspace/lineage-migrations.ts +343 -0
  360. package/src/workspace/lineage-update.ts +160 -0
  361. package/src/workspace/lineage-upgrade-cli.ts +151 -0
  362. package/src/workspace/lineage-upgrade.test.ts +474 -0
  363. package/src/workspace/lineage-upgrade.ts +624 -0
  364. package/src/workspace/lineage-vendor.test.ts +126 -0
  365. package/src/workspace/lineage-vendor.ts +215 -0
  366. package/src/workspace/lineage-version.ts +127 -0
  367. package/src/workspace/links.test.ts +344 -0
  368. package/src/workspace/links.ts +331 -0
  369. package/src/workspace/ls-contract.test.ts +200 -0
  370. package/src/workspace/ls.schema.json +190 -0
  371. package/src/workspace/ls.ts +254 -0
  372. package/src/workspace/member-commands.e2e.test.ts +244 -0
  373. package/src/workspace/member-commands.test.ts +217 -0
  374. package/src/workspace/member-commands.ts +540 -0
  375. package/src/workspace/member-handles.test.ts +76 -0
  376. package/src/workspace/member-handles.ts +228 -0
  377. package/src/workspace/member-pipeline.test.ts +135 -0
  378. package/src/workspace/member-pipeline.ts +317 -0
  379. package/src/workspace/member-run.ts +146 -0
  380. package/src/workspace/read-contract.test.ts +129 -0
  381. package/src/workspace/reason-codes.test.ts +113 -0
  382. package/src/workspace/reason-codes.ts +81 -0
  383. package/src/workspace/records-cli.ts +86 -14
  384. package/src/workspace/records-contract.test.ts +5 -0
  385. package/src/workspace/records.schema.json +32 -2
  386. package/src/workspace/records.ts +3 -2
  387. package/src/workspace/root-refusal.ts +97 -0
  388. package/src/workspace/status-contract.test.ts +308 -0
  389. package/src/workspace/status.schema.json +210 -0
  390. package/src/workspace/status.ts +412 -0
  391. package/src/workspace/template-manifest.test.ts +79 -0
  392. package/src/workspace/template-manifest.ts +221 -0
  393. package/src/workspace/tree.ts +132 -0
  394. package/src/workspace/trust/attestor.ts +93 -0
  395. package/src/workspace/trust/policy.ts +306 -0
  396. package/src/workspace/trust/provenance.ts +181 -0
  397. package/src/workspace/trust/ssh-commit.ts +138 -0
  398. package/src/workspace/trust/test-repo.ts +138 -0
  399. package/src/workspace/trust/trust.test.ts +397 -0
  400. package/src/workspace/trust/verify-cli.ts +56 -0
  401. package/src/workspace/trust/verify.ts +194 -0
  402. package/src/workspace/which-chant.test.ts +117 -0
  403. package/src/workspace/which-chant.ts +151 -0
  404. package/src/workspace/workspace-kinds.schema.json +133 -0
  405. package/dist/components/unbound-gate-approval.d.ts +0 -24
  406. package/dist/components/unbound-gate-approval.d.ts.map +0 -1
  407. package/dist/discovery/convergence.d.ts +0 -97
  408. package/dist/discovery/convergence.d.ts.map +0 -1
  409. package/src/cli/commands/audit-walk-warnings.test.ts +0 -156
  410. package/src/components/unbound-gate-approval.test.ts +0 -82
  411. package/src/components/unbound-gate-approval.ts +0 -51
  412. package/src/discovery/convergence.test.ts +0 -231
  413. package/src/discovery/convergence.ts +0 -399
  414. package/src/op/discover-convergence.test.ts +0 -70
@@ -0,0 +1,506 @@
1
+ /**
2
+ * Member kinds (#2524 D3, #2535; ws-031 for the plugin shape, ws-051 for
3
+ * `examples`).
4
+ *
5
+ * A kind is data: a name, a precedence and a probe that says what its
6
+ * directory holds. Probes run no code (K3). Four kinds are built in: the
7
+ * member kinds `chant`, `workspace` and `other`, and the group kind
8
+ * `examples`. Every other kind comes from a pinned package, which publishes
9
+ * its kinds as a JSON file at a `./workspace-kinds` subpath, the way a
10
+ * lexicon publishes a slim `./detect` entry (#426). chant finds that file
11
+ * through the package's `package.json` and reads it with the file system, so
12
+ * reading kinds never imports the package and never loads a lexicon.
13
+ *
14
+ * The vocabulary is closed: a member whose kind no registry knows fails
15
+ * closed, and the message lists the known kinds. When the probes of several
16
+ * kinds claim one directory, the highest precedence decides, and a tie
17
+ * fails ({@link resolveKind}).
18
+ */
19
+
20
+ import { existsSync, readFileSync, statSync } from "node:fs";
21
+ import { createRequire } from "node:module";
22
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
23
+ import schema from "./workspace-kinds.schema.json";
24
+ import type { WorkspaceTree } from "./tree";
25
+ import { joinPath, skippedDir } from "./tree";
26
+
27
+ export const KINDS_SCHEMA_ID = schema.$id;
28
+
29
+ /** The subpath a package publishes its kinds at. */
30
+ export const KINDS_SUBPATH = "./workspace-kinds";
31
+
32
+ /**
33
+ * The probe a package's kind carries (#2535, #2545). It passes when any of
34
+ * its clauses does. A name in either clause may use `*`, which matches any
35
+ * run of characters in one file name, so `*.tf` is every Terraform file.
36
+ */
37
+ export interface FileProbe {
38
+ /** A file matching one of these names sits directly in the directory. */
39
+ anyFile?: string[];
40
+ /**
41
+ * A file directly in the directory whose name matches one of `in` has a
42
+ * line that opens an unlabelled block named in `blocks`: leading space,
43
+ * the name, optional space, then `{`. This is how a choudoufu root's
44
+ * `live {` block is found without parsing HCL (#2545).
45
+ */
46
+ anyBlock?: { in: string[]; blocks: string[] };
47
+ }
48
+
49
+ /** What a kind's probe checks in a directory. */
50
+ export type KindProbe =
51
+ /** Files, or blocks in files, sit directly in the directory. */
52
+ | FileProbe
53
+ /** The directory exists; nothing else is checked (`other`). */
54
+ | { directory: true }
55
+ /** The directory holds a chant project, as {@link holdsChantProject} says (`examples`). */
56
+ | { chantProject: true };
57
+
58
+ /**
59
+ * Which outputs a member of a kind exposes as link targets (#2524 D6,
60
+ * #2539). A member link may only name an output its producer exposes.
61
+ */
62
+ export type KindOutputs =
63
+ /** The chant project's own outputs, read from its source without running it (`chant`). */
64
+ | { from: "chant-source" }
65
+ /** None: the member is opaque to links (`workspace`, and the group kind `examples`). */
66
+ | { from: "none" }
67
+ /** The names listed here, plus any the member entry lists in `outputs` (`other`, and kinds from a package). */
68
+ | { from: "declared"; names: string[] };
69
+
70
+ export interface MemberKind {
71
+ name: string;
72
+ /** One line for listings and error messages. */
73
+ description: string;
74
+ probe: KindProbe;
75
+ /**
76
+ * When several kinds' probes claim one directory, the highest precedence
77
+ * decides; equal highest precedences are a tie, and a tie fails. `other`
78
+ * and `examples` are never claimants.
79
+ */
80
+ precedence: number;
81
+ /** A member kind, or the kind of an example group (ws-051). */
82
+ shape: "member" | "group";
83
+ /** The outputs a member of this kind exposes as link targets (#2539). */
84
+ outputs: KindOutputs;
85
+ /** Where the kind comes from: `builtin`, or the package that supplies it. */
86
+ source: string;
87
+ }
88
+
89
+ export interface KindRegistry {
90
+ get(name: string): MemberKind | undefined;
91
+ /** Every member kind's name, sorted, for "unknown kind" messages. */
92
+ names(): string[];
93
+ /** Every kind, group kinds included, in registration order. */
94
+ all(): MemberKind[];
95
+ }
96
+
97
+ /** The group kind (ws-051). An entry of this kind is a group, not a member. */
98
+ export const EXAMPLES_KIND = "examples";
99
+
100
+ export const BUILTIN_KINDS: readonly MemberKind[] = [
101
+ {
102
+ name: "chant",
103
+ description: "a chant project, with a chant.config.ts or chant.config.json in its directory",
104
+ probe: { anyFile: ["chant.config.ts", "chant.config.json"] },
105
+ precedence: 500,
106
+ shape: "member",
107
+ outputs: { from: "chant-source" },
108
+ source: "builtin",
109
+ },
110
+ {
111
+ name: "workspace",
112
+ description: "a nested workspace, with its own chant.workspace.json; opaque to the outer one",
113
+ probe: { anyFile: ["chant.workspace.json", "chant.workspace.jsonc"] },
114
+ precedence: 1000,
115
+ shape: "member",
116
+ outputs: { from: "none" },
117
+ source: "builtin",
118
+ },
119
+ {
120
+ name: "other",
121
+ description: "a directory chant does not read; the entry says why in `because`",
122
+ probe: { directory: true },
123
+ precedence: 0,
124
+ shape: "member",
125
+ outputs: { from: "declared", names: [] },
126
+ source: "builtin",
127
+ },
128
+ {
129
+ name: EXAMPLES_KIND,
130
+ description: "an example group: every directory its glob matches that holds a chant project is built and linted",
131
+ probe: { chantProject: true },
132
+ precedence: 0,
133
+ shape: "group",
134
+ outputs: { from: "none" },
135
+ source: "builtin",
136
+ },
137
+ ];
138
+
139
+ export const BUILTIN_KIND_NAMES: readonly string[] = BUILTIN_KINDS.map((k) => k.name);
140
+
141
+ /** A registry holding the built-in kinds and then `extra`, which must not repeat a name. */
142
+ export function createKindRegistry(extra: readonly MemberKind[] = []): KindRegistry {
143
+ const byName = new Map<string, MemberKind>();
144
+ for (const k of [...BUILTIN_KINDS, ...extra]) {
145
+ if (byName.has(k.name)) throw new Error(`kind ${k.name} is registered twice`);
146
+ byName.set(k.name, k);
147
+ }
148
+ return {
149
+ get: (name) => byName.get(name),
150
+ names: () => [...byName.values()].filter((k) => k.shape === "member").map((k) => k.name).sort(),
151
+ all: () => [...byName.values()],
152
+ };
153
+ }
154
+
155
+ export function builtinKindRegistry(): KindRegistry {
156
+ return createKindRegistry();
157
+ }
158
+
159
+ /** Whether `dir` (tree-relative) passes `kind`'s probe. The directory is known to exist. */
160
+ export function probeKind(kind: MemberKind, tree: WorkspaceTree, dir: string): boolean {
161
+ if ("directory" in kind.probe) return true;
162
+ if ("chantProject" in kind.probe) return holdsChantProject(tree, dir);
163
+ const { anyFile, anyBlock } = kind.probe;
164
+ if (anyFile && filesMatching(tree, dir, anyFile).length > 0) return true;
165
+ if (anyBlock) {
166
+ const opener = new RegExp(`^\\s*(?:${anyBlock.blocks.map(escapeRegExp).join("|")})\\s*\\{`, "m");
167
+ for (const file of filesMatching(tree, dir, anyBlock.in)) {
168
+ try {
169
+ if (opener.test(tree.read(file))) return true;
170
+ } catch {
171
+ // An unreadable file is no evidence either way.
172
+ }
173
+ }
174
+ }
175
+ return false;
176
+ }
177
+
178
+ /** Whether a probe looks at the directory's files, and so can claim it. */
179
+ function isFileProbe(probe: KindProbe): probe is FileProbe {
180
+ return !("directory" in probe) && !("chantProject" in probe);
181
+ }
182
+
183
+ /**
184
+ * The files directly in `dir` (tree-relative paths) whose names match one of
185
+ * `names`. A name without `*` is looked up directly, so the common case needs
186
+ * no listing.
187
+ */
188
+ function filesMatching(tree: WorkspaceTree, dir: string, names: readonly string[]): string[] {
189
+ const out: string[] = [];
190
+ const globs = names.filter((n) => n.includes("*"));
191
+ for (const name of names) {
192
+ if (!name.includes("*") && tree.stat(joinPath(dir, name)) === "file") out.push(joinPath(dir, name));
193
+ }
194
+ if (globs.length > 0) {
195
+ const patterns = globs.map((g) => new RegExp(`^${g.split("*").map(escapeRegExp).join("[^/]*")}$`));
196
+ for (const e of tree.list(dir) ?? []) {
197
+ if (e.type === "file" && patterns.some((p) => p.test(e.name))) out.push(joinPath(dir, e.name));
198
+ }
199
+ }
200
+ return out.sort();
201
+ }
202
+
203
+ function escapeRegExp(text: string): string {
204
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
205
+ }
206
+
207
+ export interface KindResolution {
208
+ /** Every member kind whose probe claims the directory, highest precedence first. */
209
+ claims: MemberKind[];
210
+ /** The kind the precedence order picks, when exactly one has the highest precedence. */
211
+ winner: MemberKind | undefined;
212
+ /** The kinds sharing the highest precedence, when there are two or more. A tie fails. */
213
+ tie: MemberKind[];
214
+ }
215
+
216
+ /**
217
+ * Which kind's probe claims `dir` (tree-relative). Only member kinds whose
218
+ * probe looks at the directory take part: `other` claims every directory and
219
+ * so claims none, and `examples` is a group kind. `exclude` leaves kinds out,
220
+ * such as `workspace` for the root member, whose directory holds the
221
+ * workspace's own declaration.
222
+ */
223
+ export function resolveKind(kinds: KindRegistry, tree: WorkspaceTree, dir: string, exclude: readonly string[] = []): KindResolution {
224
+ const claims = kinds
225
+ .all()
226
+ .filter((k) => k.shape === "member" && isFileProbe(k.probe) && !exclude.includes(k.name) && probeKind(k, tree, dir))
227
+ .sort((a, b) => b.precedence - a.precedence || (a.name < b.name ? -1 : 1));
228
+ const top = claims.filter((k) => k.precedence === claims[0]?.precedence);
229
+ return { claims, winner: top.length === 1 ? top[0] : undefined, tie: top.length > 1 ? top : [] };
230
+ }
231
+
232
+ const CONFIG_FILES = ["chant.config.ts", "chant.config.json"];
233
+ const PROJECT_SEARCH_DEPTH = 4;
234
+
235
+ /**
236
+ * Whether directory `dir` holds a chant project, for an example group's
237
+ * matches (ws-051). That is true when a chant config sits in it or up to four
238
+ * levels below it (many examples keep theirs in `src/`), or when its own
239
+ * `package.json` depends on `@intentius/chant` or a chant lexicon, which is
240
+ * how an example with no config names its lexicon.
241
+ */
242
+ export function holdsChantProject(tree: WorkspaceTree, dir: string): boolean {
243
+ const pkg = joinPath(dir, "package.json");
244
+ if (tree.stat(pkg) === "file") {
245
+ try {
246
+ const json = JSON.parse(tree.read(pkg)) as Record<string, unknown>;
247
+ for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
248
+ const deps = json[field];
249
+ if (deps && typeof deps === "object" && Object.keys(deps).some(isChantPackage)) return true;
250
+ }
251
+ } catch {
252
+ // An unreadable package.json names no lexicon; fall through to the config search.
253
+ }
254
+ }
255
+ const search = (at: string, depth: number): boolean => {
256
+ const entries = tree.list(at) ?? [];
257
+ if (entries.some((e) => e.type === "file" && CONFIG_FILES.includes(e.name))) return true;
258
+ if (depth === PROJECT_SEARCH_DEPTH) return false;
259
+ return entries.some((e) => e.type === "dir" && !skippedDir(e.name) && search(joinPath(at, e.name), depth + 1));
260
+ };
261
+ return search(dir, 0);
262
+ }
263
+
264
+ function isChantPackage(name: string): boolean {
265
+ return name === "@intentius/chant" || name.startsWith("@intentius/chant-lexicon-");
266
+ }
267
+
268
+ // ── Kinds as data ────────────────────────────────────────────────────────────
269
+
270
+ interface AjvError {
271
+ instancePath: string;
272
+ message?: string;
273
+ }
274
+ type Validate = ((data: unknown) => boolean) & { errors?: AjvError[] | null };
275
+
276
+ let compiled: Validate | undefined;
277
+ function validator(): Validate {
278
+ if (compiled) return compiled;
279
+ const require = createRequire(import.meta.url);
280
+ // ajv is CommonJS; its class is the default export, or that export's own default.
281
+ const mod = require("ajv/dist/2020") as { default?: unknown };
282
+ const Ajv = (mod.default ?? mod) as new (opts: object) => { compile(s: object): Validate };
283
+ compiled = new Ajv({ allErrors: true, strict: true }).compile(schema);
284
+ return compiled;
285
+ }
286
+
287
+ export interface KindData {
288
+ kinds: MemberKind[];
289
+ /** Why the data can't be used, one line each. Empty when it can. */
290
+ problems: string[];
291
+ }
292
+
293
+ /**
294
+ * Check the text of a kinds file against `workspace-kinds.schema.json` and
295
+ * the rules the schema can't say: no built-in name, and no name twice.
296
+ * `source` names the package in the kinds and in the messages.
297
+ */
298
+ export function parseKindData(text: string, source: string): KindData {
299
+ let raw: unknown;
300
+ try {
301
+ raw = JSON.parse(text);
302
+ } catch (err) {
303
+ return { kinds: [], problems: [`${source}: the kinds file is not JSON (${(err as Error).message})`] };
304
+ }
305
+ const validate = validator();
306
+ if (!validate(raw)) {
307
+ const problems = (validate.errors ?? []).map((e) => `${source}: ${e.instancePath || "the kinds file"} ${e.message ?? "is invalid"}`);
308
+ return { kinds: [], problems: [...new Set(problems)] };
309
+ }
310
+ const problems: string[] = [];
311
+ const kinds: MemberKind[] = [];
312
+ const seen = new Set<string>();
313
+ for (const k of (raw as { kinds: { name: string; description: string; precedence: number; probe: FileProbe; outputs?: string[] }[] }).kinds) {
314
+ if (BUILTIN_KIND_NAMES.includes(k.name)) {
315
+ problems.push(`${source}: kind ${k.name} is built in and can't be supplied by a package`);
316
+ continue;
317
+ }
318
+ if (seen.has(k.name)) {
319
+ problems.push(`${source}: kind ${k.name} is listed twice`);
320
+ continue;
321
+ }
322
+ seen.add(k.name);
323
+ kinds.push({
324
+ name: k.name,
325
+ description: k.description,
326
+ probe: {
327
+ ...(k.probe.anyFile ? { anyFile: [...k.probe.anyFile] } : {}),
328
+ ...(k.probe.anyBlock ? { anyBlock: { in: [...k.probe.anyBlock.in], blocks: [...k.probe.anyBlock.blocks] } } : {}),
329
+ },
330
+ precedence: k.precedence,
331
+ shape: "member",
332
+ outputs: { from: "declared", names: [...(k.outputs ?? [])] },
333
+ source,
334
+ });
335
+ }
336
+ return { kinds, problems };
337
+ }
338
+
339
+ export interface PackageKinds extends KindData {
340
+ /** The kinds file, absolute, or undefined when the package publishes none. */
341
+ file: string | undefined;
342
+ }
343
+
344
+ /**
345
+ * Where a package's `exports` send `./workspace-kinds`, or undefined when
346
+ * the package doesn't export that subpath. Only the literal key counts: a
347
+ * `./*` pattern maps the subpath to code, which chant never runs for kinds.
348
+ */
349
+ export function kindsExportTarget(pkg: Record<string, unknown>): string | undefined | { problem: string } {
350
+ const exports = pkg.exports;
351
+ if (!exports || typeof exports !== "object" || Array.isArray(exports)) return undefined;
352
+ const entry = (exports as Record<string, unknown>)[KINDS_SUBPATH];
353
+ if (entry === undefined) return undefined;
354
+ let target: unknown = entry;
355
+ if (target && typeof target === "object" && !Array.isArray(target)) {
356
+ const conditions = target as Record<string, unknown>;
357
+ target = conditions.default ?? conditions.import ?? conditions.require;
358
+ }
359
+ if (typeof target !== "string") {
360
+ return { problem: `exports["${KINDS_SUBPATH}"] must name one file, as a string or a "default" condition` };
361
+ }
362
+ if (!target.startsWith("./") || !target.endsWith(".json")) {
363
+ return { problem: `exports["${KINDS_SUBPATH}"] is ${target}; it must name a .json file inside the package, since chant reads kinds as data and never runs a package's code` };
364
+ }
365
+ return target;
366
+ }
367
+
368
+ /** Read the kinds a package directory publishes. Reads files only; imports nothing. */
369
+ export function readPackageKinds(packageDir: string, source?: string): PackageKinds {
370
+ const manifest = join(packageDir, "package.json");
371
+ let pkg: Record<string, unknown>;
372
+ try {
373
+ pkg = JSON.parse(readFileSync(manifest, "utf-8")) as Record<string, unknown>;
374
+ } catch {
375
+ return { kinds: [], problems: [`${source ?? packageDir}: no readable package.json in ${packageDir}`], file: undefined };
376
+ }
377
+ const name = source ?? (typeof pkg.name === "string" ? pkg.name : packageDir);
378
+ const target = kindsExportTarget(pkg);
379
+ if (target === undefined) return { kinds: [], problems: [], file: undefined };
380
+ if (typeof target !== "string") return { kinds: [], problems: [`${name}: ${target.problem}`], file: undefined };
381
+ const file = resolve(packageDir, target);
382
+ const inside = relative(packageDir, file);
383
+ if (inside.startsWith("..") || isAbsolute(inside)) {
384
+ return { kinds: [], problems: [`${name}: exports["${KINDS_SUBPATH}"] points outside the package`], file: undefined };
385
+ }
386
+ let text: string;
387
+ try {
388
+ text = readFileSync(file, "utf-8");
389
+ } catch {
390
+ return { kinds: [], problems: [`${name}: exports["${KINDS_SUBPATH}"] names ${target}, which does not exist`], file };
391
+ }
392
+ return { ...parseKindData(text, name), file };
393
+ }
394
+
395
+ /**
396
+ * The directory of an installed package `name`, found the way Node finds a
397
+ * bare import: `node_modules/<name>` in `fromDir` and each directory above it.
398
+ * It looks for the directory, not for an entry point, so it works for a
399
+ * package whose `exports` don't expose `package.json`.
400
+ */
401
+ export function findInstalledPackage(name: string, fromDir: string): string | undefined {
402
+ for (let dir = resolve(fromDir); ; dir = dirname(dir)) {
403
+ const candidate = join(dir, "node_modules", ...name.split("/"));
404
+ try {
405
+ if (statSync(candidate).isDirectory() && existsSync(join(candidate, "package.json"))) return candidate;
406
+ } catch {
407
+ // Not here; keep walking.
408
+ }
409
+ if (dirname(dir) === dir) return undefined;
410
+ }
411
+ }
412
+
413
+ export interface PinLike {
414
+ package: string | null;
415
+ version: string | null;
416
+ path: string | null;
417
+ }
418
+
419
+ export interface KindLoadProblem {
420
+ /** The pin's index in the declaration's `pins`. */
421
+ pin: number;
422
+ message: string;
423
+ }
424
+
425
+ export interface LoadedKinds {
426
+ registry: KindRegistry;
427
+ problems: KindLoadProblem[];
428
+ }
429
+
430
+ /**
431
+ * Build the registry for a workspace: the built-in kinds plus the kinds
432
+ * every pin publishes. `workspaceRoot` is the absolute workspace root; a
433
+ * package pin is looked up from there, and a path pin is relative to it.
434
+ * An installed version that differs from the pin, a kinds file that doesn't
435
+ * validate, and a kind name two packages both supply are problems; the kinds
436
+ * involved are left out, so members of those kinds read as unknown.
437
+ * Never throws.
438
+ */
439
+ export function loadKindRegistry(pins: readonly PinLike[], workspaceRoot: string): LoadedKinds {
440
+ const problems: KindLoadProblem[] = [];
441
+ const extra: MemberKind[] = [];
442
+ const owner = new Map<string, string>();
443
+ const clashing = new Set<string>();
444
+ pins.forEach((pin, i) => {
445
+ let dir: string | undefined;
446
+ let source: string;
447
+ if (pin.package) {
448
+ source = pin.package;
449
+ dir = findInstalledPackage(pin.package, workspaceRoot);
450
+ if (!dir) {
451
+ problems.push({ pin: i, message: `pinned package ${pin.package} is not installed; install it to read the kinds it supplies` });
452
+ return;
453
+ }
454
+ let installed: unknown;
455
+ try {
456
+ installed = (JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")) as { version?: unknown }).version;
457
+ } catch {
458
+ installed = undefined;
459
+ }
460
+ if (pin.version && installed !== pin.version) {
461
+ problems.push({ pin: i, message: `${pin.package} is pinned at ${pin.version}, and ${String(installed ?? "an unknown version")} is installed` });
462
+ return;
463
+ }
464
+ } else if (pin.path) {
465
+ source = pin.path;
466
+ dir = join(workspaceRoot, ...pin.path.split("/"));
467
+ } else {
468
+ return;
469
+ }
470
+ const read = readPackageKinds(dir, source);
471
+ for (const p of read.problems) problems.push({ pin: i, message: p });
472
+ for (const k of read.kinds) {
473
+ const first = owner.get(k.name);
474
+ if (first) {
475
+ clashing.add(k.name);
476
+ problems.push({ pin: i, message: `kind ${k.name} is supplied by both ${first} and ${source}; a kind name has one source` });
477
+ continue;
478
+ }
479
+ owner.set(k.name, source);
480
+ extra.push(k);
481
+ }
482
+ });
483
+ // A name two packages both supply is left out altogether: neither reading is safe.
484
+ return { registry: createKindRegistry(extra.filter((k) => !clashing.has(k.name))), problems };
485
+ }
486
+
487
+ /**
488
+ * Whether `file` (absolute, inside `packageDir`) is published, as far as the
489
+ * package's `files` list says. A package with no `files` list publishes
490
+ * everything npm doesn't ignore by default.
491
+ */
492
+ export function kindsFileShips(packageDir: string, file: string): boolean {
493
+ let pkg: { files?: unknown };
494
+ try {
495
+ pkg = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf-8")) as { files?: unknown };
496
+ } catch {
497
+ return false;
498
+ }
499
+ if (!Array.isArray(pkg.files)) return true;
500
+ const rel = relative(packageDir, file).split("\\").join("/");
501
+ return pkg.files.some((entry) => {
502
+ if (typeof entry !== "string") return false;
503
+ const e = entry.replace(/^\.\//, "").replace(/\/+$/, "");
504
+ return rel === e || rel.startsWith(`${e}/`);
505
+ });
506
+ }