@intentius/chant 0.101.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (739) hide show
  1. package/dist/agents/checks.d.ts.map +1 -1
  2. package/dist/attrref.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +2 -0
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts.map +1 -1
  6. package/dist/audit/nginx.d.ts.map +1 -1
  7. package/dist/audit/prior-art.d.ts +48 -0
  8. package/dist/audit/prior-art.d.ts.map +1 -1
  9. package/dist/behaviour-kinds.d.ts.map +1 -1
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/change-set.d.ts +232 -0
  12. package/dist/change-set.d.ts.map +1 -0
  13. package/dist/cli/commands/audit.d.ts +7 -0
  14. package/dist/cli/commands/audit.d.ts.map +1 -1
  15. package/dist/cli/commands/build.d.ts.map +1 -1
  16. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  17. package/dist/cli/commands/check-lexicon.d.ts +16 -0
  18. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  19. package/dist/cli/commands/import.d.ts +8 -0
  20. package/dist/cli/commands/import.d.ts.map +1 -1
  21. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  22. package/dist/cli/commands/init.d.ts +19 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/onboard.d.ts +9 -0
  25. package/dist/cli/commands/onboard.d.ts.map +1 -1
  26. package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
  27. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
  28. package/dist/cli/handlers/build.d.ts.map +1 -1
  29. package/dist/cli/handlers/change-set.d.ts +11 -0
  30. package/dist/cli/handlers/change-set.d.ts.map +1 -0
  31. package/dist/cli/handlers/dev.d.ts.map +1 -1
  32. package/dist/cli/handlers/fan-out.d.ts +33 -0
  33. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  34. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  35. package/dist/cli/handlers/misc.d.ts.map +1 -1
  36. package/dist/cli/handlers/operator.d.ts +16 -0
  37. package/dist/cli/handlers/operator.d.ts.map +1 -1
  38. package/dist/cli/handlers/pr.d.ts +31 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -0
  40. package/dist/cli/handlers/run.d.ts.map +1 -1
  41. package/dist/cli/lsp/server.d.ts.map +1 -1
  42. package/dist/cli/main.d.ts.map +1 -1
  43. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  44. package/dist/cli/mcp/server.d.ts.map +1 -1
  45. package/dist/cli/mcp/tools/build.d.ts.map +1 -1
  46. package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
  47. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  48. package/dist/cli/mcp/tools/import.d.ts.map +1 -1
  49. package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
  50. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
  51. package/dist/cli/mcp/tools/search.d.ts.map +1 -1
  52. package/dist/cli/mcp/workspace-tools.d.ts +4 -3
  53. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  54. package/dist/cli/registry.d.ts +74 -3
  55. package/dist/cli/registry.d.ts.map +1 -1
  56. package/dist/codegen/fetch.d.ts.map +1 -1
  57. package/dist/codegen/naming.d.ts.map +1 -1
  58. package/dist/codegen/pinned-upgrade.d.ts +67 -3
  59. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  60. package/dist/codegen/registry.d.ts.map +1 -1
  61. package/dist/components/auto-release.d.ts +16 -0
  62. package/dist/components/auto-release.d.ts.map +1 -1
  63. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  64. package/dist/components/capability.d.ts +53 -0
  65. package/dist/components/capability.d.ts.map +1 -1
  66. package/dist/components/changed-files.d.ts +31 -0
  67. package/dist/components/changed-files.d.ts.map +1 -0
  68. package/dist/components/cli-support.d.ts +9 -1
  69. package/dist/components/cli-support.d.ts.map +1 -1
  70. package/dist/components/component.d.ts +24 -0
  71. package/dist/components/component.d.ts.map +1 -1
  72. package/dist/components/deploy-units.d.ts.map +1 -1
  73. package/dist/components/driver.d.ts +13 -0
  74. package/dist/components/driver.d.ts.map +1 -1
  75. package/dist/components/fan-out-output.d.ts +6 -0
  76. package/dist/components/fan-out-output.d.ts.map +1 -1
  77. package/dist/components/fan-out-record.d.ts +41 -0
  78. package/dist/components/fan-out-record.d.ts.map +1 -0
  79. package/dist/components/fan-out-run.d.ts +65 -0
  80. package/dist/components/fan-out-run.d.ts.map +1 -1
  81. package/dist/components/fan-out-support.d.ts +2 -0
  82. package/dist/components/fan-out-support.d.ts.map +1 -1
  83. package/dist/components/fan-out.d.ts +6 -0
  84. package/dist/components/fan-out.d.ts.map +1 -1
  85. package/dist/components/gated-wave-pipeline.d.ts +50 -0
  86. package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
  87. package/dist/components/index.d.ts +1 -1
  88. package/dist/components/index.d.ts.map +1 -1
  89. package/dist/components/layers.d.ts +25 -0
  90. package/dist/components/layers.d.ts.map +1 -0
  91. package/dist/components/pr-pipeline.d.ts +61 -0
  92. package/dist/components/pr-pipeline.d.ts.map +1 -0
  93. package/dist/components/pr-run.d.ts +119 -0
  94. package/dist/components/pr-run.d.ts.map +1 -0
  95. package/dist/components/promote.d.ts.map +1 -1
  96. package/dist/components/starter-plugin.d.ts.map +1 -1
  97. package/dist/components/verbs/process-runner.d.ts.map +1 -1
  98. package/dist/components/verbs/r2-sync.d.ts.map +1 -1
  99. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  100. package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
  101. package/dist/components/verbs/shell.d.ts.map +1 -1
  102. package/dist/components/verbs/sign.d.ts.map +1 -1
  103. package/dist/components/verbs/verify.d.ts.map +1 -1
  104. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  105. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  106. package/dist/components/verbs/wrangler.d.ts.map +1 -1
  107. package/dist/components/wave-plan.d.ts +49 -0
  108. package/dist/components/wave-plan.d.ts.map +1 -0
  109. package/dist/composite.d.ts.map +1 -1
  110. package/dist/config.d.ts +19 -7
  111. package/dist/config.d.ts.map +1 -1
  112. package/dist/declarable.d.ts +16 -0
  113. package/dist/declarable.d.ts.map +1 -1
  114. package/dist/discovery/cache.d.ts.map +1 -1
  115. package/dist/discovery/fold-import.d.ts +15 -5
  116. package/dist/discovery/fold-import.d.ts.map +1 -1
  117. package/dist/discovery/param-deps.d.ts +16 -0
  118. package/dist/discovery/param-deps.d.ts.map +1 -1
  119. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
  120. package/dist/discovery/specifier-resolve.d.ts +37 -0
  121. package/dist/discovery/specifier-resolve.d.ts.map +1 -0
  122. package/dist/errors.d.ts.map +1 -1
  123. package/dist/fold/fold.d.ts +3 -1
  124. package/dist/fold/fold.d.ts.map +1 -1
  125. package/dist/gated-waves.d.ts +147 -0
  126. package/dist/gated-waves.d.ts.map +1 -0
  127. package/dist/graph-detail.d.ts.map +1 -1
  128. package/dist/graph-ir.d.ts.map +1 -1
  129. package/dist/graph-layout.d.ts.map +1 -1
  130. package/dist/import/base-parser.d.ts.map +1 -1
  131. package/dist/import/embedded.d.ts +7 -0
  132. package/dist/import/embedded.d.ts.map +1 -1
  133. package/dist/import/parser-options.d.ts +14 -0
  134. package/dist/import/parser-options.d.ts.map +1 -0
  135. package/dist/import/parser.d.ts +17 -0
  136. package/dist/import/parser.d.ts.map +1 -1
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/kubectl-context.d.ts.map +1 -1
  140. package/dist/lexicon-output.d.ts.map +1 -1
  141. package/dist/lexicon-schema.d.ts +3 -3
  142. package/dist/lexicon.d.ts +103 -3
  143. package/dist/lexicon.d.ts.map +1 -1
  144. package/dist/lifecycle/assert-live.d.ts.map +1 -1
  145. package/dist/lifecycle/gate-ledger.d.ts +22 -0
  146. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  147. package/dist/lifecycle/git.d.ts +46 -1
  148. package/dist/lifecycle/git.d.ts.map +1 -1
  149. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  150. package/dist/lifecycle/observe.d.ts.map +1 -1
  151. package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  153. package/dist/lifecycle/scenario.d.ts.map +1 -1
  154. package/dist/lifecycle/status.d.ts.map +1 -1
  155. package/dist/lifecycle/work-lease.d.ts +61 -2
  156. package/dist/lifecycle/work-lease.d.ts.map +1 -1
  157. package/dist/lint/config.d.ts +8 -8
  158. package/dist/lint/engine.d.ts +6 -0
  159. package/dist/lint/engine.d.ts.map +1 -1
  160. package/dist/lint/post-synth.d.ts +18 -0
  161. package/dist/lint/post-synth.d.ts.map +1 -1
  162. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  163. package/dist/op/activities/activity-contracts.d.ts +137 -11
  164. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  165. package/dist/op/activities/apply.d.ts +79 -9
  166. package/dist/op/activities/apply.d.ts.map +1 -1
  167. package/dist/op/activities/change-set.d.ts +62 -0
  168. package/dist/op/activities/change-set.d.ts.map +1 -0
  169. package/dist/op/activities/decide.d.ts +2 -0
  170. package/dist/op/activities/decide.d.ts.map +1 -1
  171. package/dist/op/activities/factory.d.ts +137 -0
  172. package/dist/op/activities/factory.d.ts.map +1 -0
  173. package/dist/op/activities/index.d.ts +5 -1
  174. package/dist/op/activities/index.d.ts.map +1 -1
  175. package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
  176. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  177. package/dist/op/activity-contract.d.ts +1 -1
  178. package/dist/op/activity-contract.d.ts.map +1 -1
  179. package/dist/op/activity-failure.d.ts.map +1 -1
  180. package/dist/op/activity-profiles.d.ts.map +1 -1
  181. package/dist/op/builders.d.ts +11 -0
  182. package/dist/op/builders.d.ts.map +1 -1
  183. package/dist/op/composites/apply-op.d.ts +12 -5
  184. package/dist/op/composites/apply-op.d.ts.map +1 -1
  185. package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
  186. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
  187. package/dist/op/decide-backend.d.ts +5 -1
  188. package/dist/op/decide-backend.d.ts.map +1 -1
  189. package/dist/op/decide-read-inputs.d.ts +4 -2
  190. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  191. package/dist/op/emulator-lifecycle.d.ts +21 -2
  192. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  193. package/dist/op/factory.d.ts +83 -0
  194. package/dist/op/factory.d.ts.map +1 -0
  195. package/dist/op/gate-approval.d.ts +5 -1
  196. package/dist/op/gate-approval.d.ts.map +1 -1
  197. package/dist/op/gate-wait.d.ts.map +1 -1
  198. package/dist/op/gate.d.ts +19 -3
  199. package/dist/op/gate.d.ts.map +1 -1
  200. package/dist/op/index.d.ts +6 -1
  201. package/dist/op/index.d.ts.map +1 -1
  202. package/dist/op/local-executor.d.ts +6 -0
  203. package/dist/op/local-executor.d.ts.map +1 -1
  204. package/dist/op/op-ir.d.ts +2 -0
  205. package/dist/op/op-ir.d.ts.map +1 -1
  206. package/dist/op/op-verb-class.d.ts.map +1 -1
  207. package/dist/op/operator.d.ts.map +1 -1
  208. package/dist/op/run-context.d.ts +39 -0
  209. package/dist/op/run-context.d.ts.map +1 -0
  210. package/dist/op/run-live.d.ts.map +1 -1
  211. package/dist/op/runtimes/local.d.ts.map +1 -1
  212. package/dist/op/source-archive.d.ts.map +1 -1
  213. package/dist/op/steward-beside.d.ts.map +1 -1
  214. package/dist/op/steward-points.d.ts.map +1 -1
  215. package/dist/op/steward.d.ts.map +1 -1
  216. package/dist/op/types.d.ts +16 -3
  217. package/dist/op/types.d.ts.map +1 -1
  218. package/dist/op/work-lease-run.d.ts +24 -4
  219. package/dist/op/work-lease-run.d.ts.map +1 -1
  220. package/dist/plan-summary.d.ts +207 -0
  221. package/dist/plan-summary.d.ts.map +1 -0
  222. package/dist/pr-forge.d.ts +105 -0
  223. package/dist/pr-forge.d.ts.map +1 -0
  224. package/dist/pr-loop.d.ts +178 -0
  225. package/dist/pr-loop.d.ts.map +1 -0
  226. package/dist/project-root.d.ts.map +1 -1
  227. package/dist/provenance.d.ts +21 -0
  228. package/dist/provenance.d.ts.map +1 -1
  229. package/dist/pseudo-parameter.d.ts.map +1 -1
  230. package/dist/reconcile.d.ts.map +1 -1
  231. package/dist/secret-materialization.d.ts.map +1 -1
  232. package/dist/telemetry-attribution.d.ts +31 -0
  233. package/dist/telemetry-attribution.d.ts.map +1 -1
  234. package/dist/terraform/emit-source.d.ts.map +1 -1
  235. package/dist/terraform/hcl2json.d.ts +45 -0
  236. package/dist/terraform/hcl2json.d.ts.map +1 -0
  237. package/dist/terraform/parse.d.ts +4 -40
  238. package/dist/terraform/parse.d.ts.map +1 -1
  239. package/dist/testing.d.ts.map +1 -1
  240. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
  241. package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
  242. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
  243. package/dist/workspace/agent-cli.d.ts +5 -0
  244. package/dist/workspace/agent-cli.d.ts.map +1 -1
  245. package/dist/workspace/box-cli.d.ts +12 -0
  246. package/dist/workspace/box-cli.d.ts.map +1 -0
  247. package/dist/workspace/box-factory.d.ts +97 -0
  248. package/dist/workspace/box-factory.d.ts.map +1 -0
  249. package/dist/workspace/box-listing.d.ts +85 -0
  250. package/dist/workspace/box-listing.d.ts.map +1 -0
  251. package/dist/workspace/box-publish.d.ts +147 -0
  252. package/dist/workspace/box-publish.d.ts.map +1 -0
  253. package/dist/workspace/broker-protocol.d.ts +190 -0
  254. package/dist/workspace/broker-protocol.d.ts.map +1 -0
  255. package/dist/workspace/changes.d.ts.map +1 -1
  256. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
  257. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  258. package/dist/workspace/checks.d.ts +5 -0
  259. package/dist/workspace/checks.d.ts.map +1 -1
  260. package/dist/workspace/compose-graph.d.ts +10 -0
  261. package/dist/workspace/compose-graph.d.ts.map +1 -1
  262. package/dist/workspace/composites.d.ts +2 -2
  263. package/dist/workspace/composites.d.ts.map +1 -1
  264. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
  265. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
  266. package/dist/workspace/conformance/broker.d.ts +202 -0
  267. package/dist/workspace/conformance/broker.d.ts.map +1 -0
  268. package/dist/workspace/conformance/index.d.ts +68 -6
  269. package/dist/workspace/conformance/index.d.ts.map +1 -1
  270. package/dist/workspace/conformance/vitest.d.ts +19 -3
  271. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  272. package/dist/workspace/conformance/writer.d.ts +462 -0
  273. package/dist/workspace/conformance/writer.d.ts.map +1 -0
  274. package/dist/workspace/decide.d.ts +126 -12
  275. package/dist/workspace/decide.d.ts.map +1 -1
  276. package/dist/workspace/decision-points.schema.json +11 -4
  277. package/dist/workspace/declaration.d.ts +156 -4
  278. package/dist/workspace/declaration.d.ts.map +1 -1
  279. package/dist/workspace/declaration.schema.json +383 -5
  280. package/dist/workspace/environments.d.ts +36 -10
  281. package/dist/workspace/environments.d.ts.map +1 -1
  282. package/dist/workspace/factory-rules.d.ts +180 -0
  283. package/dist/workspace/factory-rules.d.ts.map +1 -0
  284. package/dist/workspace/generated-files.d.ts.map +1 -1
  285. package/dist/workspace/graph-cache.d.ts.map +1 -1
  286. package/dist/workspace/graph-cli.d.ts +2 -0
  287. package/dist/workspace/graph-cli.d.ts.map +1 -1
  288. package/dist/workspace/identity.d.ts +111 -0
  289. package/dist/workspace/identity.d.ts.map +1 -0
  290. package/dist/workspace/init.d.ts +21 -0
  291. package/dist/workspace/init.d.ts.map +1 -1
  292. package/dist/workspace/intent-cli.d.ts +7 -4
  293. package/dist/workspace/intent-cli.d.ts.map +1 -1
  294. package/dist/workspace/intent-record.d.ts +36 -2
  295. package/dist/workspace/intent-record.d.ts.map +1 -1
  296. package/dist/workspace/intent.d.ts +249 -8
  297. package/dist/workspace/intent.d.ts.map +1 -1
  298. package/dist/workspace/json-edit.d.ts +24 -0
  299. package/dist/workspace/json-edit.d.ts.map +1 -0
  300. package/dist/workspace/jsonc.d.ts +11 -0
  301. package/dist/workspace/jsonc.d.ts.map +1 -1
  302. package/dist/workspace/kinds.d.ts +66 -4
  303. package/dist/workspace/kinds.d.ts.map +1 -1
  304. package/dist/workspace/lexicon-symbols.d.ts +29 -0
  305. package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
  306. package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
  307. package/dist/workspace/lineage-lock.d.ts +2 -2
  308. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  309. package/dist/workspace/lineage-upgrade.d.ts +31 -2
  310. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  311. package/dist/workspace/links.d.ts.map +1 -1
  312. package/dist/workspace/point-answer.schema.json +42 -2
  313. package/dist/workspace/points-cli.d.ts +10 -3
  314. package/dist/workspace/points-cli.d.ts.map +1 -1
  315. package/dist/workspace/points.d.ts +66 -5
  316. package/dist/workspace/points.d.ts.map +1 -1
  317. package/dist/workspace/principal-classes.d.ts +114 -0
  318. package/dist/workspace/principal-classes.d.ts.map +1 -0
  319. package/dist/workspace/reason-codes.d.ts +53 -4
  320. package/dist/workspace/reason-codes.d.ts.map +1 -1
  321. package/dist/workspace/record-assets.d.ts.map +1 -1
  322. package/dist/workspace/record-sessions.d.ts +5 -7
  323. package/dist/workspace/record-sessions.d.ts.map +1 -1
  324. package/dist/workspace/records-checkout.d.ts +54 -0
  325. package/dist/workspace/records-checkout.d.ts.map +1 -0
  326. package/dist/workspace/records-cli.d.ts +34 -1
  327. package/dist/workspace/records-cli.d.ts.map +1 -1
  328. package/dist/workspace/records-close.d.ts +7 -3
  329. package/dist/workspace/records-close.d.ts.map +1 -1
  330. package/dist/workspace/records-since.d.ts.map +1 -1
  331. package/dist/workspace/records-write.d.ts +68 -7
  332. package/dist/workspace/records-write.d.ts.map +1 -1
  333. package/dist/workspace/records.d.ts +43 -9
  334. package/dist/workspace/records.d.ts.map +1 -1
  335. package/dist/workspace/runs-cli.d.ts +296 -0
  336. package/dist/workspace/runs-cli.d.ts.map +1 -0
  337. package/dist/workspace/runs.d.ts +544 -0
  338. package/dist/workspace/runs.d.ts.map +1 -0
  339. package/dist/workspace/session-kinds.d.ts +1 -1
  340. package/dist/workspace/session-kinds.d.ts.map +1 -1
  341. package/dist/workspace/source-block.d.ts +1 -1
  342. package/dist/workspace/source-block.d.ts.map +1 -1
  343. package/dist/workspace/squash.d.ts +80 -0
  344. package/dist/workspace/squash.d.ts.map +1 -0
  345. package/dist/workspace/status-gates.d.ts +17 -3
  346. package/dist/workspace/status-gates.d.ts.map +1 -1
  347. package/dist/workspace/status.d.ts +64 -0
  348. package/dist/workspace/status.d.ts.map +1 -1
  349. package/dist/workspace/symbols.d.ts +63 -0
  350. package/dist/workspace/symbols.d.ts.map +1 -0
  351. package/dist/workspace/trailer-joins.d.ts +46 -0
  352. package/dist/workspace/trailer-joins.d.ts.map +1 -0
  353. package/dist/workspace/trailers.d.ts +89 -0
  354. package/dist/workspace/trailers.d.ts.map +1 -0
  355. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  356. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  357. package/dist/workspace/trust/run-commits.d.ts +46 -0
  358. package/dist/workspace/trust/run-commits.d.ts.map +1 -0
  359. package/dist/workspace/trust/run-statement.d.ts +128 -0
  360. package/dist/workspace/trust/run-statement.d.ts.map +1 -0
  361. package/dist/workspace/trust/seal.d.ts +38 -0
  362. package/dist/workspace/trust/seal.d.ts.map +1 -1
  363. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  364. package/dist/workspace/trust/verify-cli.d.ts +1 -1
  365. package/dist/workspace/trust/verify.d.ts +16 -2
  366. package/dist/workspace/trust/verify.d.ts.map +1 -1
  367. package/dist/workspace/wip-cli.d.ts +21 -0
  368. package/dist/workspace/wip-cli.d.ts.map +1 -0
  369. package/dist/workspace/wip.d.ts +268 -0
  370. package/dist/workspace/wip.d.ts.map +1 -0
  371. package/dist/workspace/work-cli.d.ts +39 -3
  372. package/dist/workspace/work-cli.d.ts.map +1 -1
  373. package/dist/workspace/work-evidence.d.ts +1 -1
  374. package/dist/workspace/work-evidence.d.ts.map +1 -1
  375. package/dist/workspace/work-size.d.ts +55 -0
  376. package/dist/workspace/work-size.d.ts.map +1 -0
  377. package/dist/workspace/work.d.ts +26 -1
  378. package/dist/workspace/work.d.ts.map +1 -1
  379. package/dist/workspace/workspace-kinds.schema.json +122 -0
  380. package/dist/workspace/workspace-principals.schema.json +60 -0
  381. package/dist/workspace/write-lock-cli.d.ts +60 -0
  382. package/dist/workspace/write-lock-cli.d.ts.map +1 -0
  383. package/dist/workspace/write-lock.d.ts +152 -0
  384. package/dist/workspace/write-lock.d.ts.map +1 -0
  385. package/dist/workspace/write-scope.d.ts +83 -19
  386. package/dist/workspace/write-scope.d.ts.map +1 -1
  387. package/dist/yaml.d.ts +21 -39
  388. package/dist/yaml.d.ts.map +1 -1
  389. package/package.json +7 -2
  390. package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
  391. package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
  392. package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
  393. package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
  394. package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
  395. package/src/__fixtures__/change-set/warden.plan.json +44 -0
  396. package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
  397. package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
  398. package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
  399. package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
  400. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
  401. package/src/audit/core.test.ts +15 -0
  402. package/src/audit/core.ts +8 -2
  403. package/src/audit/discover.test.ts +11 -0
  404. package/src/audit/discover.ts +7 -2
  405. package/src/audit/prior-art.ts +15 -0
  406. package/src/change-set-bundle.test.ts +57 -0
  407. package/src/change-set.test.ts +215 -0
  408. package/src/change-set.ts +445 -0
  409. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
  410. package/src/cli/commands/audit-opt-in.test.ts +54 -0
  411. package/src/cli/commands/audit.ts +29 -2
  412. package/src/cli/commands/build.test.ts +19 -0
  413. package/src/cli/commands/build.ts +3 -2
  414. package/src/cli/commands/carve-emit-state.test.ts +4 -0
  415. package/src/cli/commands/carve-emit.ts +5 -19
  416. package/src/cli/commands/check-lexicon.test.ts +62 -1
  417. package/src/cli/commands/check-lexicon.ts +36 -6
  418. package/src/cli/commands/import-live.test.ts +18 -0
  419. package/src/cli/commands/import-parser-options.test.ts +133 -0
  420. package/src/cli/commands/import.ts +21 -3
  421. package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
  422. package/src/cli/commands/init.test.ts +8 -1
  423. package/src/cli/commands/init.ts +23 -8
  424. package/src/cli/commands/lint.test.ts +37 -0
  425. package/src/cli/commands/onboard.test.ts +53 -3
  426. package/src/cli/commands/onboard.ts +52 -4
  427. package/src/cli/commands/pinned-upgrade.ts +73 -33
  428. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
  429. package/src/cli/handlers/build.ts +13 -1
  430. package/src/cli/handlers/change-set.test.ts +56 -0
  431. package/src/cli/handlers/change-set.ts +44 -0
  432. package/src/cli/handlers/components.ts +2 -2
  433. package/src/cli/handlers/dev.ts +8 -6
  434. package/src/cli/handlers/fan-out.test.ts +221 -2
  435. package/src/cli/handlers/fan-out.ts +165 -75
  436. package/src/cli/handlers/graph.ts +3 -0
  437. package/src/cli/handlers/lifecycle.test.ts +67 -0
  438. package/src/cli/handlers/lifecycle.ts +6 -5
  439. package/src/cli/handlers/misc.ts +2 -0
  440. package/src/cli/handlers/operator.test.ts +21 -0
  441. package/src/cli/handlers/operator.ts +121 -6
  442. package/src/cli/handlers/pr.ts +373 -0
  443. package/src/cli/handlers/run.test.ts +111 -0
  444. package/src/cli/handlers/run.ts +86 -24
  445. package/src/cli/handlers/scenario.ts +2 -2
  446. package/src/cli/main.test.ts +21 -0
  447. package/src/cli/main.ts +246 -30
  448. package/src/cli/mcp/never-over-mcp.test.ts +101 -0
  449. package/src/cli/mcp/op-tools.ts +24 -2
  450. package/src/cli/mcp/workspace-tools.test.ts +5 -2
  451. package/src/cli/mcp/workspace-tools.ts +62 -7
  452. package/src/cli/registry.ts +74 -3
  453. package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
  454. package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
  455. package/src/codegen/pinned-upgrade.test.ts +104 -0
  456. package/src/codegen/pinned-upgrade.ts +250 -56
  457. package/src/codegen/testdata/postgres-tags.json +242 -0
  458. package/src/components/auto-release.ts +1 -1
  459. package/src/components/capability.ts +55 -0
  460. package/src/components/changed-files.ts +66 -0
  461. package/src/components/cli-support.ts +28 -5
  462. package/src/components/component.schema.json +17 -0
  463. package/src/components/component.ts +25 -0
  464. package/src/components/deploy-units.ts +3 -0
  465. package/src/components/driver.test.ts +52 -0
  466. package/src/components/driver.ts +31 -13
  467. package/src/components/fan-out-output.ts +42 -1
  468. package/src/components/fan-out-record.ts +69 -0
  469. package/src/components/fan-out-run.test.ts +17 -0
  470. package/src/components/fan-out-run.ts +304 -1
  471. package/src/components/fan-out-support.ts +3 -0
  472. package/src/components/fan-out-waves.test.ts +375 -0
  473. package/src/components/fan-out.ts +18 -17
  474. package/src/components/gated-wave-pipeline.ts +82 -0
  475. package/src/components/index.ts +1 -0
  476. package/src/components/layers.ts +30 -0
  477. package/src/components/pr-pipeline.ts +91 -0
  478. package/src/components/pr-run.test.ts +205 -0
  479. package/src/components/pr-run.ts +280 -0
  480. package/src/components/promote.ts +5 -0
  481. package/src/components/verbs/shell.test.ts +11 -0
  482. package/src/components/verbs/shell.ts +7 -3
  483. package/src/components/wave-plan.ts +124 -0
  484. package/src/config.test.ts +21 -0
  485. package/src/config.ts +15 -0
  486. package/src/declarable.test.ts +21 -0
  487. package/src/declarable.ts +19 -0
  488. package/src/discovery/fold-composite.test.ts +41 -5
  489. package/src/discovery/fold-import.test.ts +129 -0
  490. package/src/discovery/fold-import.ts +643 -131
  491. package/src/discovery/fold-package-composite.test.ts +264 -0
  492. package/src/discovery/fold-specifiers.test.ts +191 -0
  493. package/src/discovery/param-deps.test.ts +66 -1
  494. package/src/discovery/param-deps.ts +45 -0
  495. package/src/discovery/sandbox/bundle.ts +1 -1
  496. package/src/discovery/specifier-resolve.ts +344 -0
  497. package/src/fold/fold.test.ts +39 -1
  498. package/src/fold/fold.ts +83 -9
  499. package/src/fold-provenance.test.ts +140 -0
  500. package/src/gated-waves-bundle.test.ts +62 -0
  501. package/src/gated-waves.test.ts +118 -0
  502. package/src/gated-waves.ts +240 -0
  503. package/src/graph-ir.test.ts +83 -0
  504. package/src/graph-ir.ts +29 -0
  505. package/src/import/embedded.test.ts +20 -0
  506. package/src/import/embedded.ts +13 -0
  507. package/src/import/parser-options.ts +46 -0
  508. package/src/import/parser.ts +20 -0
  509. package/src/index.ts +1 -0
  510. package/src/lexicon.ts +106 -3
  511. package/src/lifecycle/gate-ledger.ts +23 -0
  512. package/src/lifecycle/git.ts +102 -16
  513. package/src/lifecycle/observe.test.ts +18 -0
  514. package/src/lifecycle/observe.ts +6 -4
  515. package/src/lifecycle/snapshot.ts +2 -2
  516. package/src/lifecycle/work-lease.test.ts +1 -1
  517. package/src/lifecycle/work-lease.ts +93 -2
  518. package/src/lint/engine.test.ts +55 -0
  519. package/src/lint/engine.ts +30 -4
  520. package/src/lint/output-docs.test.ts +59 -56
  521. package/src/lint/post-synth.test.ts +19 -0
  522. package/src/lint/post-synth.ts +19 -1
  523. package/src/meta/declared-imports.test.ts +1 -1
  524. package/src/op/activities/activity-contracts.ts +84 -0
  525. package/src/op/activities/apply.test.ts +189 -5
  526. package/src/op/activities/apply.ts +230 -8
  527. package/src/op/activities/change-set.ts +114 -0
  528. package/src/op/activities/decide.ts +3 -0
  529. package/src/op/activities/factory.ts +675 -0
  530. package/src/op/activities/index.ts +9 -0
  531. package/src/op/activities/lexicon-upgrade.test.ts +160 -6
  532. package/src/op/activities/lexicon-upgrade.ts +154 -51
  533. package/src/op/activity-contract.test.ts +21 -1
  534. package/src/op/activity-contract.ts +19 -9
  535. package/src/op/builders.ts +23 -0
  536. package/src/op/composites/apply-op.ts +12 -5
  537. package/src/op/composites/composites.test.ts +30 -3
  538. package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
  539. package/src/op/composites/lexicon-upgrade-op.ts +29 -8
  540. package/src/op/decide-backend.ts +5 -1
  541. package/src/op/decide-read-inputs.ts +33 -5
  542. package/src/op/emulator-lifecycle.test.ts +23 -0
  543. package/src/op/emulator-lifecycle.ts +52 -14
  544. package/src/op/factory.e2e.test.ts +232 -0
  545. package/src/op/factory.ts +118 -0
  546. package/src/op/gate-approval.test.ts +74 -0
  547. package/src/op/gate-approval.ts +5 -1
  548. package/src/op/gate.ts +31 -5
  549. package/src/op/index.ts +11 -1
  550. package/src/op/local-executor.test.ts +15 -0
  551. package/src/op/local-executor.ts +40 -12
  552. package/src/op/local-output.ts +1 -1
  553. package/src/op/op-ir.test.ts +9 -0
  554. package/src/op/op-ir.ts +4 -0
  555. package/src/op/op-verb-class.ts +3 -0
  556. package/src/op/operator.ts +4 -0
  557. package/src/op/run-context.test.ts +141 -0
  558. package/src/op/run-context.ts +51 -0
  559. package/src/op/runtimes/local.test.ts +14 -0
  560. package/src/op/runtimes/local.ts +2 -0
  561. package/src/op/steward-beside.ts +2 -0
  562. package/src/op/types.ts +16 -3
  563. package/src/op/work-lease-run.test.ts +47 -0
  564. package/src/op/work-lease-run.ts +76 -11
  565. package/src/plan-summary.test.ts +263 -0
  566. package/src/plan-summary.ts +845 -0
  567. package/src/pr-forge.test.ts +237 -0
  568. package/src/pr-forge.ts +332 -0
  569. package/src/pr-loop-bundle.test.ts +46 -0
  570. package/src/pr-loop.test.ts +171 -0
  571. package/src/pr-loop.ts +324 -0
  572. package/src/provenance.ts +35 -0
  573. package/src/telemetry-attribution.test.ts +23 -1
  574. package/src/telemetry-attribution.ts +51 -0
  575. package/src/terraform/hcl2json.test.ts +21 -0
  576. package/src/terraform/hcl2json.ts +81 -0
  577. package/src/terraform/parse.ts +11 -74
  578. package/src/workspace/agent-cli.ts +7 -3
  579. package/src/workspace/agent.schema.json +22 -0
  580. package/src/workspace/app-kind.test.ts +196 -0
  581. package/src/workspace/box-cli.ts +113 -0
  582. package/src/workspace/box-factory.test.ts +323 -0
  583. package/src/workspace/box-factory.ts +136 -0
  584. package/src/workspace/box-listing-write.schema.json +204 -0
  585. package/src/workspace/box-listing.test.ts +234 -0
  586. package/src/workspace/box-listing.ts +324 -0
  587. package/src/workspace/box-publish.schema.json +498 -0
  588. package/src/workspace/box-publish.test.ts +204 -0
  589. package/src/workspace/box-publish.ts +420 -0
  590. package/src/workspace/box-ship.test.ts +96 -0
  591. package/src/workspace/broker-protocol.schema.json +186 -0
  592. package/src/workspace/broker-protocol.test.ts +122 -0
  593. package/src/workspace/broker-protocol.ts +317 -0
  594. package/src/workspace/builder-tiers.test.ts +146 -0
  595. package/src/workspace/change-set.schema.json +460 -0
  596. package/src/workspace/changes.schema.json +12 -20
  597. package/src/workspace/changes.ts +4 -1
  598. package/src/workspace/chant-migrations.e2e.test.ts +17 -5
  599. package/src/workspace/checks/boxes.test.ts +5 -0
  600. package/src/workspace/checks.ts +39 -8
  601. package/src/workspace/component-environments.test.ts +105 -0
  602. package/src/workspace/compose-graph.ts +7 -0
  603. package/src/workspace/composites.schema.json +23 -4
  604. package/src/workspace/composites.test.ts +8 -8
  605. package/src/workspace/composites.ts +13 -2
  606. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
  607. package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
  608. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
  609. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
  610. package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  611. package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  612. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
  613. package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  614. package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  615. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
  616. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
  617. package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  618. package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  619. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
  620. package/src/workspace/conformance/broker.test.ts +122 -0
  621. package/src/workspace/conformance/broker.ts +792 -0
  622. package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
  623. package/src/workspace/conformance/index.mjs +51 -3
  624. package/src/workspace/conformance/index.ts +107 -15
  625. package/src/workspace/conformance/vitest.ts +76 -2
  626. package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
  627. package/src/workspace/conformance/writer.test.ts +186 -0
  628. package/src/workspace/conformance/writer.ts +1191 -0
  629. package/src/workspace/decide.test.ts +208 -4
  630. package/src/workspace/decide.ts +433 -73
  631. package/src/workspace/decision-points.schema.json +11 -4
  632. package/src/workspace/declaration.schema.json +383 -5
  633. package/src/workspace/declaration.ts +315 -10
  634. package/src/workspace/environments.ts +66 -14
  635. package/src/workspace/factory-rules.test.ts +62 -0
  636. package/src/workspace/factory-rules.ts +218 -0
  637. package/src/workspace/graph-cli.ts +6 -3
  638. package/src/workspace/graph.schema.json +314 -0
  639. package/src/workspace/identity.test.ts +219 -0
  640. package/src/workspace/identity.ts +186 -0
  641. package/src/workspace/init.ts +82 -2
  642. package/src/workspace/intent-cli.ts +84 -13
  643. package/src/workspace/intent-patch-id.test.ts +162 -0
  644. package/src/workspace/intent-record.schema.json +336 -1
  645. package/src/workspace/intent-record.ts +96 -16
  646. package/src/workspace/intent-reviews.test.ts +76 -0
  647. package/src/workspace/intent-squash.test.ts +213 -0
  648. package/src/workspace/intent-why.test.ts +274 -0
  649. package/src/workspace/intent.schema.json +950 -9
  650. package/src/workspace/intent.test.ts +11 -2
  651. package/src/workspace/intent.ts +722 -65
  652. package/src/workspace/json-edit.test.ts +121 -0
  653. package/src/workspace/json-edit.ts +142 -0
  654. package/src/workspace/jsonc.ts +20 -0
  655. package/src/workspace/kinds.ts +201 -39
  656. package/src/workspace/lexicon-symbols.test.ts +148 -0
  657. package/src/workspace/lexicon-symbols.ts +125 -0
  658. package/src/workspace/lineage-upgrade.test.ts +63 -0
  659. package/src/workspace/lineage-upgrade.ts +146 -5
  660. package/src/workspace/plan-summary.schema.json +155 -0
  661. package/src/workspace/point-answer.schema.json +42 -2
  662. package/src/workspace/points-cli.ts +42 -16
  663. package/src/workspace/points-write.schema.json +163 -4
  664. package/src/workspace/points.schema.json +157 -2
  665. package/src/workspace/points.test.ts +13 -1
  666. package/src/workspace/points.ts +118 -12
  667. package/src/workspace/pr-report.schema.json +95 -0
  668. package/src/workspace/principal-classes.test.ts +175 -0
  669. package/src/workspace/principal-classes.ts +307 -0
  670. package/src/workspace/profiles.test.ts +159 -0
  671. package/src/workspace/read-contract.test.ts +2 -2
  672. package/src/workspace/reason-codes.test.ts +23 -3
  673. package/src/workspace/reason-codes.ts +61 -4
  674. package/src/workspace/record-sessions.ts +9 -8
  675. package/src/workspace/records-amend.schema.json +80 -0
  676. package/src/workspace/records-checkout.ts +106 -0
  677. package/src/workspace/records-cli.ts +123 -17
  678. package/src/workspace/records-close.schema.json +79 -0
  679. package/src/workspace/records-close.ts +31 -7
  680. package/src/workspace/records-concurrent.e2e.test.ts +135 -0
  681. package/src/workspace/records-concurrent.test.ts +145 -0
  682. package/src/workspace/records-formats.test.ts +46 -10
  683. package/src/workspace/records-new.schema.json +9 -0
  684. package/src/workspace/records-review.schema.json +80 -0
  685. package/src/workspace/records-sessions-write.test.ts +69 -0
  686. package/src/workspace/records-sessions.test.ts +22 -0
  687. package/src/workspace/records-uncommitted.test.ts +171 -0
  688. package/src/workspace/records-write.ts +219 -30
  689. package/src/workspace/records.schema.json +88 -1
  690. package/src/workspace/records.ts +76 -8
  691. package/src/workspace/reference-kinds/app/package.json +10 -0
  692. package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  693. package/src/workspace/run-statement.schema.json +622 -0
  694. package/src/workspace/runs-cli.ts +710 -0
  695. package/src/workspace/runs-statement.test.ts +239 -0
  696. package/src/workspace/runs-write.schema.json +994 -0
  697. package/src/workspace/runs.schema.json +1257 -0
  698. package/src/workspace/runs.test.ts +281 -0
  699. package/src/workspace/runs.ts +970 -0
  700. package/src/workspace/session-kinds.ts +3 -3
  701. package/src/workspace/squash.ts +198 -0
  702. package/src/workspace/status-contract.test.ts +10 -2
  703. package/src/workspace/status-gates.ts +25 -9
  704. package/src/workspace/status.schema.json +252 -4
  705. package/src/workspace/status.ts +110 -1
  706. package/src/workspace/symbols.ts +191 -0
  707. package/src/workspace/trailer-joins.test.ts +171 -0
  708. package/src/workspace/trailer-joins.ts +82 -0
  709. package/src/workspace/trailers.ts +148 -0
  710. package/src/workspace/trust/run-commits.ts +115 -0
  711. package/src/workspace/trust/run-statement.ts +226 -0
  712. package/src/workspace/trust/seal.ts +58 -1
  713. package/src/workspace/trust/verify-cli.ts +6 -5
  714. package/src/workspace/trust/verify.ts +39 -6
  715. package/src/workspace/wip-cli.ts +97 -0
  716. package/src/workspace/wip-write.schema.json +504 -0
  717. package/src/workspace/wip.schema.json +334 -0
  718. package/src/workspace/wip.test.ts +294 -0
  719. package/src/workspace/wip.ts +753 -0
  720. package/src/workspace/work-cli.e2e.test.ts +28 -1
  721. package/src/workspace/work-cli.ts +136 -8
  722. package/src/workspace/work-evidence.schema.json +5 -0
  723. package/src/workspace/work-history.schema.json +73 -1
  724. package/src/workspace/work-history.test.ts +48 -5
  725. package/src/workspace/work-kind-fields.test.ts +154 -0
  726. package/src/workspace/work-lease.schema.json +14 -1
  727. package/src/workspace/work-size.test.ts +77 -0
  728. package/src/workspace/work-size.ts +93 -0
  729. package/src/workspace/work.ts +82 -0
  730. package/src/workspace/workspace-kinds.schema.json +122 -0
  731. package/src/workspace/workspace-principals.schema.json +60 -0
  732. package/src/workspace/write-lock-cli.ts +131 -0
  733. package/src/workspace/write-lock.schema.json +172 -0
  734. package/src/workspace/write-lock.test.ts +189 -0
  735. package/src/workspace/write-lock.ts +474 -0
  736. package/src/workspace/write-scope.test.ts +144 -3
  737. package/src/workspace/write-scope.ts +192 -45
  738. package/src/yaml.test.ts +111 -1
  739. package/src/yaml.ts +141 -549
@@ -0,0 +1,373 @@
1
+ /**
2
+ * `chant components pr-plan` and `chant components pr-apply` (#3183): the
3
+ * pull-request loop the generated CI runs.
4
+ *
5
+ * ```
6
+ * chant components pr-plan --base <ref> --pr <n> --env <env> [--forge github|gitlab|forgejo]
7
+ * chant approve pr-<n> pr-apply --plan <digest> --approver github:<login> --sign
8
+ * chant components pr-apply --base <ref> --env <env> [--pr <n>] [--forge <kind>] [--require-review]
9
+ * ```
10
+ *
11
+ * Both measure the change from the merge base of `--base` and `HEAD`, select
12
+ * the components it reaches and the ones that depend on them (the fan-out's
13
+ * derivation, #2417), and plan every member before anything applies
14
+ * (`../../components/pr-run.ts`). pr-plan writes the report and the note and
15
+ * applies nothing; it reads the gate ledger and writes nothing to it, since
16
+ * it runs the pull request's own code. pr-apply plans the same members on
17
+ * the merged commit, decides the gate against the digest it gets, and
18
+ * applies only when an approval stands for that digest. A moved plan stops
19
+ * it with both digests named and nothing applied (exit 3).
20
+ *
21
+ * Every run writes `pr-plan.json` or `pr-apply.json` (`pr-report.schema.json`),
22
+ * `change-set.json` and `pr-note.md` under `--output` (default `.chant/pr`).
23
+ */
24
+
25
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
26
+ import { join, resolve } from "node:path";
27
+ import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
28
+ import { resolveCommit, resolveMergeBase } from "../../components/changed-files";
29
+ import { deriveFanOut, fanOutRegistry } from "../../components/fan-out-support";
30
+ import {
31
+ applyPrSet,
32
+ approvalOf,
33
+ approversWithoutReview,
34
+ decidePrGate,
35
+ planPrSet,
36
+ prReport,
37
+ readOnlyLedger,
38
+ type PrPlanSet,
39
+ } from "../../components/pr-run";
40
+ import { gitGateLedgerPort } from "../../op/gate";
41
+ import {
42
+ describePlanChanged,
43
+ PR_APPLY_GATE,
44
+ PR_STATUS_CONTEXTS,
45
+ prApproveCommand,
46
+ prNoteMarker,
47
+ prOp,
48
+ prStatusDescription,
49
+ prStatusState,
50
+ renderPrNote,
51
+ type PrApproval,
52
+ type PrReport,
53
+ } from "../../pr-loop";
54
+ import { FORGE_KINDS, forgeFromEnv, forgePrincipalOf, type ForgeKind, type PrForge } from "../../pr-forge";
55
+ import { GITHUB_COMMENT_LIMIT, GITLAB_NOTE_LIMIT } from "../../plan-summary";
56
+ import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
57
+ import { formatError, formatInfo, formatSuccess, formatWarning } from "../format";
58
+ import { resolveChangedUnits } from "./fan-out";
59
+ import { GATED_EXIT_CODE, recordAutoReleasesForRun } from "./run";
60
+ import type { CommandContext } from "../registry";
61
+ import type { ComponentChangeSignal, FanOutPlan } from "../../components/fan-out";
62
+ import type { DriverComponent } from "../../components/driver";
63
+ import type { CapabilityRegistry } from "../../components/capability";
64
+
65
+
66
+ /** Where the reports land unless `--output` says. */
67
+ export const PR_REPORT_DIR = ".chant/pr";
68
+
69
+ interface Prepared {
70
+ config: ChantConfig;
71
+ env: string;
72
+ base: string;
73
+ head: string;
74
+ gate: string;
75
+ forge?: PrForge;
76
+ components: DriverComponent[];
77
+ plan: FanOutPlan;
78
+ signal: ComponentChangeSignal;
79
+ registry: CapabilityRegistry;
80
+ set: PrPlanSet;
81
+ }
82
+
83
+ const fail = (message: string, hint?: string): number => {
84
+ console.error(formatError({ message, ...(hint ? { hint } : {}) }));
85
+ return 1;
86
+ };
87
+
88
+ /** Everything both stages share: the change, the derivation and the plan of every member. */
89
+ async function prepare(ctx: CommandContext, stage: "plan" | "apply"): Promise<Prepared | number> {
90
+ const { args } = ctx;
91
+ const projectPath = resolve(".");
92
+ const { config } = await loadChantConfig(projectPath).catch(() => ({ config: {} as ChantConfig }));
93
+ const paramsResolution = resolveCliBuildParams(config.buildParams, {
94
+ cli: parseParamFlags(args.param),
95
+ paramsFile: args.paramsFile,
96
+ verbose: args.verbose,
97
+ });
98
+ if (!paramsResolution.success) {
99
+ for (const message of paramsResolution.errors) console.error(message);
100
+ return 1;
101
+ }
102
+ if (!args.base) {
103
+ return fail(
104
+ `pr-${stage} needs the commit the change is measured from: --base <ref>`,
105
+ stage === "plan" ? "On a pull request, the target branch's commit." : "On a push, the commit before it.",
106
+ );
107
+ }
108
+ if (args.fromAffected) return fail(`pr-${stage} derives the change itself; drop --from-affected`);
109
+ if (args.forge !== undefined && !(FORGE_KINDS as readonly string[]).includes(args.forge)) {
110
+ return fail(`--forge ${args.forge} is not one of ${FORGE_KINDS.join(", ")}`);
111
+ }
112
+
113
+ let forge: PrForge | undefined;
114
+ if (args.forge) {
115
+ try {
116
+ forge = forgeFromEnv(args.forge as ForgeKind);
117
+ } catch (err) {
118
+ return fail(err instanceof Error ? err.message : String(err));
119
+ }
120
+ }
121
+
122
+ let base: string;
123
+ let head: string;
124
+ try {
125
+ head = await resolveCommit(projectPath, args.head ?? "HEAD");
126
+ base = await resolveMergeBase(projectPath, args.base, head);
127
+ } catch (err) {
128
+ return fail(err instanceof Error ? err.message : String(err));
129
+ }
130
+
131
+ const signal = await resolveChangedUnits(ctx, config, { base, stacksOnly: true });
132
+ if ("error" in signal) return fail(signal.error, signal.hint);
133
+
134
+ let derived;
135
+ try {
136
+ derived = await deriveFanOut({
137
+ path: projectPath,
138
+ units: signal.units,
139
+ sandbox: args.sandbox,
140
+ buildParams: paramsResolution.provenance,
141
+ config,
142
+ });
143
+ } catch (err) {
144
+ return fail(err instanceof Error ? err.message : String(err));
145
+ }
146
+ if (!derived.success) return fail(derived.error ?? "Could not discover components");
147
+
148
+ const seededOutputs: Record<string, Record<string, unknown>> = {};
149
+ for (const file of args.seedOutputs ?? []) {
150
+ try {
151
+ Object.assign(seededOutputs, JSON.parse(readFileSync(resolve(file), "utf8")));
152
+ } catch (err) {
153
+ return fail(`--seed-outputs: could not read "${file}": ${err instanceof Error ? err.message : String(err)}`);
154
+ }
155
+ }
156
+
157
+ const env = args.env ?? "local";
158
+ const registry = await fanOutRegistry(projectPath, config);
159
+ const set = await planPrSet({ components: derived.components, plan: derived.plan, registry, env, seededOutputs });
160
+ return {
161
+ config,
162
+ env,
163
+ base,
164
+ head,
165
+ gate: args.gate ?? PR_APPLY_GATE,
166
+ ...(forge ? { forge } : {}),
167
+ components: derived.components,
168
+ plan: derived.plan,
169
+ signal: derived.signal,
170
+ registry,
171
+ set,
172
+ };
173
+ }
174
+
175
+ /** Write the report, the change set and the note; print the note's path. */
176
+ function writeOutputs(ctx: CommandContext, report: PrReport, note: string): void {
177
+ const dir = resolve(ctx.args.output ?? PR_REPORT_DIR);
178
+ mkdirSync(dir, { recursive: true });
179
+ writeFileSync(join(dir, `pr-${report.stage}.json`), JSON.stringify(report, null, 2) + "\n");
180
+ writeFileSync(join(dir, "change-set.json"), JSON.stringify(report.changeSet, null, 2) + "\n");
181
+ writeFileSync(join(dir, "pr-note.md"), note);
182
+ }
183
+
184
+ /** Post the note and the stage's status. A forge that refuses is a warning: the stage's outcome stands. */
185
+ async function publish(forge: PrForge | undefined, report: PrReport, note: string): Promise<void> {
186
+ if (!forge) return;
187
+ const status = {
188
+ context: PR_STATUS_CONTEXTS[report.stage],
189
+ state: prStatusState(report),
190
+ description: prStatusDescription(report),
191
+ ...(forge.runUrl ? { url: forge.runUrl } : {}),
192
+ };
193
+ try {
194
+ await forge.setStatus(report.head, status);
195
+ } catch (err) {
196
+ console.error(formatWarning({ message: `could not set the ${status.context} status: ${err instanceof Error ? err.message : String(err)}` }));
197
+ }
198
+ if (report.pr === null) return;
199
+ try {
200
+ await forge.upsertNote(report.pr, prNoteMarker(report.env), note);
201
+ } catch (err) {
202
+ console.error(formatWarning({ message: `could not post the note on #${report.pr}: ${err instanceof Error ? err.message : String(err)}` }));
203
+ }
204
+ }
205
+
206
+ function noteFor(report: PrReport, forge: PrForge | undefined): string {
207
+ return renderPrNote(report, {
208
+ limit: forge?.kind === "gitlab" ? GITLAB_NOTE_LIMIT : GITHUB_COMMENT_LIMIT,
209
+ approver: forge ? forgePrincipalOf(forge.kind, forge.host, "<your-login>") : "<you>",
210
+ });
211
+ }
212
+
213
+ function printMembers(report: PrReport): void {
214
+ for (const m of report.members) {
215
+ const c = m.counts;
216
+ console.error(` ${m.member.padEnd(20)} ${m.status.padEnd(12)} create ${c.create} update ${c.update} replace ${c.replace} delete ${c.delete}${m.error ? ` ${m.error}` : ""}`);
217
+ }
218
+ }
219
+
220
+ async function finish(ctx: CommandContext, p: Prepared, report: PrReport): Promise<void> {
221
+ const note = noteFor(report, p.forge);
222
+ writeOutputs(ctx, report, note);
223
+ await publish(p.forge, report, note);
224
+ if (ctx.args.json) console.log(JSON.stringify(report, null, 2));
225
+ }
226
+
227
+ /** chant components pr-plan --base <ref> --pr <n> [--env <env>] [--gate <name>] [--forge <kind>] [--output <dir>] [--json] */
228
+ export async function runComponentsPrPlan(ctx: CommandContext): Promise<number> {
229
+ if (ctx.args.pr === undefined) {
230
+ return fail("pr-plan needs the pull or merge request: --pr <n>", "Its approval is recorded under op pr-<n>, so one pull request's approval never answers another's.");
231
+ }
232
+ const p = await prepare(ctx, "plan");
233
+ if (typeof p === "number") return p;
234
+ const op = prOp(ctx.args.pr);
235
+
236
+ let approval: PrApproval = { status: "pending" };
237
+ if (p.plan.order.length > 0) {
238
+ try {
239
+ approval = approvalOf(await decidePrGate(readOnlyLedger(gitGateLedgerPort()), { op, gate: p.gate, digest: p.set.doc.digest }));
240
+ } catch (err) {
241
+ console.error(formatWarning({ message: `could not read the gate ledger, so the approval reads as pending: ${err instanceof Error ? err.message : String(err)}` }));
242
+ }
243
+ }
244
+ const status = p.plan.order.length === 0 ? "nothing" : p.set.failed ? "plan-failed" : "planned";
245
+ const report = prReport({
246
+ stage: "plan",
247
+ pr: ctx.args.pr,
248
+ env: p.env,
249
+ base: p.base,
250
+ head: p.head,
251
+ op,
252
+ gate: p.gate,
253
+ plan: p.plan,
254
+ signal: p.signal,
255
+ set: p.set,
256
+ approval,
257
+ status,
258
+ });
259
+ await finish(ctx, p, report);
260
+
261
+ console.error(formatInfo(`pr-plan: ${report.members.length} member(s), ${status}`));
262
+ printMembers(report);
263
+ if (status === "planned") {
264
+ console.error(formatInfo(`plan : ${report.digest}`));
265
+ console.error(formatInfo(approval.status === "approved" ? `approved by ${(approval.approvedBy ?? []).join(", ")}` : `approve : ${prApproveCommand(report)}`));
266
+ }
267
+ return status === "plan-failed" ? 1 : 0;
268
+ }
269
+
270
+ /** chant components pr-apply --base <ref> [--pr <n>] [--env <env>] [--gate <name>] [--forge <kind>] [--require-review] [--output <dir>] [--json] */
271
+ export async function runComponentsPrApply(ctx: CommandContext): Promise<number> {
272
+ const { args } = ctx;
273
+ if (args.requireReview && !args.forge) return fail("--require-review reads the pull request's reviews, so it needs --forge <kind>");
274
+ const p = await prepare(ctx, "apply");
275
+ if (typeof p === "number") return p;
276
+
277
+ let pr: number | null = args.pr ?? null;
278
+ if (pr === null && p.forge && p.plan.order.length > 0) {
279
+ try {
280
+ pr = await p.forge.pullRequestFor(p.head);
281
+ } catch (err) {
282
+ return fail(`could not ask ${p.forge.kind} which pull request merged ${p.head}: ${err instanceof Error ? err.message : String(err)}`);
283
+ }
284
+ }
285
+ const op = pr === null ? "pr-unknown" : prOp(pr);
286
+ const base = { stage: "apply" as const, pr, env: p.env, base: p.base, head: p.head, op, gate: p.gate, plan: p.plan, signal: p.signal, set: p.set };
287
+
288
+ const stop = async (report: PrReport, code: number): Promise<number> => {
289
+ await finish(ctx, p, report);
290
+ console.error((code === 0 ? formatInfo : (m: string) => formatWarning({ message: m }))(`pr-apply: ${report.status}${report.refusal ? ` (${report.refusal})` : ""}`));
291
+ if (report.message) console.error(report.message);
292
+ printMembers(report);
293
+ return code;
294
+ };
295
+
296
+ if (p.plan.order.length === 0) {
297
+ return stop(prReport({ ...base, approval: { status: "pending" }, status: "nothing" }), 0);
298
+ }
299
+ if (pr === null) {
300
+ return stop(
301
+ prReport({
302
+ ...base,
303
+ approval: { status: "pending" },
304
+ status: "refused",
305
+ refusal: "no-pull-request",
306
+ message: `No pull request merged ${p.head}, so no approval answers for this change. Nothing was applied. Pass --pr <n>, or land the change through a pull request.`,
307
+ }),
308
+ GATED_EXIT_CODE,
309
+ );
310
+ }
311
+ if (p.set.failed) {
312
+ return stop(
313
+ prReport({
314
+ ...base,
315
+ approval: { status: "pending" },
316
+ status: "plan-failed",
317
+ message: "A member failed to plan, so there is no plan to compare with the approved one. Nothing was applied.",
318
+ }),
319
+ 1,
320
+ );
321
+ }
322
+
323
+ const check = await decidePrGate(gitGateLedgerPort(), {
324
+ op,
325
+ gate: p.gate,
326
+ digest: p.set.doc.digest,
327
+ description: `pull request #${pr}: ${p.plan.order.join(", ")}`,
328
+ });
329
+ const approval = approvalOf(check);
330
+ if (!check.satisfied) {
331
+ const partial = { ...base, approval, status: "refused" as const };
332
+ const report = approval.status === "changed"
333
+ ? prReport({ ...partial, refusal: "plan-changed", message: describePlanChanged({ op, gate: p.gate, digest: p.set.doc.digest, approval }) })
334
+ : prReport({
335
+ ...partial,
336
+ refusal: "not-approved",
337
+ message: `No approval stands for this plan, so nothing was applied. Approve it: ${prApproveCommand({ op, gate: p.gate, digest: p.set.doc.digest })}; then run the apply again.`,
338
+ });
339
+ return stop(report, GATED_EXIT_CODE);
340
+ }
341
+
342
+ if (args.requireReview && p.forge) {
343
+ let reviewers: string[];
344
+ try {
345
+ reviewers = (await p.forge.approvers(pr)).map((login) => p.forge!.principalOf(login));
346
+ } catch (err) {
347
+ return fail(`could not read the reviews of #${pr}: ${err instanceof Error ? err.message : String(err)}`);
348
+ }
349
+ const strangers = approversWithoutReview(approval.approvedBy ?? [], reviewers);
350
+ if (strangers.length > 0) {
351
+ return stop(
352
+ prReport({
353
+ ...base,
354
+ approval,
355
+ status: "refused",
356
+ refusal: "not-a-reviewer",
357
+ message:
358
+ `The plan is approved by ${strangers.join(", ")}, who ${strangers.length === 1 ? "has" : "have"} no approving review on #${pr}` +
359
+ ` (approving reviews: ${reviewers.join(", ") || "none"}). Nothing was applied. ` +
360
+ `An approval counts when it names the reviewer the way the forge does: ${p.forge.principalOf("<login>")}.`,
361
+ }),
362
+ GATED_EXIT_CODE,
363
+ );
364
+ }
365
+ }
366
+
367
+ const applied = await applyPrSet({ components: p.components, plan: p.plan, registry: p.registry, env: p.env, set: p.set });
368
+ await recordAutoReleasesForRun(applied.run.results, p.env, `${op}-${Date.now()}`, resolveAutoReleaseDisabled(p.config, args.noReleaseRecord));
369
+ const report = prReport({ ...base, approval, status: applied.status, members: applied.members });
370
+ const code = await stop(report, applied.status === "applied" ? 0 : 1);
371
+ if (applied.status === "applied") console.error(formatSuccess(`applied the plan ${report.digest} approved by ${(approval.approvedBy ?? []).join(", ")}`));
372
+ return code;
373
+ }
@@ -424,6 +424,30 @@ describe("runOp: a steward's turn (#2750)", () => {
424
424
  expect(acquireStewardTurnMock).not.toHaveBeenCalled();
425
425
  });
426
426
 
427
+ test("fountain form with run.on: fountain and no flag: runs on fountain like --on fountain (#2523)", async () => {
428
+ const runtime = {
429
+ name: "fountain",
430
+ start: vi.fn(async (op: { name: string }) => ({
431
+ op: op.name,
432
+ runId: "f-1",
433
+ result: async () => ({ op: op.name, runId: "f-1", state: "completed" as const, startedAt: "t", endedAt: "t" }),
434
+ })),
435
+ status: vi.fn(), log: vi.fn(), list: vi.fn(), cancel: vi.fn(),
436
+ };
437
+ discoverOpsMock.mockResolvedValue({ ops: new Map([localOp("release", [])]), errors: [] });
438
+ discoverStewardsMock.mockResolvedValueOnce(stewardOwning("release", "box-steward", "fountain"));
439
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["fountain"], run: { on: "fountain" } } });
440
+ makeStdoutSpy();
441
+ const exit = await runOp({
442
+ args: makeArgs({ path: "release" }),
443
+ plugins: [{ name: "fountain", opRuntime: runtime } as never], serializers: [],
444
+ });
445
+
446
+ expect(exit).toBe(0);
447
+ expect(runtime.start).toHaveBeenCalledTimes(1);
448
+ expect(acquireStewardTurnMock).not.toHaveBeenCalled();
449
+ });
450
+
427
451
  test("local form, the turn lease's own acquire throws (a stale .lock): refused as a lease error, not an uncaught exception, and nothing runs", async () => {
428
452
  discoverOpsMock.mockResolvedValue({
429
453
  ops: new Map([localOp("release", [{ kind: "activity", fn: "shellCmd", args: { cmd: "true" } }])]),
@@ -899,6 +923,93 @@ describe("run subcommands on the resolved runtime", () => {
899
923
  expect(stderr.join("\n")).toContain('lexicon "plain" does not host Op runs');
900
924
  });
901
925
 
926
+ test("run.on in chant.config.ts is the default runtime when --on is not given (#2523)", async () => {
927
+ const runtime = makeStubRuntime();
928
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
929
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub"], run: { on: "stub" } } });
930
+ makeStdoutSpy();
931
+ makeStderrSpy();
932
+ const ctx = (over: Partial<ParsedArgs>) => ({ args: makeArgs(over), plugins: [stubPlugin(runtime)], serializers: [] });
933
+
934
+ expect(await runOp(ctx({ path: "hello" }))).toBe(0);
935
+ expect(await runOpStatus(ctx({ extraPositional: "hello" }))).toBe(0);
936
+ expect(await runOpLog(ctx({ extraPositional: "hello" }))).toBe(0);
937
+ expect(await runOpList(ctx({}))).toBe(0);
938
+ expect(runtime.start).toHaveBeenCalledTimes(1);
939
+ expect(runtime.status).toHaveBeenCalledWith("hello");
940
+ expect(runtime.log).toHaveBeenCalledTimes(1);
941
+ expect(runtime.list).toHaveBeenCalledTimes(1);
942
+ });
943
+
944
+ test("--on local overrides run.on and runs on the built-in runtime (#2523)", async () => {
945
+ const runtime = makeStubRuntime();
946
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
947
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub"], run: { on: "stub" } } });
948
+ makeStdoutSpy();
949
+ makeStderrSpy();
950
+ await runOpList({ args: makeArgs({ on: "local" }), plugins: [stubPlugin(runtime)], serializers: [] });
951
+ expect(runtime.list).not.toHaveBeenCalled();
952
+ });
953
+
954
+ test("run.on naming an unconfigured lexicon gets --on's refusal, naming run.on (#2523)", async () => {
955
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
956
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["aws"], run: { on: "nope" } } });
957
+ const stderr = makeStderrSpy();
958
+ const exit = await runOp({ args: makeArgs({ path: "hello" }), plugins: [], serializers: [] });
959
+ expect(exit).toBe(1);
960
+ expect(stderr.join("\n")).toContain('run.on "nope" in chant.config.ts: "nope" is not a configured lexicon');
961
+ expect(stderr.join("\n")).toContain("Configured lexicons: aws");
962
+ expect(stderr.join("\n")).toContain("--on local");
963
+ });
964
+
965
+ test("an explicit --on wins over run.on (#2523)", async () => {
966
+ const chosen = makeStubRuntime();
967
+ const other = makeStubRuntime();
968
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
969
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub", "other"], run: { on: "other" } } });
970
+ makeStdoutSpy();
971
+ makeStderrSpy();
972
+ const plugins = [stubPlugin(chosen), { name: "other", opRuntime: other } as never];
973
+ expect(await runOpList({ args: makeArgs({ on: "stub" }), plugins, serializers: [] })).toBe(0);
974
+ expect(chosen.list).toHaveBeenCalledTimes(1);
975
+ expect(other.list).not.toHaveBeenCalled();
976
+ });
977
+
978
+ test("run.on: local selects the built-in runtime (#2523)", async () => {
979
+ const runtime = makeStubRuntime();
980
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
981
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub"], run: { on: "local" } } });
982
+ makeStdoutSpy();
983
+ makeStderrSpy();
984
+ await runOpList({ args: makeArgs({}), plugins: [stubPlugin(runtime)], serializers: [] });
985
+ expect(runtime.list).not.toHaveBeenCalled();
986
+ });
987
+
988
+ test("an invalid run block is refused, not run locally (#2523)", async () => {
989
+ const { InvalidChantConfigError } = await vi.importActual<typeof import("../../config")>("../../config");
990
+ const runtime = makeStubRuntime();
991
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
992
+ loadChantConfigMock.mockRejectedValue(
993
+ new InvalidChantConfigError("Invalid chant config in /p/chant.config.ts: run.on: Expected string, received number", "run"),
994
+ );
995
+ const stderr = makeStderrSpy();
996
+ makeStdoutSpy();
997
+ expect(await runOpList({ args: makeArgs({}), plugins: [stubPlugin(runtime)], serializers: [] })).toBe(1);
998
+ expect(stderr.join("\n")).toContain("Invalid chant config in /p/chant.config.ts: run.on");
999
+ expect(runtime.list).not.toHaveBeenCalled();
1000
+ // --on local still runs: the flag needs nothing from the config.
1001
+ expect(await runOpList({ args: makeArgs({ on: "local" }), plugins: [stubPlugin(runtime)], serializers: [] })).toBe(0);
1002
+ });
1003
+
1004
+ test("run.on naming a lexicon with no opRuntime gets --on's refusal, naming run.on (#2523)", async () => {
1005
+ discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
1006
+ loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["plain"], run: { on: "plain" } } });
1007
+ const stderr = makeStderrSpy();
1008
+ const exit = await runOp({ args: makeArgs({ path: "hello" }), plugins: [{ name: "plain" } as never], serializers: [] });
1009
+ expect(exit).toBe(1);
1010
+ expect(stderr.join("\n")).toContain('run.on "plain" in chant.config.ts: lexicon "plain" does not host Op runs');
1011
+ });
1012
+
902
1013
  test("--components on a runtime that cannot host them → one line, exit 1", async () => {
903
1014
  const runtime = makeStubRuntime();
904
1015
  const stderr = makeStderrSpy();
@@ -1,7 +1,7 @@
1
1
  import { lexiconNames } from "../../lexicon-module";
2
- import { resolve, dirname } from "node:path";
2
+ import { resolve, dirname, basename } from "node:path";
3
3
  import { writeFileSync, mkdirSync, readFileSync } from "node:fs";
4
- import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
4
+ import { loadChantConfig, resolveAutoReleaseDisabled, InvalidChantConfigError, type ChantConfig } from "../../config";
5
5
  import { discoverOps, discoverStewards } from "../../op/discover";
6
6
  import { stewardWorkHolder } from "../../op/work-lease-run";
7
7
  import type { OpConfig } from "../../op/types";
@@ -108,10 +108,12 @@ function refuseDurableComponentSubcommand(what: string, hint: string): number {
108
108
  /**
109
109
  * Resolve the one runtime this invocation talks to.
110
110
  *
111
- * `--on <name>` picks the named lexicon's `opRuntime` (`../../lexicon.ts`);
112
- * without it, core's built-in `local` provider runs the Op in this process.
113
- * Every `chant run` subcommand goes through whichever comes back, so there is
114
- * one dispatch path rather than a branch per runtime.
111
+ * `--on <name>` picks the named lexicon's `opRuntime` (`../../lexicon.ts`).
112
+ * Without it, `run.on` in `chant.config.ts` does (#2523), and without either,
113
+ * core's built-in `local` provider runs the Op in this process. `local`, from
114
+ * either place, names the built-in provider. Every `chant run` subcommand goes
115
+ * through whichever comes back, so there is one dispatch path rather than a
116
+ * branch per runtime.
115
117
  *
116
118
  * A lexicon already loaded into the command context wins the lookup — that is
117
119
  * how a test hands in a stub, and how a command that loaded plugins for its
@@ -121,22 +123,20 @@ function refuseDurableComponentSubcommand(what: string, hint: string): number {
121
123
  *
122
124
  * Returns `undefined` after printing an actionable error — an unconfigured
123
125
  * name is answered with the configured list, a configured lexicon that hosts
124
- * nothing is named outright.
126
+ * nothing is named outright. A `run.on` default gets the same messages as
127
+ * `--on`, labelled `run.on` and the config file instead of `--on`.
125
128
  */
126
129
  async function resolveOpRuntime(ctx: CommandContext): Promise<OpRuntimeProvider | undefined> {
127
- const on = ctx.args.on;
130
+ const choice = await chooseOpRuntime(ctx);
131
+ if (!choice) return undefined;
132
+ const { on, source, configured } = choice;
128
133
  if (!on || on === "local") return createLocalOpRuntime({ projectPath: resolve(".") });
129
134
 
130
- // Read the configured list straight from `chant.config.ts` rather than
131
- // through `resolveProjectLexicons`: `--on` names a *configured* lexicon, and
132
- // that helper's fallback is a source scan of the whole project, which is a
133
- // long wait to be told a name is wrong.
134
- let configured: string[] = [];
135
- try {
136
- configured = lexiconNames((await loadChantConfig(resolve("."))).config.lexicons ?? []);
137
- } catch {
138
- // No/unreadable chant.config.ts — the error below says so by listing nothing.
139
- }
135
+ // How the error names the choice, and how to get the built-in runtime back.
136
+ const label = source === "flag" ? `--on ${on}` : `run.on "${on}" in ${choice.configFile}`;
137
+ const fallback = source === "flag"
138
+ ? "Omit --on to run on the built-in local runtime."
139
+ : `Fix \`run.on\` in ${choice.configFile}, or pass --on local to run on the built-in local runtime.`;
140
140
 
141
141
  let plugin = ctx.plugins.find((p) => p.name === on);
142
142
  if (!plugin && configured.includes(on)) {
@@ -146,18 +146,18 @@ async function resolveOpRuntime(ctx: CommandContext): Promise<OpRuntimeProvider
146
146
  if (!plugin) {
147
147
  const known = [...new Set([...ctx.plugins.map((p) => p.name), ...configured])];
148
148
  console.error(formatError({
149
- message: `--on ${on}: "${on}" is not a configured lexicon`,
149
+ message: `${label}: "${on}" is not a configured lexicon`,
150
150
  hint: known.length > 0
151
- ? `Configured lexicons: ${known.join(", ")}. Omit --on to run on the built-in local runtime.`
152
- : "chant.config.ts configures no lexicons. Omit --on to run on the built-in local runtime.",
151
+ ? `Configured lexicons: ${known.join(", ")}. ${fallback}`
152
+ : `chant.config.ts configures no lexicons. ${fallback}`,
153
153
  }));
154
154
  return undefined;
155
155
  }
156
156
 
157
157
  if (!plugin.opRuntime) {
158
158
  console.error(formatError({
159
- message: `--on ${on}: lexicon "${on}" does not host Op runs`,
160
- hint: "It declares no opRuntime. Omit --on to run on the built-in local runtime.",
159
+ message: `${label}: lexicon "${on}" does not host Op runs`,
160
+ hint: `It declares no opRuntime. ${fallback}`,
161
161
  }));
162
162
  return undefined;
163
163
  }
@@ -165,6 +165,64 @@ async function resolveOpRuntime(ctx: CommandContext): Promise<OpRuntimeProvider
165
165
  return plugin.opRuntime;
166
166
  }
167
167
 
168
+ /** Which runtime name an invocation asked for, and where the name came from. */
169
+ interface OpRuntimeChoice {
170
+ /** The runtime name; `undefined` or `"local"` is the built-in runtime. */
171
+ on: string | undefined;
172
+ /** `flag` for `--on`, `config` for `run.on`, `default` when neither named one. */
173
+ source: "flag" | "config" | "default";
174
+ /** The lexicons `chant.config.ts` configures. */
175
+ configured: string[];
176
+ /** The config file's name, for messages about `run.on`. */
177
+ configFile: string;
178
+ }
179
+
180
+ /**
181
+ * The runtime name `--on`, then `run.on` in `chant.config.ts` (#2523), then
182
+ * the built-in default pick, without loading any lexicon.
183
+ *
184
+ * Reads the configured list straight from `chant.config.ts` rather than
185
+ * through `resolveProjectLexicons`: `--on` names a *configured* lexicon, and
186
+ * that helper's fallback is a source scan of the whole project, which is a
187
+ * long wait to be told a name is wrong.
188
+ *
189
+ * A config that fails to load leaves the flag's choice alone, as before. With
190
+ * no flag, a config whose `run` block is invalid is refused (printed, then
191
+ * `undefined`): running the Op locally would hide that the project asked for
192
+ * another runtime. Any other load failure falls back to the built-in runtime,
193
+ * which is what a project with no `run.on` got before. `quiet` skips printing
194
+ * that refusal, for a caller that only peeks at the choice and leaves the
195
+ * reporting to {@link resolveOpRuntime}.
196
+ */
197
+ async function chooseOpRuntime(ctx: CommandContext, quiet = false): Promise<OpRuntimeChoice | undefined> {
198
+ const flag = ctx.args.on;
199
+ if (flag === "local") return { on: "local", source: "flag", configured: [], configFile: "chant.config.ts" };
200
+
201
+ let configured: string[] = [];
202
+ let configuredOn: string | undefined;
203
+ let configFile = "chant.config.ts";
204
+ try {
205
+ const { config, configPath } = await loadChantConfig(resolve("."));
206
+ configured = lexiconNames(config.lexicons ?? []);
207
+ configuredOn = config.run?.on;
208
+ if (configPath) configFile = basename(configPath);
209
+ } catch (err) {
210
+ if (!flag && err instanceof InvalidChantConfigError && err.key === "run") {
211
+ if (quiet) return undefined;
212
+ console.error(formatError({
213
+ message: err.message,
214
+ hint: "`run.on` names the runtime that hosts this project's Op runs: a configured lexicon with an opRuntime, or \"local\". Fix it, or pass --on to pick the runtime for this run.",
215
+ }));
216
+ return undefined;
217
+ }
218
+ // No/unreadable chant.config.ts: an `--on` error says so by listing nothing.
219
+ }
220
+
221
+ if (flag) return { on: flag, source: "flag", configured, configFile };
222
+ if (configuredOn) return { on: configuredOn, source: "config", configured, configFile };
223
+ return { on: undefined, source: "default", configured, configFile };
224
+ }
225
+
168
226
  /** An ISO-8601 instant trimmed to what a table cell has room for. */
169
227
  function shortInstant(iso: string | undefined): string {
170
228
  return iso ? iso.slice(0, 19).replace("T", " ") : "—";
@@ -395,6 +453,8 @@ export async function runOpApprove(ctx: CommandContext): Promise<number> {
395
453
  note: ctx.args.note,
396
454
  url: ctx.args.url,
397
455
  plan: ctx.args.plan,
456
+ ...(ctx.args.sign !== undefined ? { sign: ctx.args.sign } : {}),
457
+ ...(ctx.args.relayedBy !== undefined ? { relayedBy: ctx.args.relayedBy } : {}),
398
458
  });
399
459
  if (!outcome.ok) return 1;
400
460
 
@@ -582,7 +642,9 @@ async function stewardTurnGate(opName: string, ctx: CommandContext): Promise<Ste
582
642
  const form = stewardFormFor(owner, env);
583
643
 
584
644
  if (form === "fountain") {
585
- if (ctx.args.on === "fountain") return { ok: true };
645
+ // `run.on: "fountain"` asks for the steward's thread as much as the flag
646
+ // does (#2523).
647
+ if ((await chooseOpRuntime(ctx, true))?.on === "fountain") return { ok: true };
586
648
  return {
587
649
  ok: false,
588
650
  message: `Op "${opName}" is one of steward "${owner.name}"'s Ops, which runs on fountain in environment "${env}"`,