@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
@@ -14,6 +14,7 @@
14
14
  * _releases/<releaseDigest>.json the release, written once and never rewritten
15
15
  * _releases/cuts.jsonl one line per cut, with the release's label
16
16
  * _releases/templates/<digest>.txt each template's bytes, by content digest
17
+ * _releases/templates/<digest>.b64 a file that is not UTF-8, base64 (#4155)
17
18
  *
18
19
  * `:` is written as `_` in file names, as `_plans/` and `_builds/` do. A
19
20
  * workspace member's copy sits under `_members/<member>/` through the same
@@ -24,6 +25,14 @@
24
25
  * (ws-104 question 5). They are named by content digest, so a template that
25
26
  * two environments or two releases share is stored once.
26
27
  *
28
+ * Since #4155 a cut records every local file a deploy step deploys from, not
29
+ * only `template`, `manifest` and `values` files: a chart, a kustomize
30
+ * directory, a site's tree. A directory is recorded as one template per file
31
+ * under it, and named in the target's `trees`, so a promote deploys the
32
+ * recorded tree. A target with `trees` is one such cut; a target without the
33
+ * field was cut before #4155, and a promote of it reads directories and the
34
+ * other fields from the checkout, as it did then.
35
+ *
27
36
  * `releaseDigest` is `computePlanDigest("release", subject)` over the member,
28
37
  * the commit, the artifact digests and each target's env, templates and the
29
38
  * name and value of each param. A param's `source`, the label, the actor, the
@@ -31,7 +40,7 @@
31
40
  * same digest.
32
41
  */
33
42
  import { sortedJsonReplacer } from "../utils.js";
34
- import { contentDigest } from "../content-digest.js";
43
+ import { contentDigest, sha256Hex } from "../content-digest.js";
35
44
  import { computePlanDigest } from "./plan-digest.js";
36
45
  import { ledgerDir, listFilesInDir, readBlobBySha, readBlobFromPath, readPathSha, RefCASConflictError, writeLedgerFiles, } from "./git.js";
37
46
  /** The directory on `chant/lifecycle` that holds releases, cuts and template bytes. */
@@ -54,9 +63,12 @@ export function normalizeRelease(release) {
54
63
  .map((t) => ({
55
64
  env: t.env,
56
65
  templates: [...t.templates]
57
- .map(({ component, path, digest }) => ({ component, path, digest }))
66
+ .map(({ component, path, digest, encoding }) => ({ component, path, digest, ...(encoding ? { encoding } : {}) }))
58
67
  .sort((a, b) => byString(a.component ?? "", b.component ?? "") || byString(a.path, b.path)),
59
68
  params: [...t.params].map(({ name, value, source }) => ({ name, value, source })).sort((a, b) => byString(a.name, b.name)),
69
+ ...(t.trees
70
+ ? { trees: [...t.trees].map(({ component, path }) => ({ component, path })).sort((a, b) => byString(a.component ?? "", b.component ?? "") || byString(a.path, b.path)) }
71
+ : {}),
60
72
  }))
61
73
  .sort((a, b) => byString(a.env, b.env)),
62
74
  };
@@ -68,7 +80,12 @@ export function releaseHashInput(release) {
68
80
  member: n.member,
69
81
  commit: n.commit,
70
82
  artifactDigests: n.artifactDigests,
71
- targets: n.targets.map((t) => ({ env: t.env, templates: t.templates, params: t.params.map(({ name, value }) => ({ name, value })) })),
83
+ targets: n.targets.map((t) => ({
84
+ env: t.env,
85
+ templates: t.templates,
86
+ params: t.params.map(({ name, value }) => ({ name, value })),
87
+ ...(t.trees ? { trees: t.trees } : {}),
88
+ })),
72
89
  };
73
90
  }
74
91
  /** `computePlanDigest("release", input)` over {@link releaseHashInput}. */
@@ -86,7 +103,11 @@ export function verifyReleaseDigest(release) {
86
103
  }
87
104
  const stem = (digest) => digest.replace(/:/g, "_");
88
105
  const releaseFile = (digest) => `${stem(digest)}.json`;
89
- const templateFile = (digest) => `${stem(digest)}.txt`;
106
+ const templateFile = (digest, encoding) => `${stem(digest)}.${encoding === "base64" ? "b64" : "txt"}`;
107
+ /** The digest of a template's bytes: its text, or what its base64 decodes to. */
108
+ export function templateBytesDigest(content, encoding) {
109
+ return encoding === "base64" ? `sha256:${sha256Hex(Buffer.from(content, "base64"))}` : contentDigest(content);
110
+ }
90
111
  /** A label names a release in commands such as `chant release cut <label>`, so it is one plain word. */
91
112
  const LABEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
92
113
  /** Why a label can't be used, or undefined when it can. */
@@ -113,7 +134,7 @@ export async function persistRelease(release, templates, opts) {
113
134
  throw new Error(`release ${release.releaseDigest} does not hash to its own digest; refusing to store it`);
114
135
  }
115
136
  for (const t of templates) {
116
- if (contentDigest(t.content) !== t.digest)
137
+ if (templateBytesDigest(t.content, t.encoding) !== t.digest)
117
138
  throw new Error(`template bytes do not hash to ${t.digest}; refusing to store them`);
118
139
  }
119
140
  const dir = await ledgerDir(RELEASES_DIR, opts);
@@ -124,12 +145,13 @@ export async function persistRelease(release, templates, opts) {
124
145
  files.push({ path: releasePath, content: `${JSON.stringify(release, sortedJsonReplacer)}\n`, expectPriorSha: null });
125
146
  const seen = new Set();
126
147
  for (const t of templates) {
127
- if (seen.has(t.digest))
148
+ const file = templateFile(t.digest, t.encoding);
149
+ if (seen.has(file))
128
150
  continue;
129
- seen.add(t.digest);
130
- if ((await readPathSha(`${RELEASES_DIR}/${TEMPLATES_SUBDIR}`, templateFile(t.digest), opts)) !== null)
151
+ seen.add(file);
152
+ if ((await readPathSha(`${RELEASES_DIR}/${TEMPLATES_SUBDIR}`, file, opts)) !== null)
131
153
  continue;
132
- files.push({ path: `${dir}/${TEMPLATES_SUBDIR}/${templateFile(t.digest)}`, content: t.content, expectPriorSha: null });
154
+ files.push({ path: `${dir}/${TEMPLATES_SUBDIR}/${file}`, content: t.content, expectPriorSha: null });
133
155
  }
134
156
  if (files.length === 0)
135
157
  return { commit: null, written: false };
@@ -166,7 +188,12 @@ export function parseRelease(text) {
166
188
  r.targets.every((t) => t &&
167
189
  typeof t.env === "string" &&
168
190
  Array.isArray(t.templates) &&
169
- t.templates.every((x) => x && (x.component === null || typeof x.component === "string") && typeof x.path === "string" && typeof x.digest === "string") &&
191
+ t.templates.every((x) => x &&
192
+ (x.component === null || typeof x.component === "string") &&
193
+ typeof x.path === "string" &&
194
+ typeof x.digest === "string" &&
195
+ (x.encoding === undefined || x.encoding === "base64")) &&
196
+ (t.trees === undefined || (Array.isArray(t.trees) && t.trees.every((x) => x && (x.component === null || typeof x.component === "string") && typeof x.path === "string"))) &&
170
197
  Array.isArray(t.params) &&
171
198
  t.params.every((p) => p && typeof p.name === "string" && ["string", "number", "boolean"].includes(typeof p.value) && typeof p.source === "string"));
172
199
  return ok ? r : null;
@@ -297,9 +324,9 @@ export async function appendCut(input, opts) {
297
324
  }
298
325
  throw lastErr;
299
326
  }
300
- /** A template's bytes by digest, or null when none is stored. */
301
- export async function readReleaseTemplate(digest, opts) {
302
- return readBlobFromPath(`${RELEASES_DIR}/${TEMPLATES_SUBDIR}`, templateFile(digest), opts);
327
+ /** A template's bytes by digest, or null when none is stored. Under `base64` (#4155), the stored base64 of the bytes. */
328
+ export async function readReleaseTemplate(digest, opts, encoding) {
329
+ return readBlobFromPath(`${RELEASES_DIR}/${TEMPLATES_SUBDIR}`, templateFile(digest, encoding), opts);
303
330
  }
304
331
  /**
305
332
  * Find a release by its digest or its label. Null when neither names one.
@@ -1 +1 @@
1
- {"version":3,"file":"run-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/run-ledger.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAA+C,MAAM,eAAe,CAAC;AASrI,0EAA0E;AAC1E,eAAO,MAAM,eAAe,UAAU,CAAC;AAMvC,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,CAEjE;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC,EACzC,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,KAAK,EAAE;IACL,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IACrC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC,GACA,gBAAgB,CAiDlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,gBAAgB,EACvB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAsBlD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCxD"}
1
+ {"version":3,"file":"run-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/run-ledger.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,gBAAgB,EAA+C,MAAM,eAAe,CAAC;AASrI,0EAA0E;AAC1E,eAAO,MAAM,eAAe,UAAU,CAAC;AAMvC,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,CAEjE;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC,EACzC,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,KAAK,EAAE;IACL,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IACrC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC,GACA,gBAAgB,CAkDlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,gBAAgB,EACvB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAsBlD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCxD"}
@@ -91,6 +91,7 @@ export function buildRunRecord(config, records, times) {
91
91
  ...(record.point ? { point: record.point } : {}),
92
92
  ...(record.gate ? { gate: record.gate } : {}),
93
93
  ...(record.resumed ? { resumed: record.resumed } : {}),
94
+ ...(record.fn === "shellCmd" && typeof record.args?.image === "string" ? { image: record.args.image } : {}),
94
95
  });
95
96
  if (record.outcome)
96
97
  outcomes[record.outcome.name] = record.outcome.value;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Where an Op that changes the checkout makes its work worktrees (#2893).
3
+ *
4
+ * A work item's worktree is `<checkout>/.chant/work/[<member>/]<item>`. It
5
+ * sits inside the checkout, so a coding agent whose project root is the
6
+ * checkout may write there, and `node_modules` above it still resolves. It
7
+ * used to be `<git-common-dir>/chant-work/...`, where Claude Code refuses
8
+ * every write. `/.chant/work/` goes in `<git-common-dir>/info/exclude`, so the
9
+ * checkout's `git status` never lists it, and the rest of `.chant/` (the
10
+ * workspace lock, the factory's check logs) stays tracked.
11
+ *
12
+ * This module imports nothing from the workspace or the Op runner, so the
13
+ * hand-written walkers can ask it which directory to skip.
14
+ */
15
+ /** The work directory, relative to a checkout's top, `/`-separated. */
16
+ export declare const WORK_DIR = ".chant/work";
17
+ /** The line `<git-common-dir>/info/exclude` gets, anchored at each checkout's top. */
18
+ export declare const WORK_DIR_EXCLUDE = "/.chant/work/";
19
+ /** The directory where earlier versions made work worktrees, under the git common directory. */
20
+ export declare const LEGACY_WORK_DIR = "chant-work";
21
+ /**
22
+ * Whether a directory, given as a `/`-separated path relative to the root a
23
+ * walker started from, is a work directory: `.chant/work` at that root or at
24
+ * any depth below it. A walker skips it, since each worktree in it is a whole
25
+ * copy of the checkout.
26
+ */
27
+ export declare function isWorkDir(rel: string): boolean;
28
+ /** The worktree for `id` under the checkout whose top is `top`. */
29
+ export declare function workWorktreePath(top: string, members: readonly string[], id: string): string;
30
+ /** The worktree an earlier version made for `id`, under the git common directory. */
31
+ export declare function legacyWorkWorktreePath(commonDir: string, members: readonly string[], id: string): string;
32
+ /**
33
+ * Add {@link WORK_DIR_EXCLUDE} to `<commonDir>/info/exclude` unless the file
34
+ * already has it, or `ignored` says git already ignores the work directory
35
+ * (a `.gitignore` of the project's, or the global excludes file). Returns
36
+ * whether it wrote the line.
37
+ */
38
+ export declare function excludeWorkDir(commonDir: string, ignored: boolean): boolean;
39
+ /**
40
+ * After a work worktree is removed, remove the directories above it that are
41
+ * left empty, up to and including the checkout's `.chant`, so a run leaves
42
+ * nothing behind in a checkout that had no `.chant` before it.
43
+ */
44
+ export declare function removeEmptyWorkDirs(worktree: string): void;
45
+ //# sourceMappingURL=work-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-dir.d.ts","sourceRoot":"","sources":["../../src/lifecycle/work-dir.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,uEAAuE;AACvE,eAAO,MAAM,QAAQ,gBAAgB,CAAC;AAEtC,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD,gGAAgG;AAChG,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,qFAAqF;AACrF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAExG;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAQ3E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAa1D"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Where an Op that changes the checkout makes its work worktrees (#2893).
3
+ *
4
+ * A work item's worktree is `<checkout>/.chant/work/[<member>/]<item>`. It
5
+ * sits inside the checkout, so a coding agent whose project root is the
6
+ * checkout may write there, and `node_modules` above it still resolves. It
7
+ * used to be `<git-common-dir>/chant-work/...`, where Claude Code refuses
8
+ * every write. `/.chant/work/` goes in `<git-common-dir>/info/exclude`, so the
9
+ * checkout's `git status` never lists it, and the rest of `.chant/` (the
10
+ * workspace lock, the factory's check logs) stays tracked.
11
+ *
12
+ * This module imports nothing from the workspace or the Op runner, so the
13
+ * hand-written walkers can ask it which directory to skip.
14
+ */
15
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmdirSync } from "node:fs";
16
+ import { dirname, join, sep } from "node:path";
17
+ /** The work directory, relative to a checkout's top, `/`-separated. */
18
+ export const WORK_DIR = ".chant/work";
19
+ /** The line `<git-common-dir>/info/exclude` gets, anchored at each checkout's top. */
20
+ export const WORK_DIR_EXCLUDE = `/${WORK_DIR}/`;
21
+ /** The directory where earlier versions made work worktrees, under the git common directory. */
22
+ export const LEGACY_WORK_DIR = "chant-work";
23
+ /**
24
+ * Whether a directory, given as a `/`-separated path relative to the root a
25
+ * walker started from, is a work directory: `.chant/work` at that root or at
26
+ * any depth below it. A walker skips it, since each worktree in it is a whole
27
+ * copy of the checkout.
28
+ */
29
+ export function isWorkDir(rel) {
30
+ return rel === WORK_DIR || rel.endsWith(`/${WORK_DIR}`);
31
+ }
32
+ /** The worktree for `id` under the checkout whose top is `top`. */
33
+ export function workWorktreePath(top, members, id) {
34
+ return join(top, ...WORK_DIR.split("/"), ...members, id);
35
+ }
36
+ /** The worktree an earlier version made for `id`, under the git common directory. */
37
+ export function legacyWorkWorktreePath(commonDir, members, id) {
38
+ return join(commonDir, LEGACY_WORK_DIR, ...members, id);
39
+ }
40
+ /**
41
+ * Add {@link WORK_DIR_EXCLUDE} to `<commonDir>/info/exclude` unless the file
42
+ * already has it, or `ignored` says git already ignores the work directory
43
+ * (a `.gitignore` of the project's, or the global excludes file). Returns
44
+ * whether it wrote the line.
45
+ */
46
+ export function excludeWorkDir(commonDir, ignored) {
47
+ const file = join(commonDir, "info", "exclude");
48
+ const text = existsSync(file) ? readFileSync(file, "utf-8") : "";
49
+ if (text.split(/\r?\n/).some((l) => l.trim() === WORK_DIR_EXCLUDE))
50
+ return false;
51
+ if (ignored)
52
+ return false;
53
+ mkdirSync(join(commonDir, "info"), { recursive: true });
54
+ appendFileSync(file, `${text === "" || text.endsWith("\n") ? "" : "\n"}${WORK_DIR_EXCLUDE}\n`);
55
+ return true;
56
+ }
57
+ /**
58
+ * After a work worktree is removed, remove the directories above it that are
59
+ * left empty, up to and including the checkout's `.chant`, so a run leaves
60
+ * nothing behind in a checkout that had no `.chant` before it.
61
+ */
62
+ export function removeEmptyWorkDirs(worktree) {
63
+ const marker = `${sep}${WORK_DIR.split("/").join(sep)}${sep}`;
64
+ const at = worktree.lastIndexOf(marker);
65
+ if (at < 0)
66
+ return;
67
+ const stop = worktree.slice(0, at);
68
+ for (let dir = dirname(worktree); dir.length > stop.length; dir = dirname(dir)) {
69
+ try {
70
+ if (readdirSync(dir).length > 0)
71
+ return;
72
+ rmdirSync(dir);
73
+ }
74
+ catch {
75
+ return;
76
+ }
77
+ }
78
+ }
@@ -1,17 +1,20 @@
1
1
  /**
2
2
  * Auto-discovery for lint rules and post-synth checks.
3
3
  *
4
- * Scans directories for .ts files and loads exported rules/checks,
5
- * eliminating the need to manually list every rule in plugin.ts.
4
+ * Scans directories for rule modules and loads exported rules/checks,
5
+ * eliminating the need to manually list every rule in plugin.ts. A lexicon
6
+ * run from source has `.ts` rule modules; one run compiled has `.js` modules
7
+ * beside `.d.ts` declarations (#3981). Both are found, and tsx is registered
8
+ * only when a module found is TypeScript.
6
9
  */
7
10
  import type { LintRule } from "./rule.js";
8
11
  import type { PostSynthCheck } from "./post-synth.js";
9
12
  /**
10
13
  * Discover lint rules from a directory.
11
14
  *
12
- * Scans the directory for .ts files (excluding tests, helpers, and index files),
13
- * loads each module, and collects any exported objects that look like a LintRule
14
- * (has `id`, `severity`, `category`, and `check` function).
15
+ * Scans the directory for rule modules (see {@link listRuleFiles}), loads
16
+ * each one, and collects any exported objects that look like a LintRule (has
17
+ * `id`, `severity`, `category`, and `check` function).
15
18
  *
16
19
  * @param dir - Absolute path to the rules directory
17
20
  * @param importMetaUrl - The caller's import.meta.url (for createRequire)
@@ -20,16 +23,21 @@ export declare function discoverLintRules(dir: string, importMetaUrl: string): L
20
23
  /**
21
24
  * Discover post-synth checks from a directory.
22
25
  *
23
- * Scans the directory for .ts files (excluding tests, helpers, and index files),
24
- * loads each module, and collects any exported objects that look like a PostSynthCheck
25
- * (has `id`, `description`, and `check` function).
26
+ * Scans the directory for rule modules (see {@link listRuleFiles}), loads
27
+ * each one, and collects any exported objects that look like a
28
+ * PostSynthCheck (has `id`, `description`, and `check` function).
26
29
  *
27
30
  * @param dir - Absolute path to the post-synth rules directory
28
31
  * @param importMetaUrl - The caller's import.meta.url (for createRequire)
29
32
  */
30
33
  export declare function discoverPostSynthChecks(dir: string, importMetaUrl: string): PostSynthCheck[];
34
+ /** A rule module's name without its extension: `foo` for `foo.ts` and `foo.js`. */
35
+ export declare function ruleModuleBase(file: string): string;
31
36
  /**
32
- * List rule files in a directory (excluding tests, helpers, index).
37
+ * List rule modules in a directory: `.ts` source or compiled `.js`, leaving
38
+ * out declarations (`.d.ts`), tests, helpers and the index. A directory
39
+ * holding both `foo.ts` and `foo.js` lists `foo.ts` alone, so a rule is
40
+ * never loaded twice.
33
41
  */
34
42
  export declare function listRuleFiles(dir: string): string[];
35
43
  //# sourceMappingURL=discover.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/lint/discover.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AA8BnD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,QAAQ,EAAE,CAmBhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc,EAAE,CAmB5F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYnD"}
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/lint/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAsDnD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,QAAQ,EAAE,CAEhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,cAAc,EAAE,CAE5F;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBnD"}
@@ -1,13 +1,17 @@
1
1
  /**
2
2
  * Auto-discovery for lint rules and post-synth checks.
3
3
  *
4
- * Scans directories for .ts files and loads exported rules/checks,
5
- * eliminating the need to manually list every rule in plugin.ts.
4
+ * Scans directories for rule modules and loads exported rules/checks,
5
+ * eliminating the need to manually list every rule in plugin.ts. A lexicon
6
+ * run from source has `.ts` rule modules; one run compiled has `.js` modules
7
+ * beside `.d.ts` declarations (#3981). Both are found, and tsx is registered
8
+ * only when a module found is TypeScript.
6
9
  */
7
10
  import { readdirSync } from "fs";
8
11
  import { join } from "path";
9
12
  import { createRequire } from "module";
10
13
  import { ensureTypeScriptLoader } from "../ts-loader.js";
14
+ import { isTypeScriptModule } from "../module-source.js";
11
15
  let cjsTypeScript = false;
12
16
  /**
13
17
  * Register tsx so createRequire can load TypeScript files in Node.js ESM
@@ -17,7 +21,8 @@ let cjsTypeScript = false;
17
21
  * From source this runs when the module loads, as it always has: vitest and
18
22
  * the source CLI rely on tsx's CommonJS hook being in place from then on. The
19
23
  * compiled CLI imports this module on every start and most commands read no
20
- * rule directory, so there it waits for the first one (#3878).
24
+ * rule directory, so there it waits for the first directory that holds a
25
+ * TypeScript rule module (#3878, #3981).
21
26
  */
22
27
  function registerTypeScriptRequire() {
23
28
  if (cjsTypeScript)
@@ -37,85 +42,88 @@ function registerTypeScriptRequire() {
37
42
  if (!import.meta.url.endsWith(".js"))
38
43
  registerTypeScriptRequire();
39
44
  /**
40
- * Discover lint rules from a directory.
41
- *
42
- * Scans the directory for .ts files (excluding tests, helpers, and index files),
43
- * loads each module, and collects any exported objects that look like a LintRule
44
- * (has `id`, `severity`, `category`, and `check` function).
45
- *
46
- * @param dir - Absolute path to the rules directory
47
- * @param importMetaUrl - The caller's import.meta.url (for createRequire)
45
+ * Load every rule module in `dir` and collect the exports `accept` takes.
46
+ * Registers tsx first only when one of the modules is TypeScript.
48
47
  */
49
- export function discoverLintRules(dir, importMetaUrl) {
50
- registerTypeScriptRequire();
48
+ function discoverExports(dir, importMetaUrl, accept) {
49
+ const files = listRuleFiles(dir);
50
+ if (files.some(isTypeScriptModule))
51
+ registerTypeScriptRequire();
51
52
  const require = createRequire(importMetaUrl);
52
- const rules = [];
53
- for (const file of listRuleFiles(dir)) {
53
+ const found = [];
54
+ for (const file of files) {
54
55
  try {
55
- // Strip .ts extension — require() resolves without it
56
- const modPath = join(dir, file.replace(/\.ts$/, ""));
57
- const mod = require(modPath);
56
+ const mod = require(join(dir, file));
58
57
  for (const exp of Object.values(mod)) {
59
- if (isLintRule(exp))
60
- rules.push(exp);
58
+ if (accept(exp))
59
+ found.push(exp);
61
60
  }
62
61
  }
63
62
  catch {
64
63
  // Skip files that fail to load
65
64
  }
66
65
  }
67
- return rules.sort((a, b) => a.id.localeCompare(b.id));
66
+ return found;
67
+ }
68
+ /**
69
+ * Discover lint rules from a directory.
70
+ *
71
+ * Scans the directory for rule modules (see {@link listRuleFiles}), loads
72
+ * each one, and collects any exported objects that look like a LintRule (has
73
+ * `id`, `severity`, `category`, and `check` function).
74
+ *
75
+ * @param dir - Absolute path to the rules directory
76
+ * @param importMetaUrl - The caller's import.meta.url (for createRequire)
77
+ */
78
+ export function discoverLintRules(dir, importMetaUrl) {
79
+ return discoverExports(dir, importMetaUrl, isLintRule).sort((a, b) => a.id.localeCompare(b.id));
68
80
  }
69
81
  /**
70
82
  * Discover post-synth checks from a directory.
71
83
  *
72
- * Scans the directory for .ts files (excluding tests, helpers, and index files),
73
- * loads each module, and collects any exported objects that look like a PostSynthCheck
74
- * (has `id`, `description`, and `check` function).
84
+ * Scans the directory for rule modules (see {@link listRuleFiles}), loads
85
+ * each one, and collects any exported objects that look like a
86
+ * PostSynthCheck (has `id`, `description`, and `check` function).
75
87
  *
76
88
  * @param dir - Absolute path to the post-synth rules directory
77
89
  * @param importMetaUrl - The caller's import.meta.url (for createRequire)
78
90
  */
79
91
  export function discoverPostSynthChecks(dir, importMetaUrl) {
80
- registerTypeScriptRequire();
81
- const require = createRequire(importMetaUrl);
82
- const checks = [];
83
- for (const file of listRuleFiles(dir)) {
84
- try {
85
- // Strip .ts extension — require() resolves without it
86
- const modPath = join(dir, file.replace(/\.ts$/, ""));
87
- const mod = require(modPath);
88
- for (const exp of Object.values(mod)) {
89
- if (isPostSynthCheck(exp))
90
- checks.push(exp);
91
- }
92
- }
93
- catch {
94
- // Skip files that fail to load
95
- }
96
- }
97
- return checks.sort((a, b) => a.id.localeCompare(b.id));
92
+ return discoverExports(dir, importMetaUrl, isPostSynthCheck).sort((a, b) => a.id.localeCompare(b.id));
93
+ }
94
+ /** A rule module's name without its extension: `foo` for `foo.ts` and `foo.js`. */
95
+ export function ruleModuleBase(file) {
96
+ return file.replace(/\.(?:ts|js)$/, "");
98
97
  }
99
98
  /**
100
- * List rule files in a directory (excluding tests, helpers, index).
99
+ * List rule modules in a directory: `.ts` source or compiled `.js`, leaving
100
+ * out declarations (`.d.ts`), tests, helpers and the index. A directory
101
+ * holding both `foo.ts` and `foo.js` lists `foo.ts` alone, so a rule is
102
+ * never loaded twice.
101
103
  */
102
104
  export function listRuleFiles(dir) {
105
+ let entries;
103
106
  try {
104
- return readdirSync(dir).filter((f) => {
105
- if (!f.endsWith(".ts"))
106
- return false;
107
- if (f.endsWith(".test.ts"))
108
- return false;
109
- if (f === "index.ts")
110
- return false;
111
- if (f.includes("helper"))
112
- return false;
113
- return true;
114
- });
107
+ entries = readdirSync(dir);
115
108
  }
116
109
  catch {
117
110
  return [];
118
111
  }
112
+ const modules = entries.filter((f) => {
113
+ if (!f.endsWith(".ts") && !f.endsWith(".js"))
114
+ return false;
115
+ if (f.endsWith(".d.ts"))
116
+ return false;
117
+ if (/\.test\.[tj]s$/.test(f))
118
+ return false;
119
+ if (f === "index.ts" || f === "index.js")
120
+ return false;
121
+ if (f.includes("helper"))
122
+ return false;
123
+ return true;
124
+ });
125
+ const sources = new Set(modules.filter((f) => f.endsWith(".ts")).map(ruleModuleBase));
126
+ return modules.filter((f) => f.endsWith(".ts") || !sources.has(ruleModuleBase(f)));
119
127
  }
120
128
  function isLintRule(obj) {
121
129
  if (typeof obj !== "object" || obj === null)
@@ -16,6 +16,7 @@ export { ops014 } from "./ops014-converge-rule-refusals.js";
16
16
  export { ops015 } from "./ops015-gate-approval.js";
17
17
  export { ops016 } from "./ops016-gate-resume.js";
18
18
  export { ops017, ops017Check, workspaceIdentityGates } from "./ops017-gate-alias.js";
19
+ export { ops018 } from "./ops018-shell-image-digest.js";
19
20
  export { sys010, sys010Check } from "./sys010-key-over-plain-http.js";
20
21
  export interface CoreOpCheckOptions {
21
22
  /** `decide.backends` from the project's chant.config, for SYS010 (#2828). */
@@ -25,7 +26,7 @@ export interface CoreOpCheckOptions {
25
26
  }
26
27
  /**
27
28
  * Core's own post-synth checks over the Op model: OPS012, OPS013, OPS014,
28
- * OPS015, OPS016, OPS017 over the workspace's `identity.gates`, and SYS010
29
+ * OPS015, OPS016, OPS017 over the workspace's `identity.gates`, OPS018, and SYS010
29
30
  * over the `decide` steps and the configured decide backends.
30
31
  */
31
32
  export declare function coreOpChecks(opts?: CoreOpCheckOptions): PostSynthCheck[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAQvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;IACpE,6GAA6G;IAC7G,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,EAAE,CAE5E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;IACpE,6GAA6G;IAC7G,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,kBAAuB,GAAG,cAAc,EAAE,CAE5E"}
@@ -14,6 +14,7 @@ import { ops014 } from "./ops014-converge-rule-refusals.js";
14
14
  import { ops015 } from "./ops015-gate-approval.js";
15
15
  import { ops016 } from "./ops016-gate-resume.js";
16
16
  import { ops017Check } from "./ops017-gate-alias.js";
17
+ import { ops018 } from "./ops018-shell-image-digest.js";
17
18
  import { sys010Check } from "./sys010-key-over-plain-http.js";
18
19
  export { ops012 } from "./ops012-activity-contract.js";
19
20
  export { ops013 } from "./ops013-step-output-ref.js";
@@ -21,12 +22,13 @@ export { ops014 } from "./ops014-converge-rule-refusals.js";
21
22
  export { ops015 } from "./ops015-gate-approval.js";
22
23
  export { ops016 } from "./ops016-gate-resume.js";
23
24
  export { ops017, ops017Check, workspaceIdentityGates } from "./ops017-gate-alias.js";
25
+ export { ops018 } from "./ops018-shell-image-digest.js";
24
26
  export { sys010, sys010Check } from "./sys010-key-over-plain-http.js";
25
27
  /**
26
28
  * Core's own post-synth checks over the Op model: OPS012, OPS013, OPS014,
27
- * OPS015, OPS016, OPS017 over the workspace's `identity.gates`, and SYS010
29
+ * OPS015, OPS016, OPS017 over the workspace's `identity.gates`, OPS018, and SYS010
28
30
  * over the `decide` steps and the configured decide backends.
29
31
  */
30
32
  export function coreOpChecks(opts = {}) {
31
- return [ops012, ops013, ops014, ops015, ops016, ops017Check(opts.identityGates), sys010Check(opts.decideBackends)];
33
+ return [ops012, ops013, ops014, ops015, ops016, ops017Check(opts.identityGates), ops018, sys010Check(opts.decideBackends)];
32
34
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * OPS018: a `shellCmd` step that runs in a container (#4015) names its image
3
+ * pinned by digest, `<ref>@sha256:<digest>`, as a literal string. A tag can
4
+ * move between two runs of the same Op, and then the step record's image no
5
+ * longer says what ran. Checked over the main phases, `onFailure`, and the
6
+ * steps inside an effect.
7
+ */
8
+ import type { PostSynthCheck } from "../../post-synth.js";
9
+ export declare const ops018: PostSynthCheck;
10
+ //# sourceMappingURL=ops018-shell-image-digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops018-shell-image-digest.d.ts","sourceRoot":"","sources":["../../../../src/lint/rules/op/ops018-shell-image-digest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,cAAc,EAAyC,MAAM,kBAAkB,CAAC;AAW9F,eAAO,MAAM,MAAM,EAAE,cA6BpB,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { imageProblem } from "../../../op/activities/shell.js";
2
+ import { isOpEntity } from "./support.js";
3
+ function activitySteps(steps) {
4
+ return steps.flatMap((step) => step.kind === "activity" ? [step] : step.kind === "effect" ? step.steps.filter((s) => s.kind === "activity") : []);
5
+ }
6
+ export const ops018 = {
7
+ id: "OPS018",
8
+ description: "A shell step with an image names it pinned by digest, as a literal string",
9
+ check(ctx) {
10
+ const diagnostics = [];
11
+ for (const [entityKey, entity] of ctx.entities) {
12
+ if (!isOpEntity(entity))
13
+ continue;
14
+ const rec = entity;
15
+ const props = (entity.props ?? {});
16
+ if (typeof props.name !== "string" || !Array.isArray(props.phases))
17
+ continue;
18
+ const phases = [...props.phases, ...(props.onFailure ?? [])];
19
+ for (const phase of phases) {
20
+ for (const step of activitySteps(phase.steps ?? [])) {
21
+ if (step.fn !== "shellCmd" || step.args?.image === undefined)
22
+ continue;
23
+ const problem = imageProblem(step.args.image);
24
+ if (!problem)
25
+ continue;
26
+ diagnostics.push({
27
+ checkId: "OPS018",
28
+ severity: "error",
29
+ message: `Op "${props.name}", phase "${phase.name}", shellCmd: ${problem}`,
30
+ entity: entityKey,
31
+ lexicon: typeof rec.lexicon === "string" ? rec.lexicon : undefined,
32
+ });
33
+ }
34
+ }
35
+ }
36
+ return diagnostics;
37
+ },
38
+ };