@intentius/chant 0.124.31 → 0.124.33

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 (509) hide show
  1. package/bin/chant +7 -2
  2. package/dist/ci-jobs.d.ts +4 -0
  3. package/dist/ci-jobs.d.ts.map +1 -1
  4. package/dist/ci-jobs.js +9 -2
  5. package/dist/cli/commands/check-lexicon-plugin.d.ts +7 -4
  6. package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
  7. package/dist/cli/commands/check-lexicon-plugin.js +10 -7
  8. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  9. package/dist/cli/commands/check-lexicon.js +18 -12
  10. package/dist/cli/commands/import.d.ts +10 -0
  11. package/dist/cli/commands/import.d.ts.map +1 -1
  12. package/dist/cli/commands/import.js +37 -0
  13. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  14. package/dist/cli/commands/init-lexicon/templates/project.js +4 -3
  15. package/dist/cli/commands/onboard.d.ts.map +1 -1
  16. package/dist/cli/commands/onboard.js +8 -4
  17. package/dist/cli/commands/update.d.ts.map +1 -1
  18. package/dist/cli/commands/update.js +2 -1
  19. package/dist/cli/dependencies.d.ts +18 -0
  20. package/dist/cli/dependencies.d.ts.map +1 -0
  21. package/dist/cli/dependencies.js +120 -0
  22. package/dist/cli/handlers/build.d.ts.map +1 -1
  23. package/dist/cli/handlers/build.js +38 -4
  24. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  25. package/dist/cli/handlers/fan-out.js +12 -4
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/graph.js +16 -6
  28. package/dist/cli/handlers/lifecycle-health.d.ts +16 -0
  29. package/dist/cli/handlers/lifecycle-health.d.ts.map +1 -0
  30. package/dist/cli/handlers/lifecycle-health.js +150 -0
  31. package/dist/cli/handlers/lifecycle.d.ts +26 -0
  32. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  33. package/dist/cli/handlers/lifecycle.js +1 -1
  34. package/dist/cli/handlers/lint.d.ts.map +1 -1
  35. package/dist/cli/handlers/lint.js +6 -0
  36. package/dist/cli/handlers/operator.d.ts +2 -2
  37. package/dist/cli/handlers/operator.js +3 -3
  38. package/dist/cli/handlers/pr.d.ts +16 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -1
  40. package/dist/cli/handlers/pr.js +610 -32
  41. package/dist/cli/handlers/promote.d.ts.map +1 -1
  42. package/dist/cli/handlers/promote.js +19 -2
  43. package/dist/cli/handlers/release.d.ts +16 -1
  44. package/dist/cli/handlers/release.d.ts.map +1 -1
  45. package/dist/cli/handlers/release.js +83 -11
  46. package/dist/cli/handlers/run.d.ts +13 -1
  47. package/dist/cli/handlers/run.d.ts.map +1 -1
  48. package/dist/cli/handlers/run.js +38 -15
  49. package/dist/cli/main.d.ts.map +1 -1
  50. package/dist/cli/main.js +121 -33
  51. package/dist/cli/parse-args.d.ts.map +1 -1
  52. package/dist/cli/parse-args.js +37 -0
  53. package/dist/cli/registry.d.ts +29 -6
  54. package/dist/cli/registry.d.ts.map +1 -1
  55. package/dist/cli/registry.js +6 -2
  56. package/dist/codegen/generate-post-synth-barrel.js +2 -2
  57. package/dist/codegen/lexicon-regen.d.ts +4 -0
  58. package/dist/codegen/lexicon-regen.d.ts.map +1 -1
  59. package/dist/codegen/lexicon-regen.js +1 -1
  60. package/dist/codegen/pinned-upgrade.js +2 -2
  61. package/dist/components/capability.d.ts +44 -3
  62. package/dist/components/capability.d.ts.map +1 -1
  63. package/dist/components/capability.js +21 -0
  64. package/dist/components/changed-files.d.ts +7 -1
  65. package/dist/components/changed-files.d.ts.map +1 -1
  66. package/dist/components/changed-files.js +9 -1
  67. package/dist/components/deploy-inputs.d.ts +91 -0
  68. package/dist/components/deploy-inputs.d.ts.map +1 -0
  69. package/dist/components/deploy-inputs.js +184 -0
  70. package/dist/components/driver.d.ts +38 -0
  71. package/dist/components/driver.d.ts.map +1 -1
  72. package/dist/components/driver.js +56 -6
  73. package/dist/components/fan-out-record.d.ts +6 -1
  74. package/dist/components/fan-out-record.d.ts.map +1 -1
  75. package/dist/components/fan-out-record.js +24 -0
  76. package/dist/components/fan-out-run.d.ts +20 -0
  77. package/dist/components/fan-out-run.d.ts.map +1 -1
  78. package/dist/components/fan-out-run.js +21 -1
  79. package/dist/components/gate-plan.d.ts +8 -0
  80. package/dist/components/gate-plan.d.ts.map +1 -1
  81. package/dist/components/gate-plan.js +6 -0
  82. package/dist/components/pr-pipeline.d.ts +98 -12
  83. package/dist/components/pr-pipeline.d.ts.map +1 -1
  84. package/dist/components/pr-pipeline.js +146 -23
  85. package/dist/components/pr-run.d.ts +128 -30
  86. package/dist/components/pr-run.d.ts.map +1 -1
  87. package/dist/components/pr-run.js +290 -70
  88. package/dist/components/release-compile.d.ts +37 -2
  89. package/dist/components/release-compile.d.ts.map +1 -1
  90. package/dist/components/release-compile.js +64 -8
  91. package/dist/components/release-promote.d.ts +17 -3
  92. package/dist/components/release-promote.d.ts.map +1 -1
  93. package/dist/components/release-promote.js +79 -18
  94. package/dist/components/verbs/bom-writer.d.ts +1 -1
  95. package/dist/components/verbs/bom-writer.d.ts.map +1 -1
  96. package/dist/components/verbs/lockfile-sbom-generator.d.ts +20 -0
  97. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -1
  98. package/dist/components/verbs/lockfile-sbom-generator.js +41 -4
  99. package/dist/components/wave-plan.d.ts +15 -2
  100. package/dist/components/wave-plan.d.ts.map +1 -1
  101. package/dist/components/wave-plan.js +44 -5
  102. package/dist/discovery/fold-import.d.ts.map +1 -1
  103. package/dist/discovery/fold-import.js +16 -6
  104. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  105. package/dist/discovery/sandbox/bundle.js +6 -0
  106. package/dist/discovery/specifier-resolve.d.ts.map +1 -1
  107. package/dist/discovery/specifier-resolve.js +8 -2
  108. package/dist/fold/fold.d.ts.map +1 -1
  109. package/dist/fold/fold.js +68 -1
  110. package/dist/fold/subset.d.ts +37 -0
  111. package/dist/fold/subset.d.ts.map +1 -1
  112. package/dist/fold/subset.js +88 -0
  113. package/dist/graph-detail.d.ts.map +1 -1
  114. package/dist/graph-detail.js +32 -7
  115. package/dist/health.d.ts +110 -0
  116. package/dist/health.d.ts.map +1 -0
  117. package/dist/health.js +105 -0
  118. package/dist/health.schema.json +191 -0
  119. package/dist/lexicon-module.d.ts +10 -0
  120. package/dist/lexicon-module.d.ts.map +1 -1
  121. package/dist/lexicon-module.js +53 -8
  122. package/dist/lexicon-plugin-helpers.d.ts.map +1 -1
  123. package/dist/lexicon-plugin-helpers.js +6 -4
  124. package/dist/lexicon.d.ts +29 -0
  125. package/dist/lexicon.d.ts.map +1 -1
  126. package/dist/lifecycle/affected.d.ts.map +1 -1
  127. package/dist/lifecycle/affected.js +7 -1
  128. package/dist/lifecycle/merge-record.d.ts +104 -0
  129. package/dist/lifecycle/merge-record.d.ts.map +1 -0
  130. package/dist/lifecycle/merge-record.js +102 -0
  131. package/dist/lifecycle/publish-attachments.d.ts +8 -5
  132. package/dist/lifecycle/publish-attachments.d.ts.map +1 -1
  133. package/dist/lifecycle/publish-attachments.js +27 -13
  134. package/dist/lifecycle/publish-npm.d.ts +3 -2
  135. package/dist/lifecycle/publish-npm.d.ts.map +1 -1
  136. package/dist/lifecycle/publish-npm.js +4 -3
  137. package/dist/lifecycle/release-at.d.ts +40 -0
  138. package/dist/lifecycle/release-at.d.ts.map +1 -0
  139. package/dist/lifecycle/release-at.js +83 -0
  140. package/dist/lifecycle/release-cut.d.ts.map +1 -1
  141. package/dist/lifecycle/release-cut.js +23 -12
  142. package/dist/lifecycle/release-ledger.d.ts +21 -0
  143. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  144. package/dist/lifecycle/release-ledger.js +24 -0
  145. package/dist/lifecycle/release-publish.d.ts +28 -12
  146. package/dist/lifecycle/release-publish.d.ts.map +1 -1
  147. package/dist/lifecycle/release-publish.js +29 -17
  148. package/dist/lifecycle/release-store.d.ts +25 -2
  149. package/dist/lifecycle/release-store.d.ts.map +1 -1
  150. package/dist/lifecycle/release-store.js +40 -13
  151. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/run-ledger.js +1 -0
  153. package/dist/lifecycle/work-dir.d.ts +45 -0
  154. package/dist/lifecycle/work-dir.d.ts.map +1 -0
  155. package/dist/lifecycle/work-dir.js +78 -0
  156. package/dist/lint/discover.d.ts +17 -9
  157. package/dist/lint/discover.d.ts.map +1 -1
  158. package/dist/lint/discover.js +62 -54
  159. package/dist/lint/rules/op/index.d.ts +2 -1
  160. package/dist/lint/rules/op/index.d.ts.map +1 -1
  161. package/dist/lint/rules/op/index.js +4 -2
  162. package/dist/lint/rules/op/ops018-shell-image-digest.d.ts +10 -0
  163. package/dist/lint/rules/op/ops018-shell-image-digest.d.ts.map +1 -0
  164. package/dist/lint/rules/op/ops018-shell-image-digest.js +38 -0
  165. package/dist/module-source.d.ts +57 -0
  166. package/dist/module-source.d.ts.map +1 -0
  167. package/dist/module-source.js +104 -0
  168. package/dist/op/activities/activity-contracts.d.ts +5 -0
  169. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  170. package/dist/op/activities/activity-contracts.js +3 -0
  171. package/dist/op/activities/factory.js +1 -1
  172. package/dist/op/activities/shell.d.ts +38 -0
  173. package/dist/op/activities/shell.d.ts.map +1 -1
  174. package/dist/op/activities/shell.js +89 -3
  175. package/dist/op/builders.d.ts +7 -0
  176. package/dist/op/builders.d.ts.map +1 -1
  177. package/dist/op/builders.js +7 -0
  178. package/dist/op/discover.d.ts.map +1 -1
  179. package/dist/op/discover.js +13 -3
  180. package/dist/op/gate.d.ts.map +1 -1
  181. package/dist/op/gate.js +3 -0
  182. package/dist/op/op-waves-run.d.ts.map +1 -1
  183. package/dist/op/op-waves-run.js +20 -5
  184. package/dist/op/operator.d.ts +2 -2
  185. package/dist/op/operator.js +2 -2
  186. package/dist/op/runtime.d.ts +2 -0
  187. package/dist/op/runtime.d.ts.map +1 -1
  188. package/dist/op/steward.d.ts +6 -4
  189. package/dist/op/steward.d.ts.map +1 -1
  190. package/dist/op/steward.js +5 -3
  191. package/dist/op/work-lease-run.d.ts +20 -7
  192. package/dist/op/work-lease-run.d.ts.map +1 -1
  193. package/dist/op/work-lease-run.js +56 -12
  194. package/dist/pr-forge.d.ts +10 -0
  195. package/dist/pr-forge.d.ts.map +1 -1
  196. package/dist/pr-forge.js +39 -0
  197. package/dist/pr-loop.d.ts +155 -7
  198. package/dist/pr-loop.d.ts.map +1 -1
  199. package/dist/pr-loop.js +137 -11
  200. package/dist/pr-report-url.d.ts +4 -4
  201. package/dist/pr-report-url.d.ts.map +1 -1
  202. package/dist/pr-report-url.js +5 -5
  203. package/dist/runner-start.d.ts +179 -0
  204. package/dist/runner-start.d.ts.map +1 -0
  205. package/dist/runner-start.js +277 -0
  206. package/dist/ts-loader.d.ts +38 -4
  207. package/dist/ts-loader.d.ts.map +1 -1
  208. package/dist/ts-loader.js +190 -16
  209. package/dist/wave-runtime.mjs +238 -231
  210. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts +34 -0
  211. package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts.map +1 -0
  212. package/dist/workspace/chant-migrations/fountain-retired-kinds.js +176 -0
  213. package/dist/workspace/chant-migrations.d.ts.map +1 -1
  214. package/dist/workspace/chant-migrations.js +2 -0
  215. package/dist/workspace/check.schema.json +70 -2
  216. package/dist/workspace/checks/boxes.d.ts +6 -6
  217. package/dist/workspace/checks/boxes.js +9 -9
  218. package/dist/workspace/checks/security.d.ts +35 -0
  219. package/dist/workspace/checks/security.d.ts.map +1 -0
  220. package/dist/workspace/checks/security.js +305 -0
  221. package/dist/workspace/checks.d.ts +2 -0
  222. package/dist/workspace/checks.d.ts.map +1 -1
  223. package/dist/workspace/checks.js +5 -0
  224. package/dist/workspace/ci-builds.d.ts +163 -0
  225. package/dist/workspace/ci-builds.d.ts.map +1 -0
  226. package/dist/workspace/ci-builds.js +315 -0
  227. package/dist/workspace/ci-green-cli.d.ts +2 -1
  228. package/dist/workspace/ci-green-cli.d.ts.map +1 -1
  229. package/dist/workspace/ci-green-cli.js +25 -5
  230. package/dist/workspace/ci-green-forge.d.ts +18 -4
  231. package/dist/workspace/ci-green-forge.d.ts.map +1 -1
  232. package/dist/workspace/ci-green-forge.js +12 -0
  233. package/dist/workspace/ci-green-workflow.d.ts +55 -1
  234. package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
  235. package/dist/workspace/ci-green-workflow.js +128 -1
  236. package/dist/workspace/ci-green.d.ts +117 -16
  237. package/dist/workspace/ci-green.d.ts.map +1 -1
  238. package/dist/workspace/ci-green.js +358 -43
  239. package/dist/workspace/ci-last-green.schema.json +49 -0
  240. package/dist/workspace/ci-list.schema.json +47 -7
  241. package/dist/workspace/ci-report-url.d.ts +18 -0
  242. package/dist/workspace/ci-report-url.d.ts.map +1 -0
  243. package/dist/workspace/ci-report-url.js +33 -0
  244. package/dist/workspace/ci-run-index.d.ts +13 -1
  245. package/dist/workspace/ci-run-index.d.ts.map +1 -1
  246. package/dist/workspace/ci-run-index.js +6 -4
  247. package/dist/workspace/ci-run-index.schema.json +6 -4
  248. package/dist/workspace/ci-run.d.ts +85 -6
  249. package/dist/workspace/ci-run.d.ts.map +1 -1
  250. package/dist/workspace/ci-run.js +262 -64
  251. package/dist/workspace/ci-runner-key.d.ts +16 -3
  252. package/dist/workspace/ci-runner-key.d.ts.map +1 -1
  253. package/dist/workspace/ci-runner-key.js +30 -10
  254. package/dist/workspace/ci-runner-start.d.ts +77 -0
  255. package/dist/workspace/ci-runner-start.d.ts.map +1 -0
  256. package/dist/workspace/ci-runner-start.js +185 -0
  257. package/dist/workspace/ci-serve.d.ts +130 -11
  258. package/dist/workspace/ci-serve.d.ts.map +1 -1
  259. package/dist/workspace/ci-serve.js +323 -40
  260. package/dist/workspace/declaration.d.ts +25 -0
  261. package/dist/workspace/declaration.d.ts.map +1 -1
  262. package/dist/workspace/declaration.js +14 -2
  263. package/dist/workspace/declaration.schema.json +30 -2
  264. package/dist/workspace/export.d.ts +1 -1
  265. package/dist/workspace/export.d.ts.map +1 -1
  266. package/dist/workspace/export.js +7 -3
  267. package/dist/workspace/ls.d.ts +8 -1
  268. package/dist/workspace/ls.d.ts.map +1 -1
  269. package/dist/workspace/ls.js +2 -1
  270. package/dist/workspace/ls.schema.json +9 -2
  271. package/dist/workspace/member-pipeline.d.ts +1 -0
  272. package/dist/workspace/member-pipeline.d.ts.map +1 -1
  273. package/dist/workspace/member-pipeline.js +2 -0
  274. package/dist/workspace/merge-record.schema.json +49 -0
  275. package/dist/workspace/pin-integrity.d.ts.map +1 -1
  276. package/dist/workspace/pin-integrity.js +3 -2
  277. package/dist/workspace/pr-report.schema.json +75 -8
  278. package/dist/workspace/reason-codes.d.ts +18 -1
  279. package/dist/workspace/reason-codes.d.ts.map +1 -1
  280. package/dist/workspace/reason-codes.js +20 -2
  281. package/dist/workspace/release-candidates.d.ts +129 -0
  282. package/dist/workspace/release-candidates.d.ts.map +1 -0
  283. package/dist/workspace/release-candidates.js +233 -0
  284. package/dist/workspace/release-candidates.schema.json +353 -0
  285. package/dist/workspace/run-event.schema.json +3 -1
  286. package/dist/workspace/security.d.ts +40 -0
  287. package/dist/workspace/security.d.ts.map +1 -0
  288. package/dist/workspace/security.js +99 -0
  289. package/dist/workspace/status.schema.json +3 -1
  290. package/dist/workspace/write-scope.d.ts +9 -0
  291. package/dist/workspace/write-scope.d.ts.map +1 -1
  292. package/dist/workspace/write-scope.js +11 -1
  293. package/package.json +8 -1
  294. package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
  295. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +1 -1
  296. package/src/ci-jobs.ts +11 -2
  297. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +3 -3
  298. package/src/cli/commands/audit.test.ts +2 -2
  299. package/src/cli/commands/check-lexicon-plugin.test.ts +9 -0
  300. package/src/cli/commands/check-lexicon-plugin.ts +11 -8
  301. package/src/cli/commands/check-lexicon.test.ts +1 -1
  302. package/src/cli/commands/check-lexicon.ts +16 -11
  303. package/src/cli/commands/import.ts +40 -0
  304. package/src/cli/commands/init-lexicon/templates/project.ts +4 -3
  305. package/src/cli/commands/init-lexicon.test.ts +8 -5
  306. package/src/cli/commands/onboard.test.ts +45 -0
  307. package/src/cli/commands/onboard.ts +8 -4
  308. package/src/cli/commands/update.test.ts +6 -0
  309. package/src/cli/commands/update.ts +4 -1
  310. package/src/cli/compiled-cli.e2e.test.ts +76 -11
  311. package/src/cli/dependencies.e2e.test.ts +101 -0
  312. package/src/cli/dependencies.test.ts +93 -0
  313. package/src/cli/dependencies.ts +122 -0
  314. package/src/cli/handlers/build.test.ts +105 -0
  315. package/src/cli/handlers/build.ts +35 -4
  316. package/src/cli/handlers/fan-out.test.ts +73 -0
  317. package/src/cli/handlers/fan-out.ts +11 -4
  318. package/src/cli/handlers/graph.test.ts +76 -0
  319. package/src/cli/handlers/graph.ts +19 -12
  320. package/src/cli/handlers/lifecycle-health.test.ts +123 -0
  321. package/src/cli/handlers/lifecycle-health.ts +157 -0
  322. package/src/cli/handlers/lifecycle.ts +1 -1
  323. package/src/cli/handlers/lint.test.ts +42 -0
  324. package/src/cli/handlers/lint.ts +6 -0
  325. package/src/cli/handlers/operator.ts +3 -3
  326. package/src/cli/handlers/pr-deploy-inputs.test.ts +209 -0
  327. package/src/cli/handlers/pr-record.test.ts +201 -0
  328. package/src/cli/handlers/pr-waves.test.ts +449 -0
  329. package/src/cli/handlers/pr.test.ts +156 -0
  330. package/src/cli/handlers/pr.ts +648 -33
  331. package/src/cli/handlers/promote.test.ts +43 -1
  332. package/src/cli/handlers/promote.ts +19 -3
  333. package/src/cli/handlers/release-cut-at.e2e.test.ts +115 -0
  334. package/src/cli/handlers/release-publish-targets.e2e.test.ts +2 -2
  335. package/src/cli/handlers/release-verify.e2e.test.ts +12 -10
  336. package/src/cli/handlers/release.e2e.test.ts +19 -28
  337. package/src/cli/handlers/release.ts +81 -11
  338. package/src/cli/handlers/run-components-exit.test.ts +99 -0
  339. package/src/cli/handlers/run-signer.test.ts +79 -0
  340. package/src/cli/handlers/run.ts +34 -16
  341. package/src/cli/main.test.ts +18 -0
  342. package/src/cli/main.ts +120 -33
  343. package/src/cli/parse-args.ts +28 -0
  344. package/src/cli/registry.ts +35 -8
  345. package/src/codegen/generate-post-synth-barrel.ts +2 -2
  346. package/src/codegen/lexicon-regen.ts +1 -1
  347. package/src/codegen/pinned-upgrade.ts +2 -2
  348. package/src/codegen/post-synth-barrel-guards.test.ts +6 -11
  349. package/src/components/capability.ts +51 -3
  350. package/src/components/changed-files.test.ts +16 -1
  351. package/src/components/changed-files.ts +9 -1
  352. package/src/components/deploy-inputs.test.ts +108 -0
  353. package/src/components/deploy-inputs.ts +225 -0
  354. package/src/components/driver.test.ts +36 -1
  355. package/src/components/driver.ts +87 -4
  356. package/src/components/fan-out-record.ts +29 -1
  357. package/src/components/fan-out-run.test.ts +35 -0
  358. package/src/components/fan-out-run.ts +40 -1
  359. package/src/components/gate-plan.ts +9 -0
  360. package/src/components/pr-pipeline.test.ts +100 -0
  361. package/src/components/pr-pipeline.ts +184 -28
  362. package/src/components/pr-run.test.ts +323 -18
  363. package/src/components/pr-run.ts +355 -76
  364. package/src/components/release-compile.test.ts +34 -0
  365. package/src/components/release-compile.ts +89 -8
  366. package/src/components/release-promote.test.ts +55 -2
  367. package/src/components/release-promote.ts +93 -23
  368. package/src/components/verbs/bom-writer.ts +1 -1
  369. package/src/components/verbs/lockfile-sbom-generator.test.ts +36 -0
  370. package/src/components/verbs/lockfile-sbom-generator.ts +43 -5
  371. package/src/components/wave-plan.ts +48 -8
  372. package/src/discovery/fold-host-method.test.ts +87 -0
  373. package/src/discovery/fold-import.ts +15 -5
  374. package/src/discovery/fold-package-composite.test.ts +27 -0
  375. package/src/discovery/fold-specifiers.test.ts +8 -0
  376. package/src/discovery/sandbox/bundle.ts +6 -0
  377. package/src/discovery/specifier-resolve.ts +8 -2
  378. package/src/fold/fold.test.ts +72 -0
  379. package/src/fold/fold.ts +71 -0
  380. package/src/fold/subset.test.ts +31 -0
  381. package/src/fold/subset.ts +99 -0
  382. package/src/graph-detail.test.ts +57 -0
  383. package/src/graph-detail.ts +33 -7
  384. package/src/health.schema.json +191 -0
  385. package/src/health.test.ts +62 -0
  386. package/src/health.ts +178 -0
  387. package/src/lexicon-dist.e2e.test.ts +254 -0
  388. package/src/lexicon-module.test.ts +47 -0
  389. package/src/lexicon-module.ts +49 -7
  390. package/src/lexicon-plugin-helpers.ts +6 -4
  391. package/src/lexicon.ts +43 -1
  392. package/src/lifecycle/affected.test.ts +7 -0
  393. package/src/lifecycle/affected.ts +6 -1
  394. package/src/lifecycle/merge-record.test.ts +111 -0
  395. package/src/lifecycle/merge-record.ts +154 -0
  396. package/src/lifecycle/publish-attachments.ts +25 -13
  397. package/src/lifecycle/publish-npm.ts +4 -3
  398. package/src/lifecycle/publish-targets.test.ts +34 -4
  399. package/src/lifecycle/release-at.test.ts +48 -0
  400. package/src/lifecycle/release-at.ts +100 -0
  401. package/src/lifecycle/release-cut.test.ts +41 -0
  402. package/src/lifecycle/release-cut.ts +22 -11
  403. package/src/lifecycle/release-ledger.ts +34 -0
  404. package/src/lifecycle/release-publish.test.ts +43 -13
  405. package/src/lifecycle/release-publish.ts +38 -18
  406. package/src/lifecycle/release-store.ts +57 -13
  407. package/src/lifecycle/run-ledger.test.ts +13 -0
  408. package/src/lifecycle/run-ledger.ts +1 -0
  409. package/src/lifecycle/work-dir.test.ts +77 -0
  410. package/src/lifecycle/work-dir.ts +82 -0
  411. package/src/lint/discover.test.ts +46 -2
  412. package/src/lint/discover.ts +55 -49
  413. package/src/lint/rules/op/index.ts +4 -2
  414. package/src/lint/rules/op/ops018-shell-image-digest.test.ts +60 -0
  415. package/src/lint/rules/op/ops018-shell-image-digest.ts +48 -0
  416. package/src/module-source.test.ts +85 -0
  417. package/src/module-source.ts +112 -0
  418. package/src/op/activities/activity-contracts.ts +3 -0
  419. package/src/op/activities/factory.ts +1 -1
  420. package/src/op/activities/shell-container.e2e.test.ts +67 -0
  421. package/src/op/activities/shell.test.ts +44 -1
  422. package/src/op/activities/shell.ts +110 -3
  423. package/src/op/builders.ts +7 -0
  424. package/src/op/discover-root.test.ts +31 -2
  425. package/src/op/discover.ts +14 -4
  426. package/src/op/gate.test.ts +30 -0
  427. package/src/op/gate.ts +3 -0
  428. package/src/op/op-waves-run.ts +20 -5
  429. package/src/op/op-waves.test.ts +49 -0
  430. package/src/op/operator.ts +2 -2
  431. package/src/op/runtime.ts +2 -0
  432. package/src/op/step-console.test.ts +4 -2
  433. package/src/op/steward.ts +6 -4
  434. package/src/op/work-lease-run.test.ts +88 -2
  435. package/src/op/work-lease-run.ts +52 -12
  436. package/src/pr-forge-bundle.test.ts +2 -2
  437. package/src/pr-forge.test.ts +42 -0
  438. package/src/pr-forge.ts +40 -0
  439. package/src/pr-loop-bundle.test.ts +2 -1
  440. package/src/pr-loop.test.ts +146 -1
  441. package/src/pr-loop.ts +278 -17
  442. package/src/pr-report-url.ts +7 -7
  443. package/src/runner-start-bundle.test.ts +29 -0
  444. package/src/runner-start.test.ts +179 -0
  445. package/src/runner-start.ts +329 -0
  446. package/src/terraform/__fixtures__/advise.test.ts +21 -2
  447. package/src/ts-loader.test.ts +89 -1
  448. package/src/ts-loader.ts +180 -13
  449. package/src/workspace/changes.test.ts +1 -1
  450. package/src/workspace/chant-migrations/fountain-retired-kinds.test.ts +33 -0
  451. package/src/workspace/chant-migrations/fountain-retired-kinds.ts +190 -0
  452. package/src/workspace/chant-migrations.e2e.test.ts +5 -0
  453. package/src/workspace/chant-migrations.ts +2 -0
  454. package/src/workspace/check-contract.test.ts +3 -2
  455. package/src/workspace/check.schema.json +70 -2
  456. package/src/workspace/checks/boxes.ts +9 -9
  457. package/src/workspace/checks/security.test.ts +138 -0
  458. package/src/workspace/checks/security.ts +305 -0
  459. package/src/workspace/checks.ts +5 -0
  460. package/src/workspace/ci-builds.e2e.test.ts +208 -0
  461. package/src/workspace/ci-builds.test.ts +174 -0
  462. package/src/workspace/ci-builds.ts +385 -0
  463. package/src/workspace/ci-green-builds.test.ts +180 -0
  464. package/src/workspace/ci-green-cli.test.ts +54 -0
  465. package/src/workspace/ci-green-cli.ts +26 -5
  466. package/src/workspace/ci-green-forge.ts +30 -4
  467. package/src/workspace/ci-green-runs.test.ts +53 -11
  468. package/src/workspace/ci-green-workflow.test.ts +84 -1
  469. package/src/workspace/ci-green-workflow.ts +139 -2
  470. package/src/workspace/ci-green.test.ts +6 -3
  471. package/src/workspace/ci-green.ts +408 -48
  472. package/src/workspace/ci-last-green.schema.json +49 -0
  473. package/src/workspace/ci-list.schema.json +47 -7
  474. package/src/workspace/ci-report-url.test.ts +220 -0
  475. package/src/workspace/ci-report-url.ts +33 -0
  476. package/src/workspace/ci-run-index.schema.json +6 -4
  477. package/src/workspace/ci-run-index.test.ts +42 -3
  478. package/src/workspace/ci-run-index.ts +19 -5
  479. package/src/workspace/ci-run.test.ts +203 -8
  480. package/src/workspace/ci-run.ts +295 -63
  481. package/src/workspace/ci-runner-key.test.ts +55 -17
  482. package/src/workspace/ci-runner-key.ts +36 -11
  483. package/src/workspace/ci-runner-start.test.ts +151 -0
  484. package/src/workspace/ci-runner-start.ts +193 -0
  485. package/src/workspace/ci-serve-builds.test.ts +86 -0
  486. package/src/workspace/ci-serve.test.ts +209 -6
  487. package/src/workspace/ci-serve.ts +341 -42
  488. package/src/workspace/declaration.schema.json +30 -2
  489. package/src/workspace/declaration.test.ts +40 -0
  490. package/src/workspace/declaration.ts +40 -3
  491. package/src/workspace/export.ts +6 -3
  492. package/src/workspace/ls.schema.json +9 -2
  493. package/src/workspace/ls.ts +10 -4
  494. package/src/workspace/member-pipeline.ts +2 -1
  495. package/src/workspace/merge-record.schema.json +49 -0
  496. package/src/workspace/pin-integrity.test.ts +5 -0
  497. package/src/workspace/pin-integrity.ts +3 -2
  498. package/src/workspace/pr-report.schema.json +75 -8
  499. package/src/workspace/reason-codes.test.ts +2 -0
  500. package/src/workspace/reason-codes.ts +20 -2
  501. package/src/workspace/release-candidates.schema.json +353 -0
  502. package/src/workspace/release-candidates.test.ts +106 -0
  503. package/src/workspace/release-candidates.ts +315 -0
  504. package/src/workspace/run-event.schema.json +3 -1
  505. package/src/workspace/security.test.ts +70 -0
  506. package/src/workspace/security.ts +118 -0
  507. package/src/workspace/status.schema.json +3 -1
  508. package/src/workspace/write-scope.test.ts +29 -1
  509. package/src/workspace/write-scope.ts +12 -1
@@ -0,0 +1,48 @@
1
+ <!-- chant-pr:prod -->
2
+ ### chant apply for `prod`
3
+
4
+ Wave 2 waits at its gate `release-wave-2`; nothing in it applied. Head `222222222222`, measured from `111111111111`.
5
+
6
+ > Wave 2 was planned after the waves before it applied, and the pull request's approved plan does not cover it.
7
+
8
+ | Member | Component | Status | Create | Update | Replace | Delete |
9
+ |---|---|---|---:|---:|---:|---:|
10
+ | `a` | a | applied | 0 | 1 | 0 | 0 |
11
+ | `app` | app | planned | 0 | 0 | 0 | 0 |
12
+
13
+ | Wave | Components | Status | Approval |
14
+ |---:|---|---|---|
15
+ | 1 | `a` | applied | the pull request's `pr-apply` by `github:alice` |
16
+ | 2 | `app` | waiting | its own `release-wave-2`, not approved yet |
17
+
18
+ Wave 2 was planned after the waves before it applied, and the approved plan does not cover it:
19
+
20
+ - app now writes app.main.cidr to a different value than the approved plan
21
+
22
+ Read wave 2's plan, `jcs1-sha256:0000000000000000000000000000000000000000000000000000000000000007`, and approve it with:
23
+
24
+ ```
25
+ chant approve pr-12 release-wave-2 --plan jcs1-sha256:0000000000000000000000000000000000000000000000000000000000000007 --approver github:<your-login> --sign
26
+ ```
27
+
28
+ Then run the wave's apply job again.
29
+
30
+ Plan digest: `jcs1-sha256:7623a8677afb0bf98d77c602521a3abfa96f76cff25675d350a28c2e26a7bad0`
31
+
32
+ Approved by `github:alice` for this digest.
33
+
34
+ ### Plan summary
35
+
36
+ 2 members: 2 groups, 0 destroys or replacements.
37
+
38
+ #### Group e84467713bf6: 1 member (outlier), change
39
+
40
+ ```
41
+ ~ terraform_data.subnet: input
42
+ ```
43
+
44
+ Members: `a`
45
+
46
+ #### Group 49648f9475c7: 1 member (outlier), no changes
47
+
48
+ Members: `app`
@@ -18,7 +18,7 @@ A reviewer who approved this pull request approves the plan with:
18
18
  chant approve pr-12 pr-apply --plan jcs1-sha256:7623a8677afb0bf98d77c602521a3abfa96f76cff25675d350a28c2e26a7bad0 --approver github:<your-login> --sign
19
19
  ```
20
20
 
21
- It applies on merge if the plan is still this one. If it moved, the apply refuses and names both digests.
21
+ On merge the plan is recorded, and a release deploys it. With apply on merge it applies if the plan is still this one; if it moved, the apply refuses and names both digests.
22
22
 
23
23
  ### Plan summary
24
24
 
package/src/ci-jobs.ts CHANGED
@@ -417,6 +417,12 @@ export const GITLAB_SCHEDULE_SOURCE = '$CI_PIPELINE_SOURCE == "schedule"';
417
417
  /** A job variable that makes the runner clone the whole history, which a job reading the base commit needs. */
418
418
  export const GITLAB_FULL_HISTORY = { GIT_DEPTH: "0" } as const;
419
419
 
420
+ /** The tags a build request is pushed as (#4169), as a glob for a trigger. */
421
+ export const BUILD_REQUEST_TAGS = "ci/build/**";
422
+
423
+ /** The `rules:` if-expression for a build request's tag (#4169). */
424
+ export const GITLAB_BUILD_REQUEST_RULE = "$CI_COMMIT_TAG =~ /^ci\\/build\\//";
425
+
420
426
  /** The `rules:` if-expression for a push to `branch`, a quoted name or an expression such as `$CI_DEFAULT_BRANCH`. */
421
427
  export function gitlabPushRule(branch: string): string {
422
428
  return `$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == ${branch}`;
@@ -462,11 +468,14 @@ export function gitlabRules(subject: string, trigger: OpTrigger, selector: { var
462
468
  return { if: `${GITLAB_MERGE_REQUEST_SOURCE} && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "${branch}"` };
463
469
  });
464
470
  }
465
- case "push":
466
- return pushBranches(trigger.branches).map((branch) => {
471
+ case "push": {
472
+ const rules = pushBranches(trigger.branches).map((branch) => {
467
473
  assertGitlabBranch(subject, branch);
468
474
  return { if: gitlabPushRule(JSON.stringify(branch)) };
469
475
  });
476
+ // #4169: a newest build also runs at each build request's tag.
477
+ return trigger.build === "newest" ? [...rules, { if: GITLAB_BUILD_REQUEST_RULE }] : rules;
478
+ }
470
479
  }
471
480
  }
472
481
 
@@ -11,12 +11,12 @@
11
11
  ".": {
12
12
  "development": "./src/index.ts",
13
13
  "types": "./dist/index.d.ts",
14
- "default": "./src/index.ts"
14
+ "default": "./dist/index.js"
15
15
  },
16
16
  "./*": {
17
17
  "development": "./src/*.ts",
18
18
  "types": "./dist/*.d.ts",
19
- "default": "./src/*.ts"
19
+ "default": "./dist/*.js"
20
20
  },
21
21
  "./manifest": "./dist/manifest.json",
22
22
  "./meta": "./dist/meta.json",
@@ -26,7 +26,7 @@
26
26
  "generate": "npx tsx src/codegen/generate-cli.ts",
27
27
  "validate": "npx tsx src/validate-cli.ts",
28
28
  "docs": "npx tsx src/codegen/docs-cli.ts",
29
- "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete",
29
+ "build": "tsc -p tsconfig.build.json --sourceMap false && tsc-alias -p tsconfig.build.json",
30
30
  "prepack": "npm run generate && npm run bundle && npm run validate && npm run build",
31
31
  "bundle": "tsx src/package-cli.ts"
32
32
  },
@@ -153,13 +153,13 @@ describe("auditCommand", () => {
153
153
  const envelope = JSON.parse(json.output) as { findings: Array<{ checkId: string; authority: Array<{ url: string }>; severity: string }> };
154
154
  const ftn11 = envelope.findings.find((f) => f.checkId === "FTN011")!;
155
155
  expect(ftn11.authority.length).toBeGreaterThan(0);
156
- expect(ftn11.authority[0].url).toContain("fountain");
156
+ expect(ftn11.authority[0].url).toContain("managoat");
157
157
  expect(envelope.findings.find((f) => f.checkId === "FTN012")!.severity).toBe("error");
158
158
 
159
159
  const sarif = await auditCommand({ path: repo, format: "sarif" });
160
160
  const run = (JSON.parse(sarif.output) as { runs: Array<{ tool: { driver: { rules: Array<{ id: string; helpUri?: string }> } }; results: Array<{ ruleId: string }> }> }).runs[0];
161
161
  expect(run.results.some((r) => r.ruleId === "FTN011")).toBe(true);
162
- expect(run.tool.driver.rules.find((r) => r.id === "FTN011")!.helpUri).toContain("fountain");
162
+ expect(run.tool.driver.rules.find((r) => r.id === "FTN011")!.helpUri).toContain("managoat");
163
163
 
164
164
  const md = await auditCommand({ path: repo, format: "markdown" });
165
165
  expect(md.output).toContain("FTN011");
@@ -55,6 +55,15 @@ describe("pluginEntryFor", () => {
55
55
  expect(pluginEntryFor(dir)).toBe(join(dir, "src/plugin.ts"));
56
56
  });
57
57
 
58
+ test("prefers the development source over the compiled default (#3981)", () => {
59
+ const dir = lexiconDir({
60
+ "package.json": JSON.stringify({ exports: { ".": { development: "./src/index.ts", default: "./dist/index.js" } } }),
61
+ "src/index.ts": "",
62
+ "dist/index.js": "",
63
+ });
64
+ expect(pluginEntryFor(dir)).toBe(join(dir, "src/index.ts"));
65
+ });
66
+
58
67
  test("skips a declared entry that does not exist", () => {
59
68
  const dir = lexiconDir({
60
69
  "package.json": JSON.stringify({ exports: { ".": { default: "./dist/index.js" } } }),
@@ -23,7 +23,7 @@ import { existsSync, readFileSync } from "fs";
23
23
  import { isAbsolute, join, resolve } from "path";
24
24
  import { pathToFileURL } from "url";
25
25
  import { isLexiconPlugin, type LexiconPlugin } from "../../lexicon";
26
- import { ensureTypeScriptLoader } from "../../ts-loader";
26
+ import { ensureTypeScriptLoaderFor } from "../../ts-loader";
27
27
  import { esModuleNamespace } from "../../module-interop";
28
28
 
29
29
  export interface LoadedLexicon {
@@ -36,20 +36,23 @@ export interface LoadedLexicon {
36
36
  }
37
37
 
38
38
  /**
39
- * The module a lexicon package presents to consumers.
39
+ * The module a lexicon package presents to consumers, as its source.
40
40
  *
41
- * Tier 1 requires `exports["."].default` to be `./src/index.ts`, so that is the
42
- * first choice — it is the module core itself imports. The fallbacks keep this
43
- * usable on a lexicon that has not reached that check yet.
41
+ * Tier 1 requires `exports["."].development` to be `./src/index.ts` and
42
+ * `default` to be its compiled `./dist/index.js` (#3981). The check reads the
43
+ * lexicon's source, so `development` is the first choice: a `dist/` may be
44
+ * missing or older than the source. `default` and `main` come next, and the
45
+ * conventional paths keep this usable on a lexicon that has not reached that
46
+ * check yet.
44
47
  */
45
48
  export function pluginEntryFor(dir: string): string | undefined {
46
49
  const candidates: string[] = [];
47
50
  try {
48
51
  const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")) as {
49
- exports?: { "."?: { default?: string } };
52
+ exports?: { "."?: { development?: string; default?: string } };
50
53
  main?: string;
51
54
  };
52
- for (const declared of [pkg.exports?.["."]?.default, pkg.main]) {
55
+ for (const declared of [pkg.exports?.["."]?.development, pkg.exports?.["."]?.default, pkg.main]) {
53
56
  if (typeof declared === "string") candidates.push(declared);
54
57
  }
55
58
  } catch {
@@ -78,7 +81,7 @@ export async function loadLexiconFromDir(dir: string): Promise<LoadedLexicon> {
78
81
 
79
82
  let mod: Record<string, unknown>;
80
83
  try {
81
- ensureTypeScriptLoader();
84
+ ensureTypeScriptLoaderFor(entry);
82
85
  mod = esModuleNamespace((await import(pathToFileURL(entry).href)) as Record<string, unknown>);
83
86
  } catch (error) {
84
87
  return { entry, error: `import failed: ${error instanceof Error ? error.message : String(error)}` };
@@ -25,7 +25,7 @@ describe("checkLexicon", () => {
25
25
  expect(names).toContain("Registered intrinsics are exported by the package");
26
26
  expect(names).toContain("Registered intrinsics' isTag matches how they're authored");
27
27
  expect(names).toContain("dist/manifest.json declares a chantVersion");
28
- expect(names).toContain('package.json routes exports["."].default at ./src/index.ts and deletes emitted JS in build');
28
+ expect(names).toContain('package.json routes exports["."] development at ./src/index.ts and default at ./dist/index.js, and build keeps emitted JS');
29
29
  });
30
30
 
31
31
  test("gitlab's own reference() intrinsic passes both the export and isTag audits", async () => {
@@ -310,27 +310,32 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
310
310
  detail: chantVersionDetail,
311
311
  });
312
312
 
313
- // chant #1067 — packaging shape ("all 11 lexicons route exports['.'].default
314
- // at ./src/index.ts and delete emitted JS in build") was real but
315
- // unenforced; a lexicon shipping differently would break consumers
316
- // silently. Cheap structural check on package.json, not a build execution.
313
+ // chant #1067 — packaging shape, real but unenforced before: a lexicon
314
+ // shipping differently would break consumers silently. Cheap structural
315
+ // check on package.json, not a build execution. #3981 — lexicons ship
316
+ // compiled JS: `default` is ./dist/index.js, `development` stays on
317
+ // ./src/index.ts for the repository's tools, and the build keeps the JS tsc
318
+ // emits (it used to delete it).
317
319
  const packageJsonRaw = readOr(join(dir, "package.json"));
318
320
  let packagingOk = false;
319
321
  let packagingDetail: string | undefined;
320
322
  if (packageJsonRaw) {
321
323
  try {
322
324
  const pkg = JSON.parse(packageJsonRaw) as {
323
- exports?: { "."?: { default?: string } };
325
+ exports?: { "."?: { development?: string; default?: string } };
324
326
  scripts?: { build?: string };
325
327
  };
328
+ const developmentExport = pkg.exports?.["."]?.development;
326
329
  const defaultExport = pkg.exports?.["."]?.default;
327
330
  const buildScript = pkg.scripts?.build ?? "";
328
- const exportOk = defaultExport === "./src/index.ts";
329
- const deletesEmittedJs = /-delete/.test(buildScript) && /\.js/.test(buildScript);
330
- packagingOk = exportOk && deletesEmittedJs;
331
+ const developmentOk = developmentExport === "./src/index.ts";
332
+ const defaultOk = defaultExport === "./dist/index.js";
333
+ const keepsEmittedJs = /tsconfig\.build\.json/.test(buildScript) && !/-delete/.test(buildScript);
334
+ packagingOk = developmentOk && defaultOk && keepsEmittedJs;
331
335
  const problems: string[] = [];
332
- if (!exportOk) problems.push(`exports["."].default is ${JSON.stringify(defaultExport)}, expected "./src/index.ts"`);
333
- if (!deletesEmittedJs) problems.push(`build script doesn't delete emitted .js from dist/: ${JSON.stringify(buildScript)}`);
336
+ if (!developmentOk) problems.push(`exports["."].development is ${JSON.stringify(developmentExport)}, expected "./src/index.ts"`);
337
+ if (!defaultOk) problems.push(`exports["."].default is ${JSON.stringify(defaultExport)}, expected "./dist/index.js"`);
338
+ if (!keepsEmittedJs) problems.push(`build script must compile tsconfig.build.json and keep the emitted .js in dist/: ${JSON.stringify(buildScript)}`);
334
339
  packagingDetail = problems.length > 0 ? problems.join("; ") : undefined;
335
340
  } catch {
336
341
  packagingDetail = "package.json is not valid JSON";
@@ -339,7 +344,7 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
339
344
  packagingDetail = "package.json missing or unreadable";
340
345
  }
341
346
  items.push({
342
- name: 'package.json routes exports["."].default at ./src/index.ts and deletes emitted JS in build',
347
+ name: 'package.json routes exports["."] development at ./src/index.ts and default at ./dist/index.js, and build keeps emitted JS',
343
348
  tier: 1,
344
349
  pass: packagingOk,
345
350
  detail: packagingDetail,
@@ -520,6 +520,43 @@ async function parseWithEmbedded(
520
520
  return { irs: parses.map((parse) => parse({ embedded })), embedded };
521
521
  }
522
522
 
523
+ /**
524
+ * Build the source import wrote and name each error-severity post-synth
525
+ * finding that would stop `chant build` (#3605). The findings go through the
526
+ * same `lint.presets` and `lint.rules` filtering build applies, against the
527
+ * project config above `outputDir`, so a check the project turns off is not
528
+ * named. When the source does not build here (the lexicon is not installed
529
+ * beside it, or embedded content needs another lexicon's serializer), nothing
530
+ * is said: import reports what build would refuse, not why it cannot run.
531
+ */
532
+ export async function buildErrorWarnings(plugin: LexiconPlugin, outputDir: string): Promise<string[]> {
533
+ try {
534
+ const checks = plugin.postSynthChecks?.() ?? [];
535
+ if (checks.length === 0) return [];
536
+ const [{ build }, { runPostSynthChecks }, { applyConfiguredPreset, applyConfiguredSeverity, resolvePresetIds }, { loadChantConfigUpward }] =
537
+ await Promise.all([import("../../build"), import("../../lint/post-synth"), import("../../lint/config"), import("../../config")]);
538
+ const result = await build(outputDir, [plugin.serializer]);
539
+ if (result.errors.length > 0) return [];
540
+ const { config } = await loadChantConfigUpward(outputDir);
541
+ const rules = config.lint?.rules;
542
+ // As build.ts runLexiconPostSynthChecks does: the plugin sees its own output only.
543
+ const output = result.outputs.get(plugin.serializer.name);
544
+ const outputs = new Map(output === undefined ? [] : [[plugin.serializer.name, output]]);
545
+ const diagnostics = runPostSynthChecks(checks, { ...result, outputs });
546
+ const presetIds = resolvePresetIds(plugin.lintPresets?.(), config.lint?.presets?.[plugin.name] ?? "recommended");
547
+ const afterPreset = applyConfiguredPreset(diagnostics, presetIds, rules).diagnostics;
548
+ return applyConfiguredSeverity(afterPreset, rules)
549
+ .diagnostics.filter((diag) => diag.severity === "error")
550
+ .map(
551
+ (diag) =>
552
+ `${diag.checkId}: ${diag.message.replace(/\.$/, "")}. chant build stops on this error; ` +
553
+ `change the generated source, or set lint.rules.${diag.checkId} to "off" in chant.config.ts.`,
554
+ );
555
+ } catch {
556
+ return [];
557
+ }
558
+ }
559
+
523
560
  /** The shared tail of every template import: parse → generate → write. */
524
561
  async function parseAndWrite(
525
562
  plugin: LexiconPlugin,
@@ -615,6 +652,9 @@ async function parseAndWrite(
615
652
  generatedFiles.push(file.path);
616
653
  }
617
654
 
655
+ // What `chant build` will refuse, said now rather than at the first build (#3605).
656
+ warnings.push(...(await buildErrorWarnings(plugin, outputDir)));
657
+
618
658
  return {
619
659
  success: true,
620
660
  generatedFiles,
@@ -13,12 +13,12 @@ export function generatePackageJson(name: string, names: { packageName: string }
13
13
  ".": {
14
14
  development: "./src/index.ts",
15
15
  types: "./dist/index.d.ts",
16
- default: "./src/index.ts",
16
+ default: "./dist/index.js",
17
17
  },
18
18
  "./*": {
19
19
  development: "./src/*.ts",
20
20
  types: "./dist/*.d.ts",
21
- default: "./src/*.ts",
21
+ default: "./dist/*.js",
22
22
  },
23
23
  "./manifest": "./dist/manifest.json",
24
24
  "./meta": "./dist/meta.json",
@@ -28,7 +28,8 @@ export function generatePackageJson(name: string, names: { packageName: string }
28
28
  generate: "npx tsx src/codegen/generate-cli.ts",
29
29
  validate: "npx tsx src/validate-cli.ts",
30
30
  docs: "npx tsx src/codegen/docs-cli.ts",
31
- build: 'tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name "*.js" -o -name "*.js.map" \\) -delete',
31
+ // #3981 — the package ships the compiled dist/*.js its exports' `default` names.
32
+ build: "tsc -p tsconfig.build.json --sourceMap false && tsc-alias -p tsconfig.build.json",
32
33
  prepack: "npm run generate && npm run bundle && npm run validate && npm run build",
33
34
  bundle: "tsx src/package-cli.ts",
34
35
  },
@@ -274,13 +274,16 @@ describe("scaffold content validation", () => {
274
274
  });
275
275
 
276
276
  // #2090, the scaffolded package.json failed tier 1 as generated: a bare
277
- // string exports["."], a build script that never deletes emitted .js, and
278
- // a prepack that never bundled, so dist/manifest.json never existed.
279
- test("package.json exports[\".\"].default is ./src/index.ts, build deletes emitted JS, prepack bundles (#2090)", () => {
277
+ // string exports["."] and a prepack that never bundled, so
278
+ // dist/manifest.json never existed. #3981 — the package ships compiled JS.
279
+ test("package.json exports[\".\"] is development src, default dist JS, build keeps JS, prepack bundles (#2090, #3981)", () => {
280
280
  const pkg = JSON.parse(readFileSync(join(targetDir, "package.json"), "utf-8"));
281
- expect(pkg.exports["."].default).toBe("./src/index.ts");
282
- expect(pkg.scripts.build).toContain("-delete");
281
+ expect(pkg.exports["."].development).toBe("./src/index.ts");
282
+ expect(pkg.exports["."].default).toBe("./dist/index.js");
283
+ expect(pkg.exports["./*"].default).toBe("./dist/*.js");
284
+ expect(pkg.scripts.build).not.toContain("-delete");
283
285
  expect(pkg.scripts.prepack).toContain("bundle");
286
+ expect(pkg.scripts.prepack).toContain("npm run build");
284
287
  });
285
288
 
286
289
  test("tsconfig.build.json uses bundler resolution + the development condition (#749)", () => {
@@ -305,6 +305,51 @@ describe("onboardCommand", () => {
305
305
  });
306
306
  });
307
307
 
308
+ describe("chant.yml validate step for a lexicon it already has (#2877)", () => {
309
+ let root: string;
310
+
311
+ beforeEach(() => {
312
+ root = makeTempDir();
313
+ writeFixtureRepo(root);
314
+ });
315
+
316
+ afterEach(() => {
317
+ rmSync(root, { recursive: true, force: true });
318
+ });
319
+
320
+ const withGithubStep = (run: string) =>
321
+ ciContent.replace(
322
+ " - name: Generate and validate K8s lexicon",
323
+ ` - name: Generate and validate GitHub lexicon\n ${run}\n\n - name: Generate and validate K8s lexicon`,
324
+ );
325
+
326
+ const githubSteps = (ci: string) => ci.match(/Generate and validate github lexicon/gi)?.length;
327
+
328
+ test("a named step's bare run: line counts as the lexicon's prepack line", () => {
329
+ const before = withGithubStep("run: npm run --prefix lexicons/github prepack");
330
+ expect(before).not.toBe(ciContent);
331
+ writeFileSync(join(root, ".github/workflows/chant.yml"), before);
332
+
333
+ const result = onboardCommand({ name: "github", root });
334
+ expect(result.patched).not.toContain("chant.yml (prepack + validate)");
335
+ expect(result.skipped).toContain("chant.yml: github already in chant.yml");
336
+ expect(readFileSync(join(root, ".github/workflows/chant.yml"), "utf-8")).toBe(before);
337
+ });
338
+
339
+ test("the step-name check ignores case (Github vs GitHub)", () => {
340
+ // A step whose run line is not a plain prepack call, so only the name can
341
+ // tell onboard the validate step already exists.
342
+ writeFileSync(
343
+ join(root, ".github/workflows/chant.yml"),
344
+ withGithubStep("run: npm run --prefix lexicons/github prepack -- --strict"),
345
+ );
346
+
347
+ onboardCommand({ name: "github", root });
348
+ const ci = readFileSync(join(root, ".github/workflows/chant.yml"), "utf-8");
349
+ expect(githubSteps(ci)).toBe(1);
350
+ });
351
+ });
352
+
308
353
  describe("root tsconfig.json paths (#1614)", () => {
309
354
  let root: string;
310
355
 
@@ -32,13 +32,14 @@ function findRepoRoot(): string {
32
32
  }
33
33
 
34
34
  /**
35
- * A real prepack invocation line: a Dockerfile `RUN`, a workflow `- run:`,
36
- * or a bare line inside a `run: |` block. Comments, `echo` messages and
35
+ * A real prepack invocation line: a Dockerfile `RUN`, a workflow `- run:` or
36
+ * `run:` step key (a named step puts `run:` on its own line, #2877), or a bare
37
+ * line inside a `run: |` block. Comments, `echo` messages and
37
38
  * `$lex` / `<lex>` placeholders do not match. Matching those placeholder
38
39
  * substrings was how onboard appended duplicates to Dockerfile.smoke on
39
40
  * every run (#1678).
40
41
  */
41
- const PREPACK_LINE = /^\s*(?:RUN\s+|-\s*run:\s*)?npm run --prefix lexicons\/[a-z0-9-]+ prepack\s*$/i;
42
+ const PREPACK_LINE = /^\s*(?:RUN\s+|(?:-\s*)?run:\s*)?npm run --prefix lexicons\/[a-z0-9-]+ prepack\s*$/i;
42
43
 
43
44
  function isPrepackLine(line: string): boolean {
44
45
  return PREPACK_LINE.test(line);
@@ -256,7 +257,10 @@ function patchCiWorkflow(root: string, name: string): PatchResult {
256
257
  const displayName = name.charAt(0).toUpperCase() + name.slice(1);
257
258
  const validateStepName = `Generate and validate ${displayName} lexicon`;
258
259
 
259
- if (!lines.some((l) => l.includes(validateStepName))) {
260
+ // Case-insensitive: the name is built from the directory ("Github"), and an
261
+ // existing step may spell the product its own way ("GitHub", #2877).
262
+ const stepNameLower = validateStepName.toLowerCase();
263
+ if (!lines.some((l) => l.toLowerCase().includes(stepNameLower))) {
260
264
  let lastValidateRunIdx = -1;
261
265
  for (let i = 0; i < lines.length; i++) {
262
266
  if (lines[i].includes("Generate and validate")) {
@@ -25,6 +25,12 @@ describe("updateCommand", () => {
25
25
  const result = await updateCommand({ path: testDir });
26
26
  expect(result.success).toBe(true);
27
27
  expect(result.warnings.some((w) => w.includes("not found"))).toBe(true);
28
+ // chant #3988 — the warning names the install command for the package.
29
+ expect(
30
+ result.warnings.some((w) =>
31
+ w.includes('npm install --save-dev @intentius/chant-lexicon-nonexistent'),
32
+ ),
33
+ ).toBe(true);
28
34
  });
29
35
  });
30
36
 
@@ -154,7 +154,10 @@ export async function updateCommand(options: UpdateOptions): Promise<UpdateResul
154
154
  const pkgPath = resolvePackagePath(pkgName, projectDir);
155
155
 
156
156
  if (!pkgPath) {
157
- warnings.push(`${pkgName} not found in node_modules. Run "npm install" first.`);
157
+ // chant #3988 — update copies from node_modules and never installs.
158
+ warnings.push(
159
+ `${pkgName} not found in node_modules. chant update does not install lexicons: run "npm install --save-dev ${pkgName}" first.`,
160
+ );
158
161
  continue;
159
162
  }
160
163
 
@@ -7,14 +7,19 @@
7
7
  * Each run is traced through a load hook that NODE_OPTIONS hands to the CLI's
8
8
  * node, so the test can say what loaded: none of chant's TypeScript source,
9
9
  * ever, and tsx only for a command that imports TypeScript (here the
10
- * lexicon and the project source). tsx's ESM hooks run on a thread of their
11
- * own, about 200 MB of the process (#3276), so a workspace read must not
12
- * register it either.
10
+ * project source). tsx's ESM hooks run on a thread of their own, about 200 MB
11
+ * of the process (#3276), so a workspace read must not register it either.
12
+ *
13
+ * The lexicon ships compiled JS (#3981): its exports' `default` is
14
+ * `dist/*.js`. No command loads a module of the lexicon's TypeScript, and
15
+ * `serve mcp` on a project whose config is JSON loads no tsx at all, with the
16
+ * same lint rules and post-synth checks as the lexicon loaded from source.
13
17
  *
14
18
  * End to end because it packs, installs from the registry and spawns the CLI.
15
19
  */
16
20
 
17
21
  import { execFileSync, spawnSync } from "node:child_process";
22
+ import { loadPlugin } from "./plugins";
18
23
  import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
19
24
  import { tmpdir } from "node:os";
20
25
  import { join, resolve } from "node:path";
@@ -33,14 +38,20 @@ let waves: string;
33
38
  let workspace: string;
34
39
  let chant: string;
35
40
  let tracer: string;
41
+ let mcpProject: string;
36
42
 
37
43
  const TRACER = `
38
44
  import { registerHooks } from "node:module";
39
45
  import { appendFileSync } from "node:fs";
40
46
  const out = process.env.CHANT_TRACE_OUT;
41
- const seen = { chantSrc: 0, chantDist: 0, tsx: 0, typescript: 0, dist: [] };
47
+ const seen = { chantSrc: 0, chantDist: 0, tsx: 0, typescript: 0, dist: [], lexiconTs: 0, lexiconJs: 0 };
42
48
  registerHooks({
43
49
  load(url, context, next) {
50
+ if (url.includes("/@intentius/chant-lexicon-")) {
51
+ const path = url.replace(/[?#].*$/, "");
52
+ if (/\\.[cm]?tsx?$/.test(path) && !/\\.d\\.[cm]?ts$/.test(path)) seen.lexiconTs++;
53
+ else if (path.includes("/dist/") && path.endsWith(".js")) seen.lexiconJs++;
54
+ }
44
55
  if (url.includes("/@intentius/chant/src/")) seen.chantSrc++;
45
56
  else if (url.includes("/@intentius/chant/dist/")) { seen.chantDist++; seen.dist.push(url.slice(url.indexOf("/@intentius/chant/dist/") + 23)); }
46
57
  else if (url.includes("/node_modules/tsx/")) seen.tsx++;
@@ -61,15 +72,15 @@ interface Run {
61
72
  status: number | null;
62
73
  stdout: string;
63
74
  stderr: string;
64
- /** Counts of what loaded, plus each compiled module's path under `dist/`. */
65
- loaded: { chantSrc: number; chantDist: number; tsx: number; typescript: number; dist: string[] };
75
+ /** Counts of what loaded, plus each compiled module's path under `dist/`. `lexiconTs` and `lexiconJs` count the lexicon's TypeScript and compiled modules. */
76
+ loaded: { chantSrc: number; chantDist: number; tsx: number; typescript: number; dist: string[]; lexiconTs: number; lexiconJs: number };
66
77
  }
67
78
 
68
- function run(cwd: string, args: string[], extraEnv: NodeJS.ProcessEnv = {}, command = chant): Run {
79
+ function run(cwd: string, args: string[], extraEnv: NodeJS.ProcessEnv = {}, command = chant, input?: string): Run {
69
80
  const traceOut = join(scratch, `trace-${Math.random().toString(36).slice(2)}.jsonl`);
70
81
  const env: NodeJS.ProcessEnv = { ...process.env, ...extraEnv, NODE_OPTIONS: `--import ${tracer}`, CHANT_TRACE_OUT: traceOut };
71
82
  delete env.CHANT_ENV;
72
- const result = spawnSync(command, args, { cwd, env, encoding: "utf-8" });
83
+ const result = spawnSync(command, args, { cwd, env, encoding: "utf-8", input, timeout: 120_000 });
73
84
  const lines = readFileSync(traceOut, "utf-8").trim().split("\n");
74
85
  return { status: result.status, stdout: result.stdout, stderr: result.stderr, loaded: JSON.parse(lines[0]!) as Run["loaded"] };
75
86
  }
@@ -80,7 +91,9 @@ beforeAll(() => {
80
91
  writeFileSync(tracer, TRACER);
81
92
  const core = pack(coreRoot);
82
93
  // The lexicon's prepack regenerates it from upstream specs; the checkout's
83
- // generated source and dist are what this test needs, so pack them as they are.
94
+ // generated source and bundle are what this test needs, so pack them as they
95
+ // are, after the prepack's last step, the build that writes dist/*.js.
96
+ execFileSync("npm", ["run", "build"], { cwd: renderRoot, stdio: ["ignore", "pipe", "pipe"] });
84
97
  const render = pack(renderRoot, true);
85
98
 
86
99
  project = join(scratch, "project");
@@ -95,6 +108,13 @@ beforeAll(() => {
95
108
  );
96
109
  chant = join(project, "node_modules", ".bin", "chant");
97
110
 
111
+ // The same lexicon, from a config that is JSON, with no source: nothing for tsx to load.
112
+ mcpProject = join(scratch, "mcp-project");
113
+ mkdirSync(mcpProject);
114
+ writeFileSync(join(mcpProject, "package.json"), JSON.stringify({ name: "compiled-cli-mcp-e2e", private: true, type: "module" }));
115
+ writeFileSync(join(mcpProject, "chant.config.json"), JSON.stringify({ lexicons: ["render"] }));
116
+ symlinkSync(join(project, "node_modules"), join(mcpProject, "node_modules"), "dir");
117
+
98
118
  // The same project with no package.json at all, so nothing above the config
99
119
  // says "type": "module" and tsx compiles chant.config.ts as CommonJS (#3897).
100
120
  cjsProject = join(scratch, "cjs-project");
@@ -217,19 +237,64 @@ describe("the installed chant CLI (#3878)", () => {
217
237
  expect(heavy).toEqual([]);
218
238
  });
219
239
 
220
- test("build loads the TypeScript lexicon and project through tsx, against the one compiled core", () => {
240
+ test("build loads the project through tsx and the lexicon as compiled JS, against the one compiled core", () => {
221
241
  const r = run(project, ["build", "src", "-o", "out/render.json"]);
222
242
  expect(r.status, r.stderr).toBe(0);
223
243
  const built = JSON.parse(readFileSync(join(project, "out", "render.json"), "utf-8")) as Record<string, { body?: { name?: string } }>;
224
244
  expect(built.db?.body?.name).toBe("e2e-db");
225
245
  expect(r.loaded.tsx).toBeGreaterThan(0);
226
246
  expect(r.loaded.chantSrc).toBe(0);
247
+ expect(r.loaded.lexiconJs).toBeGreaterThan(0);
248
+ expect(r.loaded.lexiconTs).toBe(0);
227
249
  });
228
250
 
229
- test("lint passes on the project", () => {
251
+ test("lint passes on the project and loads none of the lexicon's TypeScript", () => {
230
252
  const r = run(project, ["lint", "src"]);
231
253
  expect(r.status, r.stdout + r.stderr).toBe(0);
232
254
  expect(r.loaded.chantSrc).toBe(0);
255
+ expect(r.loaded.lexiconTs).toBe(0);
256
+ });
257
+
258
+ test("serve mcp loads the packed lexicon's plugin with no tsx (#3981)", () => {
259
+ const input =
260
+ [
261
+ { jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05", clientInfo: { name: "e2e" } } },
262
+ { jsonrpc: "2.0", method: "notifications/initialized" },
263
+ { jsonrpc: "2.0", id: 2, method: "tools/list", params: {} },
264
+ { jsonrpc: "2.0", id: 3, method: "resources/list", params: {} },
265
+ ]
266
+ .map((m) => JSON.stringify(m))
267
+ .join("\n") + "\n";
268
+ const r = run(mcpProject, ["serve", "mcp"], {}, chant, input);
269
+ expect(r.status, r.stderr).toBe(0);
270
+ const responses = r.stdout.trim().split("\n").filter(Boolean).map((line) => JSON.parse(line) as { id?: number; result?: Record<string, unknown> });
271
+ const result = (id: number) => responses.find((m) => m.id === id)?.result;
272
+ expect((result(1)?.serverInfo as { name?: string } | undefined)?.name).toBe("chant");
273
+ const tools = ((result(2)?.tools ?? []) as Array<{ name: string }>).map((t) => t.name);
274
+ for (const name of ["build", "lint", "explain"]) expect(tools).toContain(name);
275
+ expect(r.loaded.lexiconJs).toBeGreaterThan(0);
276
+ expect(r.loaded).toMatchObject({ chantSrc: 0, tsx: 0, lexiconTs: 0 });
277
+ });
278
+
279
+ test("the packed lexicon's plugin has the lint rules and post-synth checks of its source (#3981)", async () => {
280
+ // The plugin as the installed CLI loads it: compiled core, plain node, the lexicon's dist/*.js.
281
+ const script =
282
+ `const core = ${JSON.stringify(pathToFileURL(join(project, "node_modules", "@intentius", "chant", "dist")).href)};\n` +
283
+ `const { installCompiledCli } = await import(core + "/ts-loader.js");\n` +
284
+ `installCompiledCli();\n` +
285
+ `const { loadPlugin } = await import(core + "/cli/plugins.js");\n` +
286
+ `const plugin = await loadPlugin("render");\n` +
287
+ `process.stdout.write(JSON.stringify({ lintRules: plugin.lintRules().map((r) => r.id).sort(), postSynthChecks: (plugin.postSynthChecks?.() ?? []).map((c) => c.id).sort() }));\n`;
288
+ const r = run(mcpProject, ["--input-type=module", "-e", script], {}, process.execPath);
289
+ expect(r.status, r.stderr).toBe(0);
290
+ expect(r.loaded).toMatchObject({ chantSrc: 0, tsx: 0, lexiconTs: 0 });
291
+ const packed = JSON.parse(r.stdout) as { lintRules: string[]; postSynthChecks: string[] };
292
+
293
+ // The same plugin from the repository's source, in this (vitest) process.
294
+ const source = await loadPlugin("render");
295
+ expect(packed.lintRules).toEqual((source.lintRules?.() ?? []).map((rule) => rule.id).sort());
296
+ expect(packed.postSynthChecks).toEqual((source.postSynthChecks?.() ?? []).map((check) => check.id).sort());
297
+ expect(packed.lintRules.length).toBeGreaterThan(0);
233
298
  });
234
299
 
235
300
  test("build --sandbox bundles chant's source for the sandboxed child", () => {