@intentius/chant 0.90.0 → 0.93.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 (402) hide show
  1. package/dist/cli/commands/build.d.ts.map +1 -1
  2. package/dist/cli/commands/lint.d.ts.map +1 -1
  3. package/dist/cli/handlers/components.d.ts +8 -0
  4. package/dist/cli/handlers/components.d.ts.map +1 -1
  5. package/dist/cli/handlers/graph.d.ts.map +1 -1
  6. package/dist/cli/handlers/operator.d.ts +20 -0
  7. package/dist/cli/handlers/operator.d.ts.map +1 -1
  8. package/dist/cli/handlers/run.d.ts.map +1 -1
  9. package/dist/cli/main.d.ts.map +1 -1
  10. package/dist/cli/mcp/workspace-tools.d.ts +7 -4
  11. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  12. package/dist/cli/plugins.d.ts.map +1 -1
  13. package/dist/cli/registry.d.ts +42 -1
  14. package/dist/cli/registry.d.ts.map +1 -1
  15. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  16. package/dist/components/verbs/vuln-scan.d.ts +72 -0
  17. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  18. package/dist/config.d.ts +22 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/lexicon-module.d.ts +22 -0
  21. package/dist/lexicon-module.d.ts.map +1 -1
  22. package/dist/lifecycle/converge-ledger.d.ts +19 -0
  23. package/dist/lifecycle/converge-ledger.d.ts.map +1 -1
  24. package/dist/lifecycle/git.d.ts +40 -5
  25. package/dist/lifecycle/git.d.ts.map +1 -1
  26. package/dist/lifecycle/lease.d.ts +72 -16
  27. package/dist/lifecycle/lease.d.ts.map +1 -1
  28. package/dist/lifecycle/member-ledger.d.ts +3 -2
  29. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  30. package/dist/lifecycle/plan-ledger.d.ts +114 -0
  31. package/dist/lifecycle/plan-ledger.d.ts.map +1 -0
  32. package/dist/lifecycle/run-ledger.d.ts +2 -0
  33. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  34. package/dist/lifecycle/symptoms.d.ts +51 -0
  35. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  36. package/dist/lifecycle/work-lease.d.ts +140 -0
  37. package/dist/lifecycle/work-lease.d.ts.map +1 -0
  38. package/dist/lint/rules/index.d.ts +4 -2
  39. package/dist/lint/rules/index.d.ts.map +1 -1
  40. package/dist/lint/rules/op/index.d.ts +14 -3
  41. package/dist/lint/rules/op/index.d.ts.map +1 -1
  42. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -1
  43. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts +29 -0
  44. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts.map +1 -0
  45. package/dist/lint/rules/sys001-no-literal-key.d.ts +3 -0
  46. package/dist/lint/rules/sys001-no-literal-key.d.ts.map +1 -0
  47. package/dist/op/__fixtures__/decide-stub-backend.d.ts +53 -0
  48. package/dist/op/__fixtures__/decide-stub-backend.d.ts.map +1 -0
  49. package/dist/op/activities/activity-contracts.d.ts +203 -2
  50. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  51. package/dist/op/activities/apply.d.ts.map +1 -1
  52. package/dist/op/activities/change-coverage.d.ts +44 -0
  53. package/dist/op/activities/change-coverage.d.ts.map +1 -0
  54. package/dist/op/activities/converge.d.ts +24 -1
  55. package/dist/op/activities/converge.d.ts.map +1 -1
  56. package/dist/op/activities/decide.d.ts +107 -0
  57. package/dist/op/activities/decide.d.ts.map +1 -0
  58. package/dist/op/activities/index.d.ts +10 -0
  59. package/dist/op/activities/index.d.ts.map +1 -1
  60. package/dist/op/activities/shell.d.ts +32 -0
  61. package/dist/op/activities/shell.d.ts.map +1 -1
  62. package/dist/op/activities/source-release.d.ts +86 -0
  63. package/dist/op/activities/source-release.d.ts.map +1 -0
  64. package/dist/op/activities/source-rollback.d.ts +100 -0
  65. package/dist/op/activities/source-rollback.d.ts.map +1 -0
  66. package/dist/op/activities/work-evidence.d.ts +42 -0
  67. package/dist/op/activities/work-evidence.d.ts.map +1 -0
  68. package/dist/op/activity-contract.d.ts +1 -0
  69. package/dist/op/activity-contract.d.ts.map +1 -1
  70. package/dist/op/activity-profiles.d.ts +16 -0
  71. package/dist/op/activity-profiles.d.ts.map +1 -1
  72. package/dist/op/builders.d.ts +84 -2
  73. package/dist/op/builders.d.ts.map +1 -1
  74. package/dist/op/composites/converge-op.d.ts +31 -4
  75. package/dist/op/composites/converge-op.d.ts.map +1 -1
  76. package/dist/op/decide-backend.d.ts +116 -0
  77. package/dist/op/decide-backend.d.ts.map +1 -0
  78. package/dist/op/decide-config.d.ts +120 -0
  79. package/dist/op/decide-config.d.ts.map +1 -0
  80. package/dist/op/decide-read-inputs.d.ts +40 -0
  81. package/dist/op/decide-read-inputs.d.ts.map +1 -0
  82. package/dist/op/discover.d.ts +25 -0
  83. package/dist/op/discover.d.ts.map +1 -1
  84. package/dist/op/gate-wait.d.ts +43 -0
  85. package/dist/op/gate-wait.d.ts.map +1 -0
  86. package/dist/op/gate.d.ts +5 -2
  87. package/dist/op/gate.d.ts.map +1 -1
  88. package/dist/op/index.d.ts +18 -5
  89. package/dist/op/index.d.ts.map +1 -1
  90. package/dist/op/lifecycle-receipt-store.d.ts +34 -0
  91. package/dist/op/lifecycle-receipt-store.d.ts.map +1 -0
  92. package/dist/op/local-executor.d.ts +48 -4
  93. package/dist/op/local-executor.d.ts.map +1 -1
  94. package/dist/op/local-output.d.ts +2 -0
  95. package/dist/op/local-output.d.ts.map +1 -1
  96. package/dist/op/op-ir.d.ts +12 -1
  97. package/dist/op/op-ir.d.ts.map +1 -1
  98. package/dist/op/op-verb-class.d.ts.map +1 -1
  99. package/dist/op/operator.d.ts +126 -1
  100. package/dist/op/operator.d.ts.map +1 -1
  101. package/dist/op/runtime.d.ts +46 -5
  102. package/dist/op/runtime.d.ts.map +1 -1
  103. package/dist/op/runtimes/local.d.ts.map +1 -1
  104. package/dist/op/source-archive.d.ts +63 -0
  105. package/dist/op/source-archive.d.ts.map +1 -0
  106. package/dist/op/step-output-ref.d.ts +2 -2
  107. package/dist/op/step-output-ref.d.ts.map +1 -1
  108. package/dist/op/steward-points.d.ts +136 -0
  109. package/dist/op/steward-points.d.ts.map +1 -0
  110. package/dist/op/steward-turn.d.ts +53 -0
  111. package/dist/op/steward-turn.d.ts.map +1 -0
  112. package/dist/op/steward.d.ts +161 -0
  113. package/dist/op/steward.d.ts.map +1 -0
  114. package/dist/op/types.d.ts +58 -0
  115. package/dist/op/types.d.ts.map +1 -1
  116. package/dist/op/work-lease-decl.d.ts +18 -0
  117. package/dist/op/work-lease-decl.d.ts.map +1 -0
  118. package/dist/op/work-lease-run.d.ts +173 -0
  119. package/dist/op/work-lease-run.d.ts.map +1 -0
  120. package/dist/workspace/__fixtures__/decide-workspace.d.ts +100 -0
  121. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -0
  122. package/dist/workspace/answers-ledger.d.ts +76 -0
  123. package/dist/workspace/answers-ledger.d.ts.map +1 -0
  124. package/dist/workspace/box-isolation.d.ts +99 -0
  125. package/dist/workspace/box-isolation.d.ts.map +1 -0
  126. package/dist/workspace/changes-cli.d.ts +16 -0
  127. package/dist/workspace/changes-cli.d.ts.map +1 -0
  128. package/dist/workspace/changes.d.ts +200 -0
  129. package/dist/workspace/changes.d.ts.map +1 -0
  130. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts +59 -0
  131. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts.map +1 -0
  132. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts +51 -0
  133. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts.map +1 -0
  134. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts +26 -0
  135. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts.map +1 -0
  136. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts +59 -0
  137. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts.map +1 -0
  138. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts +22 -0
  139. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts.map +1 -0
  140. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts +71 -0
  141. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -0
  142. package/dist/workspace/chant-migrations.d.ts +99 -0
  143. package/dist/workspace/chant-migrations.d.ts.map +1 -0
  144. package/dist/workspace/checks/box-isolation.d.ts +18 -0
  145. package/dist/workspace/checks/box-isolation.d.ts.map +1 -0
  146. package/dist/workspace/checks/boxes.d.ts +104 -0
  147. package/dist/workspace/checks/boxes.d.ts.map +1 -0
  148. package/dist/workspace/checks/diagrams.d.ts +31 -0
  149. package/dist/workspace/checks/diagrams.d.ts.map +1 -0
  150. package/dist/workspace/checks/records.d.ts +8 -0
  151. package/dist/workspace/checks/records.d.ts.map +1 -1
  152. package/dist/workspace/checks.d.ts +13 -1
  153. package/dist/workspace/checks.d.ts.map +1 -1
  154. package/dist/workspace/compose-graph.d.ts +2 -0
  155. package/dist/workspace/compose-graph.d.ts.map +1 -1
  156. package/dist/workspace/conformance/index.d.ts.map +1 -1
  157. package/dist/workspace/decide.d.ts +229 -0
  158. package/dist/workspace/decide.d.ts.map +1 -0
  159. package/dist/workspace/decision-points.schema.json +137 -0
  160. package/dist/workspace/declaration.d.ts +103 -0
  161. package/dist/workspace/declaration.d.ts.map +1 -1
  162. package/dist/workspace/declaration.schema.json +285 -0
  163. package/dist/workspace/declared-kinds.d.ts +32 -0
  164. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  165. package/dist/workspace/generated-files.d.ts +7 -0
  166. package/dist/workspace/generated-files.d.ts.map +1 -1
  167. package/dist/workspace/intent.d.ts.map +1 -1
  168. package/dist/workspace/lineage-check.d.ts +3 -0
  169. package/dist/workspace/lineage-check.d.ts.map +1 -1
  170. package/dist/workspace/lineage-upgrade.d.ts +6 -1
  171. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  172. package/dist/workspace/ls.d.ts +39 -1
  173. package/dist/workspace/ls.d.ts.map +1 -1
  174. package/dist/workspace/point-answer.schema.json +95 -0
  175. package/dist/workspace/points-cli.d.ts +113 -0
  176. package/dist/workspace/points-cli.d.ts.map +1 -0
  177. package/dist/workspace/points.d.ts +320 -0
  178. package/dist/workspace/points.d.ts.map +1 -0
  179. package/dist/workspace/reason-codes.d.ts +38 -0
  180. package/dist/workspace/reason-codes.d.ts.map +1 -1
  181. package/dist/workspace/record-assets.d.ts.map +1 -1
  182. package/dist/workspace/records-cli.d.ts +23 -1
  183. package/dist/workspace/records-cli.d.ts.map +1 -1
  184. package/dist/workspace/records-close.d.ts +1 -1
  185. package/dist/workspace/records-close.d.ts.map +1 -1
  186. package/dist/workspace/records-write.d.ts +11 -5
  187. package/dist/workspace/records-write.d.ts.map +1 -1
  188. package/dist/workspace/records.d.ts +42 -6
  189. package/dist/workspace/records.d.ts.map +1 -1
  190. package/dist/workspace/status-gates.d.ts +7 -2
  191. package/dist/workspace/status-gates.d.ts.map +1 -1
  192. package/dist/workspace/status-stewards.d.ts +179 -0
  193. package/dist/workspace/status-stewards.d.ts.map +1 -0
  194. package/dist/workspace/status.d.ts +68 -1
  195. package/dist/workspace/status.d.ts.map +1 -1
  196. package/dist/workspace/work-cli.d.ts +189 -0
  197. package/dist/workspace/work-cli.d.ts.map +1 -0
  198. package/dist/workspace/work-evidence.d.ts +74 -0
  199. package/dist/workspace/work-evidence.d.ts.map +1 -0
  200. package/dist/workspace/work.d.ts +43 -1
  201. package/dist/workspace/work.d.ts.map +1 -1
  202. package/package.json +1 -1
  203. package/src/cli/commands/audit.test.ts +9 -1
  204. package/src/cli/commands/build.ts +3 -2
  205. package/src/cli/commands/lint.ts +7 -1
  206. package/src/cli/handlers/components.test.ts +93 -0
  207. package/src/cli/handlers/components.ts +44 -3
  208. package/src/cli/handlers/graph.test.ts +20 -0
  209. package/src/cli/handlers/graph.ts +16 -2
  210. package/src/cli/handlers/operator.ts +141 -4
  211. package/src/cli/handlers/run.test.ts +173 -2
  212. package/src/cli/handlers/run.ts +174 -3
  213. package/src/cli/main.test.ts +50 -0
  214. package/src/cli/main.ts +97 -2
  215. package/src/cli/mcp/workspace-tools.test.ts +48 -19
  216. package/src/cli/mcp/workspace-tools.ts +110 -8
  217. package/src/cli/plugins.ts +11 -3
  218. package/src/cli/registry.ts +42 -1
  219. package/src/codegen/pinned-upgrade.ts +2 -1
  220. package/src/codegen/release-wiring.test.ts +49 -2
  221. package/src/components/capability-plugin-loader.ts +3 -3
  222. package/src/components/cli-support.ts +2 -2
  223. package/src/components/verbs/vuln-scan.test.ts +124 -1
  224. package/src/components/verbs/vuln-scan.ts +142 -1
  225. package/src/config.ts +11 -0
  226. package/src/lexicon-module.ts +56 -1
  227. package/src/lexicon-package.test.ts +96 -0
  228. package/src/lifecycle/converge-ledger.ts +20 -0
  229. package/src/lifecycle/git.ts +65 -15
  230. package/src/lifecycle/lease.test.ts +22 -0
  231. package/src/lifecycle/lease.ts +133 -29
  232. package/src/lifecycle/member-ledger.ts +3 -2
  233. package/src/lifecycle/plan-ledger.test.ts +148 -0
  234. package/src/lifecycle/plan-ledger.ts +158 -0
  235. package/src/lifecycle/run-ledger.ts +6 -0
  236. package/src/lifecycle/symptoms.ts +95 -0
  237. package/src/lifecycle/work-lease.test.ts +236 -0
  238. package/src/lifecycle/work-lease.ts +426 -0
  239. package/src/lint/rules/index.ts +6 -2
  240. package/src/lint/rules/op/index.ts +17 -4
  241. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +23 -1
  242. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +10 -6
  243. package/src/lint/rules/op/sys010-key-over-plain-http.test.ts +52 -0
  244. package/src/lint/rules/op/sys010-key-over-plain-http.ts +100 -0
  245. package/src/lint/rules/sys001-no-literal-key.test.ts +31 -0
  246. package/src/lint/rules/sys001-no-literal-key.ts +67 -0
  247. package/src/op/__fixtures__/decide-stub-backend.ts +143 -0
  248. package/src/op/activities/activity-contracts.ts +190 -1
  249. package/src/op/activities/apply.ts +7 -6
  250. package/src/op/activities/change-coverage.ts +60 -0
  251. package/src/op/activities/converge.test.ts +55 -1
  252. package/src/op/activities/converge.ts +208 -29
  253. package/src/op/activities/decide.live.test.ts +78 -0
  254. package/src/op/activities/decide.test.ts +300 -0
  255. package/src/op/activities/decide.ts +267 -0
  256. package/src/op/activities/index.ts +21 -0
  257. package/src/op/activities/shell.test.ts +91 -1
  258. package/src/op/activities/shell.ts +91 -2
  259. package/src/op/activities/source-release.test.ts +118 -0
  260. package/src/op/activities/source-release.ts +168 -0
  261. package/src/op/activities/source-rollback.test.ts +131 -0
  262. package/src/op/activities/source-rollback.ts +239 -0
  263. package/src/op/activities/work-evidence.ts +62 -0
  264. package/src/op/activity-contract-registry.test.ts +2 -0
  265. package/src/op/activity-contract-registry.ts +2 -2
  266. package/src/op/activity-contract.test.ts +12 -0
  267. package/src/op/activity-contract.ts +6 -1
  268. package/src/op/activity-profiles.ts +29 -0
  269. package/src/op/activity-registry.test.ts +1 -1
  270. package/src/op/activity-registry.ts +2 -2
  271. package/src/op/builders.ts +124 -5
  272. package/src/op/command-gate.test.ts +192 -0
  273. package/src/op/composites/converge-op.test.ts +27 -1
  274. package/src/op/composites/converge-op.ts +69 -15
  275. package/src/op/decide-backend.test.ts +44 -0
  276. package/src/op/decide-backend.ts +212 -0
  277. package/src/op/decide-config.test.ts +52 -0
  278. package/src/op/decide-config.ts +80 -0
  279. package/src/op/decide-read-inputs.ts +117 -0
  280. package/src/op/discover.ts +71 -0
  281. package/src/op/gate-approval.ts +2 -2
  282. package/src/op/gate-wait.ts +57 -0
  283. package/src/op/gate.ts +8 -3
  284. package/src/op/generate-pipeline.ts +2 -2
  285. package/src/op/index.ts +34 -6
  286. package/src/op/lifecycle-receipt-store.test.ts +60 -0
  287. package/src/op/lifecycle-receipt-store.ts +61 -0
  288. package/src/op/local-executor.ts +367 -33
  289. package/src/op/local-output.test.ts +33 -0
  290. package/src/op/local-output.ts +33 -2
  291. package/src/op/op-ir.test.ts +10 -0
  292. package/src/op/op-ir.ts +18 -0
  293. package/src/op/op-verb-class.ts +1 -0
  294. package/src/op/operator.ts +360 -10
  295. package/src/op/runtime.ts +37 -8
  296. package/src/op/runtimes/local.ts +6 -1
  297. package/src/op/source-archive.ts +161 -0
  298. package/src/op/step-output-ref.ts +6 -2
  299. package/src/op/steward-points.test.ts +313 -0
  300. package/src/op/steward-points.ts +194 -0
  301. package/src/op/steward-turn.ts +79 -0
  302. package/src/op/steward.test.ts +296 -0
  303. package/src/op/steward.ts +277 -0
  304. package/src/op/types.ts +60 -0
  305. package/src/op/work-lease-decl.ts +80 -0
  306. package/src/op/work-lease-run.test.ts +345 -0
  307. package/src/op/work-lease-run.ts +395 -0
  308. package/src/workspace/__fixtures__/decide-workspace.ts +129 -0
  309. package/src/workspace/__fixtures__/studio-template-84c8b21.json +67 -0
  310. package/src/workspace/answers-ledger.ts +118 -0
  311. package/src/workspace/box-isolation.test.ts +261 -0
  312. package/src/workspace/box-isolation.ts +205 -0
  313. package/src/workspace/changes-cli.ts +56 -0
  314. package/src/workspace/changes.schema.json +472 -0
  315. package/src/workspace/changes.test.ts +315 -0
  316. package/src/workspace/changes.ts +512 -0
  317. package/src/workspace/chant-migrations/chud-lexicon-exit-fly-site.ts +234 -0
  318. package/src/workspace/chant-migrations/chud-lexicon-exit-live-names.ts +164 -0
  319. package/src/workspace/chant-migrations/chud-lexicon-exit-rollback.ts +223 -0
  320. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.ts +195 -0
  321. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-policy.ts +108 -0
  322. package/src/workspace/chant-migrations/chud-lexicon-exit.ts +882 -0
  323. package/src/workspace/chant-migrations.e2e.test.ts +1089 -0
  324. package/src/workspace/chant-migrations.ts +164 -0
  325. package/src/workspace/check-contract.test.ts +5 -1
  326. package/src/workspace/check.schema.json +25 -7
  327. package/src/workspace/checks/box-isolation.ts +68 -0
  328. package/src/workspace/checks/boxes.test.ts +276 -0
  329. package/src/workspace/checks/boxes.ts +442 -0
  330. package/src/workspace/checks/diagrams.test.ts +134 -0
  331. package/src/workspace/checks/diagrams.ts +108 -0
  332. package/src/workspace/checks/records.ts +72 -0
  333. package/src/workspace/checks.test.ts +7 -0
  334. package/src/workspace/checks.ts +27 -3
  335. package/src/workspace/compose-graph.ts +2 -0
  336. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +10 -0
  337. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +26 -0
  338. package/src/workspace/conformance/index.ts +5 -0
  339. package/src/workspace/decide.test.ts +224 -0
  340. package/src/workspace/decide.ts +709 -0
  341. package/src/workspace/decision-points.schema.json +137 -0
  342. package/src/workspace/declaration.schema.json +285 -0
  343. package/src/workspace/declaration.test.ts +58 -0
  344. package/src/workspace/declaration.ts +241 -0
  345. package/src/workspace/declared-kinds.test.ts +5 -5
  346. package/src/workspace/declared-kinds.ts +71 -3
  347. package/src/workspace/generated-files.ts +14 -0
  348. package/src/workspace/graph-cli.ts +1 -1
  349. package/src/workspace/graph.schema.json +9 -1
  350. package/src/workspace/intent.schema.json +12 -3
  351. package/src/workspace/intent.ts +3 -10
  352. package/src/workspace/lineage-check.ts +16 -1
  353. package/src/workspace/lineage-upgrade-cli.ts +1 -1
  354. package/src/workspace/lineage-upgrade.test.ts +70 -0
  355. package/src/workspace/lineage-upgrade.ts +81 -10
  356. package/src/workspace/ls-contract.test.ts +57 -0
  357. package/src/workspace/ls.schema.json +46 -1
  358. package/src/workspace/ls.ts +62 -3
  359. package/src/workspace/point-answer.schema.json +95 -0
  360. package/src/workspace/points-cli.ts +284 -0
  361. package/src/workspace/points-write.schema.json +499 -0
  362. package/src/workspace/points.schema.json +743 -0
  363. package/src/workspace/points.test.ts +264 -0
  364. package/src/workspace/points.ts +564 -0
  365. package/src/workspace/read-contract.test.ts +18 -1
  366. package/src/workspace/reason-codes.test.ts +24 -1
  367. package/src/workspace/reason-codes.ts +49 -0
  368. package/src/workspace/record-assets.test.ts +3 -2
  369. package/src/workspace/record-assets.ts +4 -1
  370. package/src/workspace/records-amend.schema.json +2 -0
  371. package/src/workspace/records-cli.ts +28 -5
  372. package/src/workspace/records-close.schema.json +2 -0
  373. package/src/workspace/records-contract.test.ts +3 -2
  374. package/src/workspace/records-new.schema.json +2 -0
  375. package/src/workspace/records-review.schema.json +2 -0
  376. package/src/workspace/records-sessions-write.e2e.test.ts +77 -0
  377. package/src/workspace/records-sessions-write.test.ts +2 -34
  378. package/src/workspace/records-write.e2e.test.ts +108 -0
  379. package/src/workspace/records-write.test.ts +32 -41
  380. package/src/workspace/records-write.ts +33 -15
  381. package/src/workspace/records.schema.json +53 -2
  382. package/src/workspace/records.test.ts +48 -3
  383. package/src/workspace/records.ts +142 -6
  384. package/src/workspace/status-contract.test.ts +189 -6
  385. package/src/workspace/status-gates.ts +9 -4
  386. package/src/workspace/status-stewards.ts +329 -0
  387. package/src/workspace/status.schema.json +335 -5
  388. package/src/workspace/status.ts +142 -6
  389. package/src/workspace/work-acceptance.test.ts +274 -0
  390. package/src/workspace/work-cli.e2e.test.ts +180 -0
  391. package/src/workspace/work-cli.ts +429 -0
  392. package/src/workspace/work-evidence.schema.json +212 -0
  393. package/src/workspace/work-evidence.ts +169 -0
  394. package/src/workspace/work-history.schema.json +349 -0
  395. package/src/workspace/work-history.test.ts +156 -0
  396. package/src/workspace/work-lease.schema.json +233 -0
  397. package/src/workspace/work-readiness-chud.test.ts +145 -0
  398. package/src/workspace/work.test.ts +3 -2
  399. package/src/workspace/work.ts +100 -1
  400. /package/src/cli/{discovery-skip.test.ts → discovery-skip.e2e.test.ts} +0 -0
  401. /package/src/workspace/conformance/{conformance.test.ts → conformance.e2e.test.ts} +0 -0
  402. /package/src/workspace/{which-chant.test.ts → which-chant.e2e.test.ts} +0 -0
package/src/cli/main.ts CHANGED
@@ -54,6 +54,7 @@ import type { LexiconPlugin } from "../lexicon";
54
54
  */
55
55
  const BOOLEAN_FLAGS = new Set([
56
56
  "--help",
57
+ "--open",
57
58
  "--version",
58
59
  "--agents",
59
60
  "--agent",
@@ -378,6 +379,14 @@ export function parseArgs(args: string[]): ParsedArgs {
378
379
  // `chant workspace graph --intent <path[:start-end]>` (#2651)
379
380
  result.intent = args[++i];
380
381
  if (!result.intent || result.intent.startsWith("-")) throw new Error("--intent needs a region: --intent <path[:start-end]>");
382
+ } else if (arg === "--changes") {
383
+ // `chant workspace check --changes <base>..<head>` (#2773)
384
+ result.changes = args[++i];
385
+ if (!result.changes || result.changes.startsWith("-")) throw new Error("--changes needs a range: --changes <base>..<head>");
386
+ } else if (arg === "--severity") {
387
+ // `chant workspace check --changes <range> --severity off|warn|fail` (#2773)
388
+ result.severity = args[++i];
389
+ if (!result.severity || result.severity.startsWith("-")) throw new Error("--severity needs off, warn or fail");
381
390
  } else if (arg === "--current") {
382
391
  result.current = true;
383
392
  } else if (arg === "--set") {
@@ -392,6 +401,27 @@ export function parseArgs(args: string[]): ParsedArgs {
392
401
  // `chant workspace records review <id> --by <principal>` (#2670): whoever the caller says.
393
402
  result.by = args[++i];
394
403
  if (!result.by || result.by.startsWith("-")) throw new Error("--by needs the reviewer: --by <principal>");
404
+ // Repeatable for `workspace points answer` (#2739): each person who answered.
405
+ (result.bys ??= []).push(result.by);
406
+ } else if (arg === "--open") {
407
+ // `chant workspace points --open` (#2739): only the questions still open.
408
+ result.open = true;
409
+ } else if (arg === "--inputs") {
410
+ // `chant workspace points ask <point> --inputs <file|->` (#2739)
411
+ result.inputs = args[++i];
412
+ if (!result.inputs || (result.inputs.startsWith("-") && result.inputs !== "-")) throw new Error("--inputs needs a JSON file, or - for standard input: --inputs <file|->");
413
+ } else if (arg === "--response") {
414
+ // `chant workspace points ask <point> --response <file>` (#2739): a POST /v1/systemone response the caller got.
415
+ result.response = args[++i];
416
+ if (!result.response || result.response.startsWith("-")) throw new Error("--response needs a JSON file: --response <file>");
417
+ } else if (arg === "--subject") {
418
+ // `chant workspace points ask <point> --subject <id>` (#2739): what the question is about.
419
+ result.subject = args[++i];
420
+ if (!result.subject || result.subject.startsWith("-")) throw new Error("--subject needs what the question is about, such as a work item id: --subject <id>");
421
+ } else if (arg === "--answer") {
422
+ // `chant workspace points answer <id> --answer <value>` (#2739)
423
+ result.answer = args[++i];
424
+ if (result.answer === undefined || result.answer === "") throw new Error("--answer needs one of the question's candidates: --answer <value>");
395
425
  } else if (arg === "--sign") {
396
426
  // `chant workspace records review <id> --sign [<key file>]` (#2687): seal the verdict.
397
427
  // `records new` and `records amend` take it too, to seal the record's author (#2688).
@@ -431,6 +461,8 @@ export function parseArgs(args: string[]): ParsedArgs {
431
461
  } else if (arg === "--digest") {
432
462
  result.digest = args[++i];
433
463
  if (result.digest !== undefined) (result.digests ??= []).push(result.digest);
464
+ } else if (arg === "--release-plan") {
465
+ result.releasePlanFile = args[++i];
434
466
  } else if (arg === "--git-sha") {
435
467
  result.gitSha = args[++i];
436
468
  } else if (arg === "--run-id") {
@@ -483,8 +515,28 @@ export function parseArgs(args: string[]): ParsedArgs {
483
515
  result.interval = args[++i];
484
516
  } else if (arg === "--lease-ttl") {
485
517
  result.leaseTtl = args[++i];
518
+ } else if (arg === "--steward") {
519
+ // #2731 — the name is optional: a project with one steward runs it
520
+ // with a bare `--steward`.
521
+ const next = args[i + 1];
522
+ if (next !== undefined && !next.startsWith("-")) {
523
+ result.steward = next;
524
+ i++;
525
+ } else {
526
+ result.steward = "";
527
+ }
486
528
  } else if (arg === "--once") {
487
529
  result.once = true;
530
+ } else if (arg === "--work") {
531
+ // `chant run <op> --work <id>` (#2748)
532
+ const value = args[++i];
533
+ if (!value || value.startsWith("-")) throw new Error("--work needs a work item id: --work <id>");
534
+ result.work = value;
535
+ } else if (arg === "--holder" || arg === "--ttl" || arg === "--token" || arg === "--outcome") {
536
+ // `chant workspace work claim|renew|release <id>` (#2732)
537
+ const value = args[++i];
538
+ if (!value || value.startsWith("-")) throw new Error(`${arg} needs a value: ${arg} <${arg.slice(2)}>`);
539
+ result[arg.slice(2) as "holder" | "ttl" | "token" | "outcome"] = value;
488
540
  } else if (arg === "--note") {
489
541
  result.note = args[++i];
490
542
  } else if (arg === "--expire") {
@@ -664,6 +716,8 @@ Commands:
664
716
 
665
717
  Ops:
666
718
  run <name> Run an Op on the resolved runtime (--on; local by default)
719
+ [--work <id>] [--holder <name>]: the work item an Op
720
+ with a work lease runs under, and who holds it
667
721
  run list List all Ops with the runtime's state for each
668
722
  run status <name> Show the runtime's state for one Op's latest run
669
723
  run approve <op> <gate> Record a gate's resolution and wake the runtime
@@ -691,7 +745,10 @@ Ops:
691
745
  environment; --interval <dur> (default 60s) and
692
746
  --lease-ttl <dur> (default 5m) tune cadence; --once
693
747
  runs a single round and exits (cron/systemd-timer/
694
- CronJob invokers use this instead of the daemon)
748
+ CronJob invokers use this instead of the daemon).
749
+ --steward [<name>] runs a declared steward's local
750
+ form instead (#2731): its scheduled Ops on their
751
+ crons, under the steward's own lease
695
752
  operator status Last tick, outcomes, and pending gates per
696
753
  ConvergeOp, read from the chant/lifecycle orphan
697
754
  branch alone — no daemon needs to be running
@@ -802,6 +859,29 @@ Workspace (level 1, #2524):
802
859
  closing commit and seal, in one write. Without
803
860
  --kind, the one session kind the declaration names.
804
861
  Prints {path, id, changed, seal, closedRev}
862
+ workspace work claim|renew|release <id> --holder <name> [--kind <kind file>] [--ttl <seconds|duration>] [--token <token>] [--outcome <text>] [--note <text>] [--json]
863
+ Take, heartbeat or give back the lease on a work item:
864
+ refs/chant/lease/work/<id>, a compare-and-set ref with a
865
+ fencing token and an expiry, pushed to the remote so
866
+ separate clones coordinate. A claim is refused, exit 2,
867
+ while anyone holds it live. Each change appends to
868
+ _leases/<id>.jsonl on chant/lifecycle
869
+ workspace work history <id> [--kind <kind file>] [--json]
870
+ A work item's lease history: each claim with its token
871
+ and holder, and how it ended, released with an outcome
872
+ or never released (expired or lost). Read-only
873
+ workspace points [--open] [--kind <kind file>] [--at <rev>] [--json]
874
+ List the decision points the declared answer kinds'
875
+ points files declare, and the questions asked of them;
876
+ --open keeps the escalated and proposed ones (ws-058)
877
+ workspace points ask <point> --inputs <file|-> [--response <file>] [--subject <id>] [--kind <kind file>] [--dry-run]
878
+ Ask a point's table, model and quorum deciders and
879
+ record the answer: proposed from a model, escalated to
880
+ people below its threshold. --response is a POST
881
+ /v1/systemone response the caller got; chant calls no model
882
+ workspace points answer <id> --answer <value> --by <name>... [--kind <kind file>] [--dry-run]
883
+ Record people's answer to an open question, or confirm
884
+ a model's proposal, once the point's quorum is met
805
885
  workspace verify [--base <rev>] [--head <rev>] [--require attested]
806
886
  Check the commits in base..head against the signers
807
887
  and roles read from base. A change to the signers file
@@ -828,6 +908,13 @@ Workspace (level 1, #2524):
828
908
  whose pinned files changed. Needs no workspace file.
829
909
  --at reads a commit's git objects; --format json
830
910
  prints the read-contract document
911
+ workspace check --changes <base>..<head> [--work <id>] [--severity off|warn|fail] [--kind <kind file>...] [--json]
912
+ Map each path the diff changes to the current records
913
+ whose constrains cover it: change-uncovered when none
914
+ does, change-out-of-scope when a record in hand (the
915
+ --work item and its decisions) lists it in
916
+ out_of_scope. The declaration's changes block sets
917
+ the severity (warn by default) and ignore globs
831
918
  workspace build [dir] [--member <name>] [-o <dir>] [--dry-run]
832
919
  Build every chant member and example project, each with
833
920
  its own chant, one process per toolchain. -o <dir>
@@ -904,7 +991,11 @@ Component release ledger + status:
904
991
  <file> finishes an attempt that stopped)
905
992
  components release <env> Append one immutable release record
906
993
  (--component <name> --digest <sha256:...>
907
- [--git-sha <sha>] [--run-id <id>] [--actor <name>])
994
+ [--git-sha <sha>] [--run-id <id>] [--actor <name>]);
995
+ --release-plan <file> takes --digest's place,
996
+ persisting the release plan the file holds to
997
+ _plans/<digest>.json (ws-055) and recording its
998
+ own digest
908
999
  components export <env> Materialize a persisted build archive manifest to
909
1000
  a portable directory (--component <name>
910
1001
  [--digest <manifestDigest>] -o <dir> [--json]);
@@ -1328,8 +1419,12 @@ export const commandRegistry: CommandDef[] = [
1328
1419
  // Workspace reads (#2524). Imported on first use, so a level-0 command never
1329
1420
  // loads anything under workspace/ (#2525 rule 5, pinned by #2526's goldens).
1330
1421
  { name: "workspace records", handler: async (ctx) => (await import("../workspace/records-cli")).runWorkspaceRecords(ctx) },
1422
+ // ws-058 (#2739) — decision points and the questions asked of them; never calls a model.
1423
+ { name: "workspace points", handler: async (ctx) => (await import("../workspace/points-cli")).runWorkspacePoints(ctx) },
1331
1424
  { name: "workspace init", handler: async (ctx) => (await import("../workspace/init")).runWorkspaceInit(ctx) },
1332
1425
  { name: "workspace ls", handler: async (ctx) => (await import("../workspace/ls")).runWorkspaceLs(ctx) },
1426
+ // #2732 — the work lease: claim, renew and release a work item.
1427
+ { name: "workspace work", runsNoConfig: true, handler: async (ctx) => (await import("../workspace/work-cli")).runWorkspaceWork(ctx) },
1333
1428
  { name: "workspace status", handler: async (ctx) => (await import("../workspace/status")).runWorkspaceStatus(ctx) },
1334
1429
  { name: "workspace lineage", handler: async (ctx) => (await import("../workspace/lineage-cli")).runWorkspaceLineage(ctx) },
1335
1430
  { name: "workspace upgrade", handler: async (ctx) => (await import("../workspace/lineage-upgrade-cli")).runWorkspaceUpgrade(ctx) },
@@ -85,7 +85,7 @@ describe("which servers have the workspace tools", () => {
85
85
  const { tools } = (await rpc(server(cwd), "tools/list")) as { tools: { name: string }[] };
86
86
  expect(tools.map((t) => t.name)).toEqual(expect.arrayContaining(names));
87
87
  }
88
- expect(names).toEqual(["workspace-ls", "workspace-status", "workspace-graph", "workspace-records", "records-new", "records-amend", "records-review", "records-close"]);
88
+ expect(names).toEqual(["workspace-ls", "workspace-status", "workspace-graph", "workspace-changes", "workspace-records", "workspace-points", "workspace-work-history", "records-new", "records-amend", "records-review", "records-close", "points-answer"]);
89
89
  });
90
90
 
91
91
  test("a server outside any workspace, or given none, does not", async () => {
@@ -100,8 +100,8 @@ describe("which servers have the workspace tools", () => {
100
100
  }
101
101
  });
102
102
 
103
- test("the descriptions say records are proposals and by names who decided", () => {
104
- for (const t of workspaceWriteTools) expect(t.description).toMatch(/proposals until they are reviewed.*by must name the person or agent that actually decided/s);
103
+ test("the descriptions say records are proposals and by names who proposed or decided", () => {
104
+ for (const t of workspaceWriteTools) expect(t.description).toMatch(/proposals until they are reviewed.*by must name the person or agent that actually proposed or decided it/s);
105
105
  });
106
106
  });
107
107
 
@@ -115,6 +115,41 @@ describe("reads", () => {
115
115
  expect(recordsOf(only.structuredContent).map((r) => r.id)).toEqual(["fix-001"]);
116
116
  }, 120_000);
117
117
 
118
+ test("workspace-points returns the document chant workspace points --json prints, and points-answer the write's (ws-058)", async () => {
119
+ const s = server();
120
+ const res = await call(s, "workspace-points", { open: true });
121
+ expect(res.isError).toBeUndefined();
122
+ expect(res.structuredContent).toEqual(cli(["workspace", "points", "--open", "--json"]));
123
+ expect(res.structuredContent).toMatchObject({ open: true, sources: [], points: [], questions: [] });
124
+ // The generated workspace declares no answer kind, so there is nothing to answer.
125
+ const answered = await call(s, "points-answer", { id: "slice-tier-000000000000", answer: "small", by: ["alice"] });
126
+ expect(answered.structuredContent).toMatchObject({ verb: "answer", error: { code: "points-undeclared" } });
127
+ const bad = await call(s, "points-answer", { id: "slice-tier-000000000000", answer: "small", by: [] });
128
+ expect(bad.isError).toBe(true);
129
+ }, 120_000);
130
+
131
+ test("workspace-work-history returns the document chant workspace work history --json prints (#2785)", async () => {
132
+ const s = server();
133
+ const res = await call(s, "workspace-work-history", { item: "W-1" });
134
+ expect(res.isError).toBeUndefined();
135
+ expect(res.structuredContent).toEqual(cli(["workspace", "work", "history", "W-1", "--json"]));
136
+ expect(res.structuredContent).toMatchObject({ contract: 1, error: { code: expect.any(String) } });
137
+ const bad = await call(s, "workspace-work-history", {});
138
+ expect(bad.isError).toBe(true);
139
+ }, 120_000);
140
+
141
+ test("workspace-changes returns the document chant workspace check --changes --json prints (#2773)", async () => {
142
+ const s = server();
143
+ const res = await call(s, "workspace-changes", { range: "HEAD", severity: "fail" });
144
+ expect(res.isError).toBeUndefined();
145
+ expect(res.structuredContent).toEqual(cli(["workspace", "check", "--changes", "HEAD", "--severity", "fail", "--json"]));
146
+ expect(res.structuredContent).toMatchObject({ severity: "fail", paths: [], findings: [], ok: true });
147
+ const unknown = await call(s, "workspace-changes", { range: "HEAD", work: "W-999" });
148
+ expect(unknown.structuredContent).toMatchObject({ error: { code: "work-item-unknown" } });
149
+ const bad = await call(s, "workspace-changes", { range: "HEAD", severity: "loud" });
150
+ expect(bad.isError).toBe(true);
151
+ }, 120_000);
152
+
118
153
  test("an error document is returned as a document, and a flag-shaped value is refused before chant runs", async () => {
119
154
  const s = server();
120
155
  const missing = await call(s, "workspace-records", { kind: "nowhere/none.kind.mjs" });
@@ -130,6 +165,7 @@ describe("reads", () => {
130
165
  expect(mcpToolCall(["workspace", "graph", "--intent", "a.mjs:1", "--kind", KIND, "--json"])).toEqual({ name: "workspace-graph", arguments: { intent: "a.mjs:1", kind: [KIND] } });
131
166
  expect(mcpToolCall(["workspace", "graph", "--composites", "--json"])).toEqual({ name: "workspace-graph", arguments: { composites: true } });
132
167
  expect(mcpToolCall(["workspace", "check", "--format", "json"])).toBeUndefined();
168
+ expect(mcpToolCall(["workspace", "check", "--changes", "main..HEAD", "--work", "W-001", "--json"])).toEqual({ name: "workspace-changes", arguments: { range: "main..HEAD", work: "W-001" } });
133
169
  });
134
170
  });
135
171
 
@@ -173,25 +209,18 @@ describe("writes", () => {
173
209
  const reasoning = await call(s, "records-amend", { kind: KIND, id: "fix-001", fields: { question: "Something else?" } });
174
210
  expect(reasoning.structuredContent).toMatchObject({ error: { code: "amend-supersede-instead" } });
175
211
 
176
- const both = await call(s, "records-new", { kind: KIND, record: { ...proposal("Two authors"), decided_by: "alice" }, by: "bob", dryRun: true });
212
+ // A new record opens proposed (MCP forces it), so by names the proposer, in proposedBy's field, not the decider (#2756).
213
+ const both = await call(s, "records-new", { kind: KIND, record: { ...proposal("Two proposers"), proposed_by: "alice" }, by: "bob", dryRun: true });
177
214
  expect(both.structuredContent).toMatchObject({ error: { code: "write-input-invalid" } });
178
- const by = await call(s, "records-new", { kind: KIND, record: proposal("One author"), by: "alice", dryRun: true });
215
+ const by = await call(s, "records-new", { kind: KIND, record: proposal("One proposer"), by: "alice", dryRun: true });
179
216
  expect(by.structuredContent, JSON.stringify(by.structuredContent)).toHaveProperty("text");
180
- expect((by.structuredContent as { text: string }).text).toContain('decided_by: "alice"');
217
+ expect((by.structuredContent as { text: string }).text).toContain('proposed_by: "alice"');
218
+ expect((by.structuredContent as { text: string }).text).toContain("decided_by: null");
219
+
220
+ // --sign seals the decider, and a record by names as proposed carries no decided_by yet.
221
+ const signed = await call(s, "records-new", { kind: KIND, record: proposal("Signed"), by: "alice", sign: true, dryRun: true });
222
+ expect(signed.structuredContent).toMatchObject({ error: { code: "record-sign-failed", message: expect.stringContaining("names no decided_by") } });
181
223
 
182
- // No key configured on this host: the CLI's refusal and remedy.
183
- const home = { GIT_CONFIG_GLOBAL: "/dev/null", GIT_CONFIG_NOSYSTEM: "1" };
184
- const saved = { ...process.env };
185
- Object.assign(process.env, home);
186
- try {
187
- const signed = await call(s, "records-new", { kind: KIND, record: proposal("Signed"), by: "alice", sign: true, dryRun: true });
188
- expect(signed.structuredContent).toMatchObject({ error: { code: "record-sign-failed", message: expect.stringContaining("pass --sign <key file>") } });
189
- } finally {
190
- for (const k of Object.keys(home)) {
191
- if (saved[k] === undefined) delete process.env[k];
192
- else process.env[k] = saved[k];
193
- }
194
- }
195
224
  // Nothing above wrote a file.
196
225
  expect(readFileSync(join(ws.dir, "decisions", "fix-001-how-the-app-is-deployed.md"), "utf-8")).toContain('question: "What declares the app\'s deployment?"');
197
226
  }, 180_000);
@@ -6,15 +6,18 @@
6
6
  * is a thin call into the code the CLI runs:
7
7
  *
8
8
  * - The reads (`workspace-ls`, `workspace-status`, `workspace-graph`,
9
- * `workspace-records`) run `chant workspace <command> ... --json` with the
10
- * chant this server runs as, in the server's directory, and return the
9
+ * `workspace-changes`, `workspace-records`, `workspace-points`,
10
+ * `workspace-work-history`) run `chant workspace <command>
11
+ * ... --json` with the chant this server runs as, in the server's
12
+ * directory, and return the
11
13
  * document it printed, unchanged, with its reason codes (#2536). Running the
12
14
  * command, rather than calling into it, keeps every rule it has, handing the
13
15
  * read to the workspace root's pinned chant included (ws-021), and keeps
14
16
  * anything a command prints away from the protocol on stdout.
15
17
  * - The writes (`records-new`, `records-amend`, `records-review`,
16
- * `records-close`) call the functions `chant workspace records new|amend|
17
- * review|close` call, and return the same JSON result. They keep every rule
18
+ * `records-close`, `points-answer`) call the functions `chant workspace
19
+ * records new|amend|review|close` and `points answer` call, and return the
20
+ * same JSON result. They keep every rule
18
21
  * the CLI keeps: the kind's schema, a closed record never changing, an
19
22
  * approved one changing only as its approval rule allows, a dissent needing
20
23
  * a note, and `sign` using this host's configured key or refusing with the
@@ -50,7 +53,7 @@ export interface WorkspaceToolsOptions {
50
53
 
51
54
  const PROTOCOL =
52
55
  "Records are proposals until they are reviewed: a new record opens proposed, and people decide it through reviews and amendments. " +
53
- "by must name the person or agent that actually decided, as it is recorded as given.";
56
+ "by must name the person or agent that actually proposed or decided it, as it is recorded as given.";
54
57
 
55
58
  const kindProp = {
56
59
  type: "string",
@@ -75,7 +78,7 @@ export const workspaceReadTools: ToolDefinition[] = [
75
78
  {
76
79
  name: "workspace-status",
77
80
  description:
78
- "What each member has released to an environment, from the lifecycle ledgers: chant workspace status <env> --json. Returns that document unchanged (status.schema.json).",
81
+ "What each member has released to an environment, its gates, and the steward that runs it with each Op's last run, from the declaration and the lifecycle ledgers: chant workspace status <env> --json. Returns that document unchanged (status.schema.json).",
79
82
  inputSchema: {
80
83
  type: "object",
81
84
  properties: {
@@ -103,10 +106,29 @@ export const workspaceReadTools: ToolDefinition[] = [
103
106
  },
104
107
  },
105
108
  },
109
+ {
110
+ name: "workspace-changes",
111
+ description:
112
+ "The forward coverage check over a diff: chant workspace check --changes <range> --json (changes.schema.json, #2773). Each changed path with the current records whose constrains cover it, and a change-uncovered or change-out-of-scope finding for each gap, at the severity the declaration's changes block sets. Returns the document unchanged.",
113
+ inputSchema: {
114
+ type: "object",
115
+ properties: {
116
+ range: { type: "string", description: "The diff: <base>..<head>, <base>...<head> (from their merge base), or <base> alone, to HEAD (--changes)." },
117
+ work: { type: "string", description: "The id of the work item in hand, whose out_of_scope and whose decisions' out_of_scope apply (--work)." },
118
+ severity: { type: "string", enum: ["off", "warn", "fail"], description: "In place of the declaration's changes.severity (--severity)." },
119
+ kind: {
120
+ type: "array",
121
+ items: { type: "string" },
122
+ description: "Record kind files to read in place of the declared ones (--kind).",
123
+ },
124
+ },
125
+ required: ["range"],
126
+ },
127
+ },
106
128
  {
107
129
  name: "workspace-records",
108
130
  description:
109
- "The records of a kind, validated, with supersession, provenance, quorum and warnings: chant workspace records --json (records.schema.json). With since, what changed since a revision or a review session (records-since.schema.json). Returns the document unchanged; with id, only that record is kept in records. " +
131
+ "The records of a kind, validated, with supersession, remediation, provenance, quorum and warnings: chant workspace records --json (records.schema.json). With since, what changed since a revision or a review session (records-since.schema.json). Returns the document unchanged; with id, only that record is kept in records. " +
110
132
  PROTOCOL,
111
133
  inputSchema: {
112
134
  type: "object",
@@ -119,6 +141,32 @@ export const workspaceReadTools: ToolDefinition[] = [
119
141
  },
120
142
  },
121
143
  },
144
+ {
145
+ name: "workspace-points",
146
+ description:
147
+ "The workspace's decision points and the questions asked of them: chant workspace points --json (points.schema.json, ws-058). A question is open while it is escalated to people, or proposed by a model and not yet confirmed; each lists any model's answer with its confidence and threshold. Returns the document unchanged. chant calls no model to answer this.",
148
+ inputSchema: {
149
+ type: "object",
150
+ properties: {
151
+ open: { type: "boolean", description: "Only the open questions (--open)." },
152
+ kind: { type: "string", description: "One answer kind file, in place of the declared ones (--kind)." },
153
+ at: atProp,
154
+ },
155
+ },
156
+ },
157
+ {
158
+ name: "workspace-work-history",
159
+ description:
160
+ "One work item's lease history, from the lifecycle ledger of the member that owns its work kind: chant workspace work history <item> --json (work-history.schema.json, #2785). Each claim has its fencing token and holder and how it ended: released with an outcome, still held, or never released (expired, or lost to a later claim). Returns the document unchanged.",
161
+ inputSchema: {
162
+ type: "object",
163
+ properties: {
164
+ item: { type: "string", description: "The work item's id." },
165
+ kind: { type: "string", description: "The work kind file, when more than one declared work kind has the id (--kind)." },
166
+ },
167
+ required: ["item"],
168
+ },
169
+ },
122
170
  ];
123
171
 
124
172
  export const workspaceWriteTools: ToolDefinition[] = [
@@ -133,7 +181,11 @@ export const workspaceWriteTools: ToolDefinition[] = [
133
181
  kind: kindProp,
134
182
  record: { type: "object", description: "The record's fields, as the kind's schema describes them. The id is allocated when left out." },
135
183
  prefix: { type: "string", description: "The id prefix to allocate under, when the records use several (--prefix)." },
136
- by: { type: "string", description: "Who decided: written to the kind's decider field, such as decided_by. Required to sign." },
184
+ by: {
185
+ type: "string",
186
+ description:
187
+ "Who proposed it: written to the kind's proposedBy field, such as proposed_by, since a record opens proposed. Written to its decider field, such as decided_by, only when the record's fields open it straight into a later state. Required to sign.",
188
+ },
137
189
  sign: signProp,
138
190
  dryRun: dryRunProp,
139
191
  },
@@ -191,6 +243,23 @@ export const workspaceWriteTools: ToolDefinition[] = [
191
243
  required: ["id"],
192
244
  },
193
245
  },
246
+ {
247
+ name: "points-answer",
248
+ description:
249
+ "Record people's answer to an open decision point question, or confirm a model's proposal: chant workspace points answer. Refused unless the point's quorum is met: distinct people, none holding the agent role, each holding one of the quorum's roles when it names any. An answered question never changes. " +
250
+ PROTOCOL,
251
+ inputSchema: {
252
+ type: "object",
253
+ properties: {
254
+ id: { type: "string", description: "The question's id, as workspace-points lists it." },
255
+ answer: { type: ["string", "boolean"], description: "One of the question's candidates; for a noul, true or false." },
256
+ by: { type: "array", items: { type: "string" }, description: "Each person who answered (--by)." },
257
+ kind: { type: "string", description: "The answer kind file. Without it, the declared answer kinds." },
258
+ dryRun: dryRunProp,
259
+ },
260
+ required: ["id", "answer", "by"],
261
+ },
262
+ },
194
263
  ];
195
264
 
196
265
  /** A tool call that can't be made as given: the client gets it as an error result, and nothing runs. */
@@ -249,6 +318,31 @@ export function readArgv(tool: string, params: Record<string, unknown>): string[
249
318
  if (intent !== undefined) return ["workspace", "graph", "--intent", intent, ...kindArgs, ...atArgs, "--json"];
250
319
  return ["workspace", "graph", ...kindArgs, ...atArgs, "--json"];
251
320
  }
321
+ case "workspace-changes": {
322
+ const range = str(params, "range", true)!;
323
+ const work = str(params, "work");
324
+ const severity = str(params, "severity");
325
+ if (severity !== undefined && !["off", "warn", "fail"].includes(severity)) throw new ToolInputError("severity must be off, warn or fail");
326
+ return [
327
+ "workspace",
328
+ "check",
329
+ "--changes",
330
+ range,
331
+ ...(work !== undefined ? ["--work", work] : []),
332
+ ...(severity !== undefined ? ["--severity", severity] : []),
333
+ ...kinds(params).flatMap((k) => ["--kind", k]),
334
+ "--json",
335
+ ];
336
+ }
337
+ case "workspace-work-history": {
338
+ const item = str(params, "item", true)!;
339
+ const kind = str(params, "kind");
340
+ return ["workspace", "work", "history", item, ...(kind !== undefined ? ["--kind", kind] : []), "--json"];
341
+ }
342
+ case "workspace-points": {
343
+ const kind = str(params, "kind");
344
+ return ["workspace", "points", ...(bool(params, "open") ? ["--open"] : []), ...(kind !== undefined ? ["--kind", kind] : []), ...atArgs, "--json"];
345
+ }
252
346
  case "workspace-records": {
253
347
  const kind = str(params, "kind");
254
348
  const since = str(params, "since");
@@ -389,6 +483,14 @@ export function createWorkspaceTools(options: WorkspaceToolsOptions): WorkspaceT
389
483
  cwd,
390
484
  });
391
485
  },
486
+ "points-answer": async (params) => {
487
+ const { answerPoint } = await import("../../workspace/decide");
488
+ const answer = params.answer;
489
+ if (typeof answer !== "string" && typeof answer !== "boolean") throw new ToolInputError("answer must be a string, or true or false");
490
+ const by = params.by;
491
+ if (!Array.isArray(by) || by.length === 0 || !by.every((b) => typeof b === "string" && b.trim() !== "")) throw new ToolInputError("by must list each person who answered");
492
+ return answerPoint({ cwd, id: str(params, "id", true)!, answer, by: by as string[], kind: str(params, "kind"), dryRun: bool(params, "dryRun") });
493
+ },
392
494
  "records-close": async (params) => {
393
495
  const w = await write();
394
496
  const { closeRecord, RECORDS_CLOSE_SCHEMA_ID } = await import("../../workspace/records-close");
@@ -1,4 +1,4 @@
1
- import { importLexiconModule, lexiconModulePath, lexiconNames, registerLexiconDeclarations } from "../lexicon-module";
1
+ import { importLexiconModule, importLexiconPackage, lexiconModulePath, lexiconNames, registerLexiconDeclarations, resolveFromProject } from "../lexicon-module";
2
2
  import { readLexiconDeclarationsStatically, type StaticLexiconRead } from "../config-static";
3
3
  export { unknownPathLexiconsNotice } from "../config-static";
4
4
  import { createRequire } from "node:module";
@@ -51,7 +51,7 @@ export async function loadPlugin(lexiconName: string): Promise<LexiconPlugin> {
51
51
  }
52
52
 
53
53
  const packageName = `@intentius/chant-lexicon-${lexiconName}`;
54
- const mod = await import(packageName);
54
+ const mod = (await importLexiconPackage(packageName)) as Record<string, any>;
55
55
 
56
56
  // Look for an explicit LexiconPlugin export
57
57
  for (const value of Object.values(mod)) {
@@ -109,7 +109,15 @@ export function resolveLexiconVersions(lexiconNames: readonly string[]): Record<
109
109
  if (lexiconModulePath(name) !== undefined) continue;
110
110
  const packageName = `@intentius/chant-lexicon-${name}`;
111
111
  try {
112
- let dir = dirname(require_.resolve(packageName));
112
+ // chant#2845 — a lexicon chant's own install can't reach is resolved from the project.
113
+ let entry: string | undefined;
114
+ try {
115
+ entry = require_.resolve(packageName);
116
+ } catch (err) {
117
+ entry = resolveFromProject(packageName);
118
+ if (entry === undefined) throw err;
119
+ }
120
+ let dir = dirname(entry);
113
121
  // Bounded walk — a resolved entry point is never deeply nested inside
114
122
  // its own package, and an unbounded loop here would climb to `/`.
115
123
  for (let depth = 0; depth < 10; depth++) {
@@ -287,17 +287,39 @@ export interface ParsedArgs {
287
287
  kind?: string;
288
288
  /** Every `--kind` given, in order: `chant workspace graph --intent` reads each (#2651). */
289
289
  kinds?: string[];
290
+ /** Every `--by` given, in order: `chant workspace points answer` counts each person toward the quorum (#2739). */
291
+ bys?: string[];
292
+ /** `chant workspace points --open` (#2739): only the questions still open. */
293
+ open?: boolean;
294
+ /** `chant workspace points ask <point> --inputs <file|->` (#2739): the inputs, as a JSON object. */
295
+ inputs?: string;
296
+ /** `chant workspace points ask <point> --response <file>` (#2739): a POST /v1/systemone response the caller got from a backend. */
297
+ response?: string;
298
+ /** `chant workspace points ask <point> --subject <id>` (#2739): what the question is about. */
299
+ subject?: string;
300
+ /** `chant workspace points answer <id> --answer <value>` (#2739): the people's answer. */
301
+ answer?: string;
290
302
  /** `chant workspace graph --composites` (#2662): print each composite instance with the components that can deploy it. */
291
303
  composites?: boolean;
292
304
  /** `chant workspace graph --intent <path[:start-end]>` (#2651): the region the intent graph is over. */
293
305
  intent?: string;
306
+ /** `chant workspace check --changes <base>..<head>` (#2773): the diff the forward coverage check maps to records. */
307
+ changes?: string;
308
+ /** `chant workspace check --changes ... --severity off|warn|fail` (#2773): in place of the declaration's `changes.severity`. */
309
+ severity?: string;
294
310
  /** `chant workspace records --current` (#2546): leave out records a closed record supersedes. */
295
311
  current?: boolean;
296
312
  /** `chant workspace records amend <id> --set <file|->` (#2670): the JSON fields to set. */
297
313
  set?: string;
298
314
  /** `chant workspace records review <id> --verdict <v>` (#2670): agree, dissent or abstain. */
299
315
  verdict?: string;
300
- /** `chant workspace records review <id> --by <principal>` (#2670): the reviewer, as the caller names them. */
316
+ /**
317
+ * `chant workspace records review <id> --by <principal>` (#2670): the
318
+ * reviewer, as the caller names them. Also `chant workspace records new
319
+ * --by <name>` (#2756): the record's proposer, or its decider when it
320
+ * opens straight into a later state; see {@link ChannelOptions.by} in
321
+ * `records-write.ts`.
322
+ */
301
323
  by?: string;
302
324
  /**
303
325
  * `chant workspace records review <id> --sign [<key file>]` (#2687): the key that seals the verdict, or true for git's user.signingkey.
@@ -369,6 +391,8 @@ export interface ParsedArgs {
369
391
  component?: string;
370
392
  /** `chant components release record --digest <sha256:...>` (#568) — artifact digest to record, joining this release to the build archive/ledger. Also `chant components export --digest <manifestDigest>` (#929) — a build archive manifest digest to export directly, bypassing env/component resolution. */
371
393
  digest?: string;
394
+ /** `chant components release record --release-plan <file>` (ws-055, #2733) — path to a release plan JSON file, persisted content-addressed to `_plans/<digest>.json` on chant/lifecycle and read back through the read contract (`chant workspace status --json`). The plan's own `digest` field supplies `--digest` when it is omitted, and must match it when both are given. Distinct from `--plan` (#2300, below), the Op gate-approval plan digest. */
395
+ releasePlanFile?: string;
372
396
  /** Every `--digest` value, in order (#2602). `chant components promote --digest <component>=<sha256:...>` is repeatable, one per component; the other commands read the single {@link digest}. */
373
397
  digests?: string[];
374
398
  /** `chant components release record --git-sha <sha>` (#568) — git commit the deploy was built from. */
@@ -413,6 +437,23 @@ export interface ParsedArgs {
413
437
  interval?: string;
414
438
  /** `chant operator --lease-ttl <duration>` (#1485) — how long an acquired lease is valid before it's reclaimable by another operator. Default: 5m. */
415
439
  leaseTtl?: string;
440
+ /**
441
+ * `chant operator --steward [<name>]` (#2731) — run a declared steward's
442
+ * local form: its scheduled Ops on their crons, under the steward's own
443
+ * lease. `""` when the flag is given without a name, which picks the
444
+ * project's only steward.
445
+ */
446
+ steward?: string;
447
+ /** `chant workspace work claim|renew|release <id> --holder <name>` (#2732): who holds, or releases, the work lease. */
448
+ holder?: string;
449
+ /** `chant run <op> --work <id>` (#2748): the work item an Op with a work lease runs under. `chant workspace check --changes --work <id>` (#2773): the work item in hand. */
450
+ work?: string;
451
+ /** `chant workspace work claim|renew <id> --ttl <seconds|duration>` (#2732): how long the lease lasts unless renewed. */
452
+ ttl?: string;
453
+ /** `chant workspace work renew|release <id> --token <token>` (#2732): the fencing token the caller holds. */
454
+ token?: string;
455
+ /** `chant workspace work release <id> --outcome <text>` (#2732): how the work ended, such as done or not_done. */
456
+ outcome?: string;
416
457
  /** `chant operator --once` (#1485) — run a single round and exit, instead of looping until Ctrl-C. Also the offline test/cron-invoker story. */
417
458
  once?: boolean;
418
459
  /** `chant approve <op> <gate> --note <text>` (#1485) — optional free-text prose recorded on the gate-resolution fact. The PR link belongs in `--url` since #2028; this is for everything that isn't the link. */
@@ -26,6 +26,7 @@ import { join } from "path";
26
26
  import { regenLexicon, type RegenResult } from "./lexicon-regen";
27
27
  import { fetchWithRetry } from "./fetch";
28
28
  import { isLexiconPlugin, type UpstreamPin } from "../lexicon";
29
+ import { importLexiconPackage } from "../lexicon-module";
29
30
 
30
31
  // ── Public types ──────────────────────────────────────────────────────
31
32
 
@@ -200,7 +201,7 @@ export function revertVersionBump(filePath: string, original: string): void {
200
201
  export async function loadUpstreamPin(lexicon: LexiconId): Promise<UpstreamPin | null> {
201
202
  let mod: Record<string, unknown>;
202
203
  try {
203
- mod = (await import(`@intentius/chant-lexicon-${lexicon}`)) as Record<string, unknown>;
204
+ mod = (await importLexiconPackage(`@intentius/chant-lexicon-${lexicon}`)) as Record<string, unknown>;
204
205
  } catch {
205
206
  return null;
206
207
  }