@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,219 @@
1
+ /**
2
+ * #3163, ws-080: person-attributed records and gate approvals rest on a forge
3
+ * identity or a signer key, and a gate the declaration names passes only on a
4
+ * signed approval from its class.
5
+ */
6
+
7
+ import { readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { afterEach, describe, expect, test } from "vitest";
10
+ import { parseDeclaration, type Declaration } from "./declaration";
11
+ import { forgePrincipal, gateAdmissionFrom, identify, IdentityError, parseForgeIdentity, refuseUnidentified } from "./identity";
12
+ import { createClassRegistry, coreClassRegistry } from "./principal-classes";
13
+ import { reviewRecord } from "./records-write";
14
+ import { answerPoint } from "./decide";
15
+ import { gatesInLedger } from "./status-gates";
16
+ import { emptyPolicy, type TrustPolicy } from "./trust/policy";
17
+ import { sealGateApproval } from "./trust/seal";
18
+ import { hasSshKeygen, TestRepo, type Key } from "./trust/test-repo";
19
+ import { evaluateGate, memoryGateLedgerPort } from "../op/gate";
20
+ import type { GateResolutionRecord, PendingGateRecord } from "../lifecycle/gate-ledger";
21
+
22
+ const decl = (identity: unknown): Declaration =>
23
+ parseDeclaration(JSON.stringify({ name: "acme", schema: 1, members: [], identity }), "chant.workspace.json", "0.102.0");
24
+
25
+ const policyWith = (signers: { principal: string; key: string }[], roles: Record<string, string[]> = {}): TrustPolicy => ({
26
+ ...emptyPolicy("0".repeat(40)),
27
+ active: true,
28
+ signers: signers.map((s, i) => ({ ...s, line: i + 1 })),
29
+ roles,
30
+ });
31
+
32
+ const repos: TestRepo[] = [];
33
+ afterEach(() => {
34
+ while (repos.length) repos.pop()!.cleanup();
35
+ });
36
+
37
+ describe("forge identities", () => {
38
+ test("github and gitlab name their own host; forgejo and gitea name one", () => {
39
+ expect(parseForgeIdentity("github:Alice")).toEqual({ forge: "github", host: "github.com", login: "alice" });
40
+ expect(parseForgeIdentity("gitlab:a.b_c")).toEqual({ forge: "gitlab", host: "gitlab.com", login: "a.b_c" });
41
+ expect(parseForgeIdentity("forgejo@codeberg.org:bob")).toEqual({ forge: "forgejo", host: "codeberg.org", login: "bob" });
42
+ expect(parseForgeIdentity("github@ghe.example.com:carol")).toEqual({ forge: "github", host: "ghe.example.com", login: "carol" });
43
+ expect(parseForgeIdentity("forgejo:bob")).toBeNull();
44
+ expect(parseForgeIdentity("alice")).toBeNull();
45
+ expect(parseForgeIdentity("alice@example.com")).toBeNull();
46
+ expect(parseForgeIdentity("github:")).toBeNull();
47
+ expect(parseForgeIdentity("bitbucket:alice")).toBeNull();
48
+ expect(forgePrincipal({ forge: "github", host: "github.com", login: "alice" })).toBe("github:alice");
49
+ expect(forgePrincipal({ forge: "forgejo", host: "codeberg.org", login: "bob" })).toBe("forgejo@codeberg.org:bob");
50
+ });
51
+
52
+ test("a principal is a signer, a forge identity, a role holder or a name", () => {
53
+ const policy = policyWith([{ principal: "github:alice", key: "ssh-ed25519 AAAA" }, { principal: "dana@example.test", key: "ssh-ed25519 BBBB" }], { runner: ["ci-bot"] });
54
+ expect(identify("GitHub:Alice", policy).form).toBe("signer");
55
+ expect(identify("dana@example.test", policy).form).toBe("signer");
56
+ expect(identify("github:bob", policy).form).toBe("forge");
57
+ expect(identify("ci-bot", policy).form).toBe("role");
58
+ expect(identify("alex", policy).form).toBe("name");
59
+ const d = parseDeclaration(
60
+ JSON.stringify({ name: "acme", schema: 1, members: [{ name: "app", dir: "app", kind: "chant" }], agents: [{ name: "builder", member: "app", principals: ["builder-bot"] }] }),
61
+ "chant.workspace.json",
62
+ "0.102.0",
63
+ );
64
+ expect(identify("builder-bot", emptyPolicy(null), d).form).toBe("role");
65
+ });
66
+ });
67
+
68
+ describe("identity.attribution", () => {
69
+ test("parses, and defaults to any", () => {
70
+ expect(decl({}).identity).toEqual({ attribution: "any", gates: {} });
71
+ expect(decl({ attribution: "identified", gates: { ship: { class: "operator" }, rollback: {} } }).identity).toEqual({
72
+ attribution: "identified",
73
+ gates: {
74
+ ship: { gate: "ship", class: "operator", pointer: "/identity/gates/ship" },
75
+ rollback: { gate: "rollback", class: null, pointer: "/identity/gates/rollback" },
76
+ },
77
+ });
78
+ expect(() => decl({ attribution: "verified" })).toThrow();
79
+ expect(() => decl({ gates: { ship: { by: "x" } } })).toThrow();
80
+ });
81
+
82
+ test("identified refuses a bare name and takes a forge identity or a signer", () => {
83
+ const source = { declaration: decl({ attribution: "identified" }), policy: policyWith([{ principal: "dana@example.test", key: "ssh-ed25519 AAAA" }]) };
84
+ expect(() => refuseUnidentified(source, ["github:alice", "dana@example.test"], "--by")).not.toThrow();
85
+ expect(() => refuseUnidentified(source, ["github:alice", "alex"], "--by")).toThrow(IdentityError);
86
+ // any, or no identity block, keeps every name: hud's roster names still work there.
87
+ expect(() => refuseUnidentified({ ...source, declaration: decl({}) }, ["alex"], "--by")).not.toThrow();
88
+ expect(() => refuseUnidentified({ ...source, declaration: null }, ["alex"], "--by")).not.toThrow();
89
+ });
90
+
91
+ test.skipIf(!hasSshKeygen)("records review and points answer refuse a roster name under identified at base", async () => {
92
+ const r = new TestRepo("identity-review");
93
+ repos.push(r);
94
+ const DECISIONS = join(import.meta.dirname, "..", "..", "..", "..", "docs", "design", "decisions");
95
+ r.write("decisions/decision.kind.mjs", readFileSync(join(DECISIONS, "decision.kind.mjs"), "utf-8"));
96
+ r.write("decisions/decision.schema.json", readFileSync(join(DECISIONS, "decision.schema.json"), "utf-8"));
97
+ r.write("decisions/ws-003-seal-scope.md", readFileSync(join(DECISIONS, "ws-003-seal-scope.md"), "utf-8"));
98
+ r.write("chant.workspace.json", JSON.stringify({ name: "acme", schema: 1, members: [], identity: { attribution: "identified" } }));
99
+ r.commit("base");
100
+ r.git(["checkout", "-q", "-b", "change"]);
101
+ const kind = "decisions/decision.kind.mjs";
102
+ const refused = await reviewRecord({ kind, id: "ws-003", verdict: "agree", by: "alex", cwd: r.dir, on: "2026-10-03", dryRun: true });
103
+ expect("error" in refused && refused.error.code).toBe("principal-unidentified");
104
+ const taken = await reviewRecord({ kind, id: "ws-003", verdict: "agree", by: "github:alex", cwd: r.dir, on: "2026-10-03", dryRun: true });
105
+ expect("error" in taken ? taken.error : null).toBeNull();
106
+ const answer = await answerPoint({ id: "P-1", answer: "yes", by: ["alex"], cwd: r.dir });
107
+ expect("error" in answer && answer.error.code).toBe("principal-unidentified");
108
+ });
109
+ });
110
+
111
+ describe.skipIf(!hasSshKeygen)("identity.gates", () => {
112
+ function keys(): { r: TestRepo; alice: Key; bob: Key; mallory: Key } {
113
+ const r = new TestRepo("identity-gates");
114
+ repos.push(r);
115
+ return { r, alice: r.key("alice"), bob: r.key("bob"), mallory: r.key("mallory") };
116
+ }
117
+
118
+ const approval = (resolvedBy: string, extra: Partial<GateResolutionRecord> = {}): GateResolutionRecord => ({
119
+ version: 1,
120
+ op: "web",
121
+ gate: "ship",
122
+ environment: "prod",
123
+ planDigest: "sha256:" + "a".repeat(64),
124
+ resolvedBy,
125
+ timestamp: "2026-10-03T12:00:00.000Z",
126
+ ...extra,
127
+ });
128
+ const signed = (key: Key, a: GateResolutionRecord): GateResolutionRecord => ({ ...a, seal: sealGateApproval(key.file, a) });
129
+
130
+ test("counts only an approval sealed by a listed signer in the class", () => {
131
+ const { alice, bob, mallory } = keys();
132
+ const policy = policyWith(
133
+ [
134
+ { principal: "github:alice", key: alice.pub },
135
+ { principal: "github:bob", key: bob.pub },
136
+ ],
137
+ { operator: ["github:alice"] },
138
+ );
139
+ const classes = createClassRegistry([{ name: "operator", description: "operators", role: "operator", source: "plugins/ops" }]);
140
+ const rule = gateAdmissionFrom({ declaration: decl({ gates: { ship: { class: "operator" } } }), policy, classes }, "ship")!;
141
+ expect(rule.requirement.class).toBe("operator");
142
+ expect(gateAdmissionFrom({ declaration: decl({ gates: { ship: {} } }), policy, classes }, "rollout")).toBeNull();
143
+
144
+ expect(rule.refuses(signed(alice, approval("github:alice")))).toBeNull();
145
+ // A hud roster name or an unsigned forge identity can't clear it.
146
+ expect(rule.refuses(approval("alex"))).toMatch(/not signed/);
147
+ expect(rule.refuses(approval("github:alice"))).toMatch(/not signed/);
148
+ // Signed by a listed signer outside the class.
149
+ expect(rule.refuses(signed(bob, approval("github:bob")))).toMatch(/not in the class operator/);
150
+ // Someone else's key under alice's name.
151
+ expect(rule.refuses(signed(mallory, approval("github:alice")))).toMatch(/does not verify/);
152
+ // A seal over another plan doesn't carry over.
153
+ const moved = { ...signed(alice, approval("github:alice")), planDigest: "sha256:" + "b".repeat(64) };
154
+ expect(rule.refuses(moved)).toMatch(/does not verify/);
155
+
156
+ // Any listed signer, when the rule names no class.
157
+ const anySigner = gateAdmissionFrom({ declaration: decl({ gates: { ship: {} } }), policy, classes }, "ship")!;
158
+ expect(anySigner.refuses(signed(bob, approval("github:bob")))).toBeNull();
159
+ // A class no pinned package supplies lets nothing through.
160
+ const unknown = gateAdmissionFrom({ declaration: decl({ gates: { ship: { class: "operator" } } }), policy, classes: coreClassRegistry() }, "ship")!;
161
+ expect(unknown.refuses(signed(alice, approval("github:alice")))).toMatch(/no pinned package supplies/);
162
+ });
163
+
164
+ test("a relayed approval: the seal covers relayedBy, and status lists it (#3402)", () => {
165
+ const { alice } = keys();
166
+ const policy = policyWith([{ principal: "github:alice", key: alice.pub }]);
167
+ const rule = gateAdmissionFrom({ declaration: decl({ gates: { ship: {} } }), policy, classes: coreClassRegistry() }, "ship")!;
168
+ const relayed = signed(alice, approval("github:alice", { relayedBy: "github:hud-follower" }));
169
+ expect(rule.refuses(relayed)).toBeNull();
170
+ // The relay can't be changed, dropped or added after sealing.
171
+ expect(rule.refuses({ ...relayed, relayedBy: "github:mallory" })).toMatch(/does not verify/);
172
+ const { relayedBy: _dropped, ...unrelayed } = relayed;
173
+ expect(rule.refuses(unrelayed)).toMatch(/does not verify/);
174
+ expect(rule.refuses({ ...signed(alice, approval("github:alice")), relayedBy: "github:hud-follower" })).toMatch(/does not verify/);
175
+ // A seal made before #3402, with no relay, still verifies.
176
+ expect(rule.refuses(signed(alice, approval("github:alice")))).toBeNull();
177
+
178
+ const pending: PendingGateRecord = { version: 1, kind: "pending", op: "web", gate: "ship", environment: "prod", planDigest: "sha256:" + "a".repeat(64), timestamp: "2026-10-03T11:00:00.000Z", expiresAt: "2026-10-10T11:00:00.000Z" };
179
+ const ledger = [pending, relayed, approval("bob")].map((l) => JSON.stringify(l)).join("\n");
180
+ const gate = gatesInLedger("web", ledger, ["prod"], "2026-10-03T13:00:00.000Z").gates[0];
181
+ expect(gate.approvals).toEqual([
182
+ { principal: "github:alice", channel: null, relayedBy: "github:hud-follower", at: "2026-10-03T12:00:00.000Z" },
183
+ { principal: "bob", channel: null, relayedBy: null, at: "2026-10-03T12:00:00.000Z" },
184
+ ]);
185
+ });
186
+
187
+ test("a run and workspace status leave out approvals the rule refuses", async () => {
188
+ const { alice } = keys();
189
+ const policy = policyWith([{ principal: "github:alice", key: alice.pub }]);
190
+ const rule = gateAdmissionFrom({ declaration: decl({ gates: { ship: {} } }), policy, classes: coreClassRegistry() }, "ship")!;
191
+ const pending: PendingGateRecord = {
192
+ version: 1,
193
+ kind: "pending",
194
+ op: "web",
195
+ gate: "ship",
196
+ environment: "prod",
197
+ planDigest: "sha256:" + "a".repeat(64),
198
+ timestamp: "2026-10-03T11:00:00.000Z",
199
+ expiresAt: "2026-10-10T11:00:00.000Z",
200
+ };
201
+ const input = { op: "web", gate: "ship", environment: "prod", planDigest: pending.planDigest, now: "2026-10-03T13:00:00.000Z" };
202
+
203
+ const roster = memoryGateLedgerPort({ pending: [pending], resolutions: [approval("alex")] });
204
+ expect((await evaluateGate(roster, input)).satisfied).toBe(true);
205
+ expect((await evaluateGate({ ...roster, approvalRule: async () => rule }, input)).satisfied).toBe(false);
206
+ const sealed = memoryGateLedgerPort({ pending: [pending], resolutions: [approval("alex"), signed(alice, approval("github:alice"))] });
207
+ const check = await evaluateGate({ ...sealed, approvalRule: async () => rule }, input);
208
+ expect(check.satisfied && check.resolution.resolvedBy).toBe("github:alice");
209
+
210
+ const ledger = [pending, approval("alex")].map((l) => JSON.stringify(l)).join("\n");
211
+ const open = gatesInLedger("web", ledger, ["prod"], "2026-10-03T13:00:00.000Z", (g) => (g === "ship" ? rule : null)).gates[0];
212
+ expect(open.state).toBe("pending");
213
+ expect(open.signed).toEqual({ class: null });
214
+ expect(open.approve).toMatch(/--sign$/);
215
+ const plain = gatesInLedger("web", ledger, ["prod"], "2026-10-03T13:00:00.000Z").gates[0];
216
+ expect(plain.state).toBe("approved");
217
+ expect(plain.signed).toBeNull();
218
+ });
219
+ });
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Who a person-attributed record or gate approval names (#3163, ws-080).
3
+ *
4
+ * chant never authenticates a person (ws-052): hud, studio or behold signs a
5
+ * person in and maps the session to one of the identities below, then passes
6
+ * it to chant's write commands (`--by`, `--actor`). chant records what it is
7
+ * given and says which form it is:
8
+ *
9
+ * - `signer`: a principal `.chant/allowed_signers` lists at base. A seal made
10
+ * with that principal's key (`--sign`) attests it.
11
+ * - `forge`: a forge identity, `github:<login>`, `gitlab:<login>`, or
12
+ * `<forge>@<host>:<login>` (forgejo, gitea, or a self-hosted github or
13
+ * gitlab). The surface that signed the person in vouches for it; nothing
14
+ * here checks it, and only a seal verified against the signers at base
15
+ * attests it. The signers file and the role grants name people this way, so
16
+ * one string is the person in the record, the key list and the classes.
17
+ * - `role`: a principal holding the agent, runner or service role at base, or
18
+ * listed by a declared agent session: not a person, and named by a grant an
19
+ * admin controls.
20
+ * - `name`: anything else, such as a hud roster name or `$USER`.
21
+ *
22
+ * The declaration's `identity` block, read at base, turns this into rules:
23
+ * `attribution: "identified"` refuses a `name` on every person-attributed
24
+ * write, and `gates.<gate>` lets a gate of that name pass only on an approval
25
+ * sealed by a signer, from a class when it names one.
26
+ */
27
+
28
+ import type { Declaration, SignedGate } from "./declaration";
29
+ import { classesOf, coreClassRegistry, principalClass, type ClassRegistry } from "./principal-classes";
30
+ import type { ReasonCode } from "./reason-codes";
31
+ import { normalisePrincipal } from "./records";
32
+ import type { TrustPolicy } from "./trust/policy";
33
+ import { checkGateSeal, type SealedGateApproval } from "./trust/seal";
34
+ import { scopeSource } from "./write-scope";
35
+
36
+ /** The forges a forge identity can name. */
37
+ export const FORGES = ["github", "gitlab", "forgejo", "gitea"] as const;
38
+ export type Forge = (typeof FORGES)[number];
39
+
40
+ /** The host a forge identity means when it names none. Forgejo and gitea have no default: name the host. */
41
+ const DEFAULT_HOST: Record<Forge, string | null> = { github: "github.com", gitlab: "gitlab.com", forgejo: null, gitea: null };
42
+
43
+ /** A person's account on a forge. */
44
+ export interface ForgeIdentity {
45
+ forge: Forge;
46
+ /** Lower-cased, such as `github.com` or `codeberg.org`. */
47
+ host: string;
48
+ /** Lower-cased: the forges compare logins without case. */
49
+ login: string;
50
+ }
51
+
52
+ const LABEL = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
53
+ const FORGE_PRINCIPAL = new RegExp(`^(${FORGES.join("|")})(?:@(${LABEL}(?:\\.${LABEL})+))?:([a-z0-9](?:[a-z0-9._-]{0,98}[a-z0-9_])?)$`);
54
+
55
+ /**
56
+ * Read `principal` as a forge identity, or null when it is not one. Case and
57
+ * surrounding space are folded as {@link normalisePrincipal} folds them.
58
+ */
59
+ export function parseForgeIdentity(principal: string): ForgeIdentity | null {
60
+ const m = FORGE_PRINCIPAL.exec(normalisePrincipal(principal));
61
+ if (!m) return null;
62
+ const forge = m[1] as Forge;
63
+ const host = m[2] ?? DEFAULT_HOST[forge];
64
+ if (host === null) return null;
65
+ return { forge, host, login: m[3] };
66
+ }
67
+
68
+ /** The principal string of a forge identity: `<forge>:<login>` on the forge's default host, else `<forge>@<host>:<login>`. */
69
+ export function forgePrincipal(id: ForgeIdentity): string {
70
+ return id.host === DEFAULT_HOST[id.forge] ? `${id.forge}:${id.login}` : `${id.forge}@${id.host}:${id.login}`;
71
+ }
72
+
73
+ export type IdentityForm = "signer" | "forge" | "role" | "name";
74
+
75
+ export interface Identified {
76
+ principal: string;
77
+ form: IdentityForm;
78
+ /** Set whenever the principal reads as a forge identity, whatever its form. */
79
+ forge: ForgeIdentity | null;
80
+ }
81
+
82
+ const NON_PERSON_CLASSES = new Set(["agent", "runner", "service"]);
83
+
84
+ /**
85
+ * What `principal` is, under the policy and declaration read at base. A
86
+ * principal the signers file lists is a `signer` even when it is also a
87
+ * forge identity, since a seal can attest it.
88
+ */
89
+ export function identify(principal: string, policy: TrustPolicy, declaration: Declaration | null = null): Identified {
90
+ const name = normalisePrincipal(principal);
91
+ const forge = parseForgeIdentity(principal);
92
+ if (policy.active && policy.signers.some((s) => normalisePrincipal(s.principal) === name)) return { principal, form: "signer", forge };
93
+ if (forge) return { principal, form: "forge", forge };
94
+ const session = (declaration?.agents ?? []).some((a) => a.principals.some((p) => normalisePrincipal(p) === name));
95
+ if (session || classesOf(coreClassRegistry(), policy, principal).some((c) => NON_PERSON_CLASSES.has(c))) return { principal, form: "role", forge: null };
96
+ return { principal, form: "name", forge: null };
97
+ }
98
+
99
+ /** Why a write naming a person was refused. Closed. */
100
+ export const IDENTITY_CODES = ["principal-unidentified"] as const satisfies readonly ReasonCode[];
101
+ export type IdentityCode = (typeof IDENTITY_CODES)[number];
102
+
103
+ export class IdentityError extends Error {
104
+ readonly code: IdentityCode = "principal-unidentified";
105
+ constructor(message: string) {
106
+ super(message);
107
+ this.name = "IdentityError";
108
+ }
109
+ }
110
+
111
+ /** What {@link refuseUnidentified} reads: the declaration and policy at base, as `scopeSource` gives them. */
112
+ export interface IdentitySource {
113
+ declaration: Declaration | null;
114
+ policy: TrustPolicy;
115
+ }
116
+
117
+ /**
118
+ * Refuse a person-attributed write that names someone by a bare name, when
119
+ * the declaration at base sets `identity.attribution` to `identified`.
120
+ * `flag` names where the name came from (`--by`, `--actor`). A write in a
121
+ * declared agent session (`CHANT_AGENT`) names the session, not a person,
122
+ * and is not judged here. Throws an {@link IdentityError}.
123
+ */
124
+ export function refuseUnidentified(source: IdentitySource, names: readonly string[], flag: string, opts: { agent?: string | null } = {}): void {
125
+ if (source.declaration?.identity?.attribution !== "identified") return;
126
+ if (opts.agent !== undefined && opts.agent !== null && source.declaration.agents.some((a) => a.name === opts.agent)) return;
127
+ for (const name of names) {
128
+ if (identify(name, source.policy, source.declaration).form !== "name") continue;
129
+ throw new IdentityError(
130
+ `${flag} ${JSON.stringify(name)} names no identity the workspace can check: chant.workspace.json at base sets identity.attribution to identified, so a person is named by a forge identity (github:<login>, gitlab:<login>, or <forge>@<host>:<login>) or by a principal ${source.policy.signersPath} lists at base`,
131
+ );
132
+ }
133
+ }
134
+
135
+ /** A gate approval as the rule judges it: the resolution line's own fields. */
136
+ export type GateApprovalLike = SealedGateApproval;
137
+
138
+ /** A gate the declaration names in `identity.gates`, and the judge for its approvals. */
139
+ export interface GateAdmission {
140
+ requirement: SignedGate;
141
+ /** Why `approval` doesn't count toward the gate, or null when it does. */
142
+ refuses(approval: GateApprovalLike): string | null;
143
+ }
144
+
145
+ /** What {@link gateAdmissionFrom} reads: the declaration, policy and classes at base, as `scopeSource` gives them. */
146
+ export interface GateRuleSource extends IdentitySource {
147
+ classes: ClassRegistry;
148
+ }
149
+
150
+ /**
151
+ * The rule for `gate`, or null when the declaration at base names none. An
152
+ * approval counts only when its seal verifies for its approver against the
153
+ * signers at base and, when the rule names a class, the approver's role
154
+ * grants at base put it in that class. A class no pinned package supplies
155
+ * lets nothing through.
156
+ */
157
+ export function gateAdmissionFrom(source: GateRuleSource, gate: string): GateAdmission | null {
158
+ const requirement = source.declaration?.identity?.gates[gate];
159
+ if (!requirement) return null;
160
+ const { policy, classes } = source;
161
+ return {
162
+ requirement,
163
+ refuses(a) {
164
+ const want = requirement.class;
165
+ if (want !== null && classes.get(want) === undefined) {
166
+ return `identity.gates.${gate} names the class ${want}, which no pinned package supplies, so no approval can show it is in that class (known classes: ${classes.names().join(", ")})`;
167
+ }
168
+ if (!policy.active) return `gate ${gate} needs a signed approval, and there is no signers file (${policy.signersPath}) at base to check one against`;
169
+ const seal = checkGateSeal(policy, a);
170
+ if (seal.attested !== true) return a.seal === undefined || a.seal === null ? `the approval by ${a.resolvedBy} is not signed; gate ${gate} needs chant approve --sign` : seal.message;
171
+ if (want === null) return null;
172
+ const inClass = want === "human" ? principalClass(policy, a.resolvedBy, classes) === "human" : classesOf(classes, policy, a.resolvedBy).includes(want);
173
+ return inClass ? null : `${a.resolvedBy} is not in the class ${want} that gate ${gate} needs: no role grant at base puts them there`;
174
+ },
175
+ };
176
+ }
177
+
178
+ /**
179
+ * The rule for `gate` in the workspace holding `cwd`, read at base (the
180
+ * target branch tip), or null when there is no declaration or it names none.
181
+ * What a run, `chant approve` and `workspace status` ask before counting an
182
+ * approval.
183
+ */
184
+ export function gateAdmission(cwd: string, gate: string): GateAdmission | null {
185
+ return gateAdmissionFrom(scopeSource(cwd), gate);
186
+ }
@@ -21,10 +21,18 @@
21
21
  * never written.
22
22
  *
23
23
  * Nothing here runs project code: it reads file names and package.json files.
24
+ *
25
+ * `--profile ideation|app|infra` starts a workspace from one of the reference
26
+ * workspace's profiles instead (#3174, ws-096): records only with a stub app,
27
+ * an app with its factory, or an estate with a factory and no app. It is
28
+ * `chant init --from` on `reference-workspace/profiles/<profile>` of the chant
29
+ * repository at this chant's release tag, or of the repository or directory
30
+ * `--from` names, so the new workspace gets a lineage lock and can be upgraded
31
+ * like any template copy.
24
32
  */
25
33
 
26
34
  import { execFileSync } from "node:child_process";
27
- import { existsSync, readdirSync, writeFileSync } from "node:fs";
35
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
28
36
  import { basename, join, resolve } from "node:path";
29
37
  import { formatError, formatSuccess } from "../cli/format";
30
38
  import type { CommandContext } from "../cli/registry";
@@ -36,12 +44,34 @@ import {
36
44
  rootExclusions,
37
45
  WorkspaceReadError,
38
46
  isInside,
47
+ readerVersion,
39
48
  } from "./declaration";
40
49
  import { expandGlob } from "./glob";
50
+ import { setProperty } from "./json-edit";
41
51
  import { holdsChantProject } from "./kinds";
42
52
  import { gitTop, skippedDir, workingTree, type WorkspaceTree } from "./tree";
43
53
 
44
- const USAGE = "chant workspace init [dir] [--name <name>] [--yes] [--verbose]";
54
+ const USAGE = "chant workspace init [dir] [--name <name>] [--yes] [--verbose]\n chant workspace init --profile ideation|app|infra [dir] [--name <name>] [--param name=<display name>] [--from <repo>@<ref>|<chant checkout>] [--yes]";
55
+
56
+ /** The profiles `--profile` takes (#3174), each a directory under {@link PROFILES_DIR} in the chant repository. */
57
+ export const PROFILES = ["ideation", "app", "infra"] as const;
58
+ export type Profile = (typeof PROFILES)[number];
59
+
60
+ /** Where the profiles live in the chant repository. */
61
+ export const PROFILES_DIR = "reference-workspace/profiles";
62
+
63
+ /** The repository the profiles are read from by default, at this chant's release tag. */
64
+ export const PROFILES_REPO = "https://github.com/INTENTIUS/chant";
65
+
66
+ /**
67
+ * The `chant init --from` source for a profile: `from` (a `<repo>@<ref>` or
68
+ * a directory holding a chant checkout) when given, else the chant repository
69
+ * at the tag of the chant reading, `chant-v<version>`.
70
+ */
71
+ export function profileSource(profile: Profile, from: string | undefined, version: string): string {
72
+ const base = from ?? `${PROFILES_REPO}@chant-v${version}`;
73
+ return `${base}#${PROFILES_DIR}/${profile}`;
74
+ }
45
75
 
46
76
  /** Directory names whose children are examples or test fixtures, not members. */
47
77
  const EXAMPLE_DIRS = new Map<string, "examples" | "fixtures">([
@@ -544,6 +574,8 @@ export async function runWorkspaceInit(ctx: CommandContext): Promise<number> {
544
574
  return 1;
545
575
  }
546
576
 
577
+ if (args.profile !== undefined) return initProfile(args, root);
578
+
547
579
  let proposal: Proposal;
548
580
  try {
549
581
  proposal = proposeWorkspace(root, { name: args.selectName });
@@ -583,3 +615,51 @@ export async function runWorkspaceInit(ctx: CommandContext): Promise<number> {
583
615
  console.log(formatSuccess(`Wrote ${target}. chant workspace ls lists what it declares.`));
584
616
  return 0;
585
617
  }
618
+
619
+ /** `chant workspace init --profile <profile>` (#3174): copy a profile with `chant init --from`, then name the workspace. */
620
+ async function initProfile(args: CommandContext["args"], root: string): Promise<number> {
621
+ const profile = args.profile as Profile;
622
+ if (!(PROFILES as readonly string[]).includes(profile)) {
623
+ console.error(formatError({ message: `--profile ${JSON.stringify(args.profile)} is not a profile; the profiles are ${PROFILES.join(", ")}`, hint: USAGE }));
624
+ return 1;
625
+ }
626
+ const { parseParamArgs } = await import("./template-manifest");
627
+ let params: Record<string, string>;
628
+ try {
629
+ params = parseParamArgs(args.param ?? []);
630
+ } catch (err) {
631
+ console.error(formatError({ message: (err as Error).message, hint: USAGE }));
632
+ return 1;
633
+ }
634
+ const from = profileSource(profile, args.migrateFrom, readerVersion());
635
+ console.log(`chant workspace init --profile ${profile} copies ${from} into ${root}, as chant init --from would, with a lineage lock.`);
636
+ if (args.selectName !== undefined) console.log(`The workspace is named ${args.selectName}.`);
637
+ console.log("");
638
+ let write = !!args.yes;
639
+ if (!write) {
640
+ if (!process.stdin.isTTY) {
641
+ console.log("Nothing written. Re-run with --yes to write it.");
642
+ return 0;
643
+ }
644
+ write = await confirm(`Make the ${profile} workspace? [y/N] `);
645
+ }
646
+ if (!write) {
647
+ console.log("Nothing written.");
648
+ return 0;
649
+ }
650
+ const { initFromCommand } = await import("./lineage-init");
651
+ const result = await initFromCommand({ from, path: root, params, force: args.force });
652
+ if (!result.success) {
653
+ console.error(formatError({ message: result.error ?? `the ${profile} profile could not be copied`, hint: USAGE }));
654
+ return 1;
655
+ }
656
+ if (args.selectName !== undefined) {
657
+ const file = join(root, "chant.workspace.json");
658
+ writeFileSync(file, setProperty(readFileSync(file, "utf-8"), false, "", "name", args.selectName));
659
+ }
660
+ console.log(formatSuccess(`Made a ${profile} workspace in ${root}:`));
661
+ for (const f of result.createdFiles) console.log(` ${f}`);
662
+ console.log("");
663
+ console.log("chant workspace check checks it, and chant workspace upgrade takes a later version of the profile.");
664
+ return 0;
665
+ }