@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
@@ -0,0 +1,137 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://intentius.io/chant/schemas/workspace/decision-points/v1/decision-points.schema.json",
4
+ "title": "Decision points",
5
+ "description": "A workspace's decision points (ws-058, #2738): the recurring questions it asks of its own graph, declared as data in a JSON file that an answer record kind names in `answers.points`. Each point is a typed question (`noul`, `choice` with 2 to 255 options, or `score` with 2 to 10 ordered levels, the question types of the POST /v1/systemone wire format, #2491), the inputs it reads, each named as a read-contract output, and an ordered chain of deciders: `table` rows, `model` deciders with a backend, a pinned model id and a threshold, and a `quorum` of people, always last. Taken from chud's decision-points.schema.json; `boolean` is read as `noul`. What JSON Schema cannot say is checked in code (`points.ts`): an input's output is one the read contract has, a table row tests declared inputs and answers a candidate, a field belongs to its decider's kind, a model id is pinned rather than an alias, and the chain ends in its one quorum. Unknown fields are refused, except fields whose names start with x-.",
6
+ "type": "object",
7
+ "required": ["points"],
8
+ "properties": {
9
+ "$schema": { "type": "string" },
10
+ "points": {
11
+ "type": "object",
12
+ "minProperties": 1,
13
+ "propertyNames": { "pattern": "^[a-z][a-z0-9-]*$" },
14
+ "additionalProperties": { "$ref": "#/$defs/point" }
15
+ }
16
+ },
17
+ "patternProperties": { "^x-": true },
18
+ "additionalProperties": false,
19
+ "$defs": {
20
+ "text": { "type": "string", "minLength": 1 },
21
+ "point": {
22
+ "type": "object",
23
+ "required": ["title", "question", "inputs", "deciders"],
24
+ "properties": {
25
+ "title": { "$ref": "#/$defs/text" },
26
+ "question": { "$ref": "#/$defs/question" },
27
+ "inputs": {
28
+ "type": "object",
29
+ "description": "The state the deciders see, input name to description. A name is a read-contract output (record, decision, work-item, finding, region, commit, member, gate, release, environment, component), optionally followed by dotted field names, such as work-item.fits_small: a field of that output, or a value the caller derives from it. The caller supplies the values; a table row can only test these names.",
30
+ "minProperties": 1,
31
+ "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_-]*(\\.[A-Za-z_][A-Za-z0-9_]*)*$" },
32
+ "additionalProperties": { "type": "string" }
33
+ },
34
+ "deciders": {
35
+ "type": "array",
36
+ "minItems": 1,
37
+ "items": { "$ref": "#/$defs/decider" }
38
+ }
39
+ },
40
+ "patternProperties": { "^x-": true },
41
+ "additionalProperties": false
42
+ },
43
+ "question": {
44
+ "type": "object",
45
+ "required": ["type", "instructions", "criteria"],
46
+ "properties": {
47
+ "type": { "enum": ["noul", "boolean", "choice", "score"], "description": "boolean is chud's name for noul, read as noul." },
48
+ "instructions": { "$ref": "#/$defs/text" },
49
+ "criteria": {
50
+ "description": "The candidates. noul: {true, false} descriptions. choice: option to description, 2 to 255 options. score: 2 to 10 ordered levels.",
51
+ "type": ["object", "array"]
52
+ }
53
+ },
54
+ "additionalProperties": false,
55
+ "allOf": [
56
+ {
57
+ "if": { "properties": { "type": { "enum": ["noul", "boolean"] } } },
58
+ "then": {
59
+ "properties": {
60
+ "criteria": {
61
+ "type": "object",
62
+ "required": ["true", "false"],
63
+ "properties": { "true": { "type": "string" }, "false": { "type": "string" } },
64
+ "additionalProperties": false
65
+ }
66
+ }
67
+ }
68
+ },
69
+ {
70
+ "if": { "properties": { "type": { "const": "choice" } } },
71
+ "then": { "properties": { "criteria": { "type": "object", "minProperties": 2, "maxProperties": 255, "additionalProperties": { "type": "string" } } } }
72
+ },
73
+ {
74
+ "if": { "properties": { "type": { "const": "score" } } },
75
+ "then": { "properties": { "criteria": { "type": "array", "minItems": 2, "maxItems": 10, "uniqueItems": true, "items": { "$ref": "#/$defs/text" } } } }
76
+ }
77
+ ]
78
+ },
79
+ "scalar": { "type": ["string", "number", "boolean", "null"] },
80
+ "condition": {
81
+ "description": "A value the input must equal, or one comparison.",
82
+ "oneOf": [
83
+ { "$ref": "#/$defs/scalar" },
84
+ {
85
+ "type": "object",
86
+ "minProperties": 1,
87
+ "maxProperties": 1,
88
+ "properties": {
89
+ "eq": { "$ref": "#/$defs/scalar" },
90
+ "ne": { "$ref": "#/$defs/scalar" },
91
+ "lt": { "type": "number" },
92
+ "lte": { "type": "number" },
93
+ "gt": { "type": "number" },
94
+ "gte": { "type": "number" },
95
+ "in": { "type": "array", "items": { "$ref": "#/$defs/scalar" } }
96
+ },
97
+ "additionalProperties": false
98
+ }
99
+ ]
100
+ },
101
+ "row": {
102
+ "type": "object",
103
+ "required": ["when", "answer"],
104
+ "properties": {
105
+ "when": {
106
+ "type": "object",
107
+ "description": "Every named input must meet its condition. An empty object matches every state.",
108
+ "additionalProperties": { "$ref": "#/$defs/condition" }
109
+ },
110
+ "answer": { "type": ["string", "boolean"] },
111
+ "note": { "type": "string" }
112
+ },
113
+ "additionalProperties": false
114
+ },
115
+ "decider": {
116
+ "type": "object",
117
+ "required": ["kind"],
118
+ "properties": {
119
+ "kind": { "enum": ["table", "model", "quorum"] },
120
+ "rows": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/row" } },
121
+ "backend": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "model: which backend answers, such as systemone (any server with the POST /v1/systemone wire format). chant never calls it: the decide Op activity or a runtime's decider does." },
122
+ "model": { "type": "string", "minLength": 1, "description": "model: the pinned model id the backend is asked for, such as jev-1.13.0. An alias such as jev-latest is refused." },
123
+ "threshold": { "type": "number", "exclusiveMinimum": 0, "maximum": 1, "description": "model: the least confidence that makes the answer a proposal. Below it the answer is not observed and the next decider is asked." },
124
+ "unreachable": { "enum": ["escalate", "fail"], "description": "model: what happens when the backend can't be reached or gives no usable answer: escalate to the next decider (the default), or fail the ask and write nothing." },
125
+ "count": { "type": "integer", "minimum": 1, "description": "quorum: how many distinct people must answer." },
126
+ "roles": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/text" }, "description": "quorum: the trust policy roles whose holders count." },
127
+ "note": { "type": "string" }
128
+ },
129
+ "additionalProperties": false,
130
+ "allOf": [
131
+ { "if": { "properties": { "kind": { "const": "table" } } }, "then": { "required": ["rows"] } },
132
+ { "if": { "properties": { "kind": { "const": "model" } } }, "then": { "required": ["backend", "model", "threshold"] } },
133
+ { "if": { "properties": { "kind": { "const": "quorum" } } }, "then": { "required": ["count"] } }
134
+ ]
135
+ }
136
+ }
137
+ }
@@ -56,6 +56,20 @@
56
56
  "$ref": "#/$defs/recordKind"
57
57
  }
58
58
  },
59
+ "hosts": {
60
+ "type": "array",
61
+ "description": "The hosts boxes run on (#2727). A host is one machine reached under one hostname: boxes on it share its ports, its state root and, in a browser, its cookie jar, so chant workspace check compares the boxes on one host and never boxes on different hosts. A member's box block names its host. Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
62
+ "items": {
63
+ "$ref": "#/$defs/host"
64
+ }
65
+ },
66
+ "diagrams": {
67
+ "type": "array",
68
+ "description": "The workspace's own diagram artifacts (#2764): the diagrams that belong to no one member, such as a diagrams directory at the root. A member names its own in its diagrams. chant workspace ls lists every declared diagram, and chant workspace check reports one whose render is stale for its source when the entry records a sourceHash. Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
69
+ "items": {
70
+ "$ref": "#/$defs/diagram"
71
+ }
72
+ },
59
73
  "checks": {
60
74
  "type": "object",
61
75
  "description": "Severity for the declaration checks that allow it, keyed by WSP id (#2535, ws-028): error, warning, info or off. chant workspace check refuses an id it does not know, and one whose severity is fixed.",
@@ -65,6 +79,28 @@
65
79
  "additionalProperties": {
66
80
  "$ref": "#/$defs/severity"
67
81
  }
82
+ },
83
+ "changes": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "description": "The forward coverage check, chant workspace check --changes <base>..<head> (#2773): each path a diff changes is mapped to the current records whose constrains cover it. severity says what a finding does: off reports none, warn (the default) reports them and passes, fail reports them and fails. ignore lists globs over files whose changes need no record, such as lockfiles and generated output. Added in schema 1 by chant 0.92.0, so a declaration that uses it sets minReader to 0.92.0 or newer.",
87
+ "properties": {
88
+ "severity": {
89
+ "enum": [
90
+ "off",
91
+ "warn",
92
+ "fail"
93
+ ],
94
+ "description": "What a change-uncovered or change-out-of-scope finding does. warn when absent."
95
+ },
96
+ "ignore": {
97
+ "type": "array",
98
+ "description": "Globs over file paths from the workspace root: * and ? within one segment, ** across segments. A changed path one matches is listed as ignored and never reported.",
99
+ "items": {
100
+ "$ref": "#/$defs/fileGlob"
101
+ }
102
+ }
103
+ }
68
104
  }
69
105
  },
70
106
  "patternProperties": {
@@ -269,6 +305,16 @@
269
305
  "$ref": "#/$defs/recordKind"
270
306
  }
271
307
  },
308
+ "diagrams": {
309
+ "type": "array",
310
+ "description": "The diagram artifacts this member holds (#2764). chant workspace ls lists every declared diagram, and chant workspace check reports one whose render is stale for its source when the entry records a sourceHash. Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
311
+ "items": {
312
+ "$ref": "#/$defs/diagram"
313
+ }
314
+ },
315
+ "box": {
316
+ "$ref": "#/$defs/box"
317
+ },
272
318
  "upstream": {
273
319
  "type": "string",
274
320
  "minLength": 1,
@@ -354,6 +400,114 @@
354
400
  "description": "A file or directory path with / separators: no leading /, no . or .. segments and no trailing /.",
355
401
  "pattern": "^(?!\\.\\.?(/|$))[^/\\\\]+(/(?!\\.\\.?(/|$))[^/\\\\]+)*$"
356
402
  },
403
+ "box": {
404
+ "type": "object",
405
+ "description": "The member is a box, or holds a box's declarations (#2726). A box holds no credential: each capability it needs outside itself is reached through a broker, a runtime such as a lobby or a door, which holds the credential and enforces the scope. chant workspace check fails when a file in the member's directory carries a literal secret (WSP121) and when a capability names no broker (WSP122). chant workspace status --json lists the capabilities, so a broker can read the scopes. Its host, slot, ports, state and cookies state the box's isolation (#2727): chant derives each value from the box's identity, its host, the member's name and its slot, and prints them in chant workspace status --json, so a runtime reads them instead of choosing its own. chant workspace check fails when two boxes on a host resolve to the same value (WSP123) and when a box hard-codes a machine path (WSP124). A member that builds the fountain lexicon's Box declares the callback token fountain gives its persistent sandbox as the capability fountain-callback, brokered by fountain, with scope owner, or chant workspace check fails (WSP125, #2780). Added in schema 1 by chant 0.91.0, so a declaration that uses it sets minReader to 0.91.0 or newer.",
406
+ "properties": {
407
+ "capabilities": {
408
+ "type": "array",
409
+ "description": "Each capability the box reaches outside itself, named once. None when omitted.",
410
+ "items": {
411
+ "$ref": "#/$defs/capability"
412
+ }
413
+ },
414
+ "host": {
415
+ "$ref": "#/$defs/name",
416
+ "description": "The host the box runs on, one of the top-level hosts (#2727). The box's name is the member's name."
417
+ },
418
+ "slot": {
419
+ "type": "integer",
420
+ "minimum": 0,
421
+ "description": "The box's number on its host (#2727). Its ports come from the slot's block of the host's range."
422
+ },
423
+ "ports": {
424
+ "type": "object",
425
+ "description": "The ports the box listens on, each a name and its offset in the box's block (#2727). The port is the block's first port plus the offset.",
426
+ "propertyNames": {
427
+ "$ref": "#/$defs/kindName"
428
+ },
429
+ "additionalProperties": {
430
+ "type": "integer",
431
+ "minimum": 0,
432
+ "maximum": 65534
433
+ }
434
+ },
435
+ "state": {
436
+ "type": "object",
437
+ "description": "State the box keeps outside its checkout, such as hud's identity and database, each a name and a path relative to the box's state directory (#2727). The name is usually the environment variable the runtime sets, such as HUD_IDENTITY_PATH. A path that is absolute, starts with ~ or an environment reference, or has a .. segment is a WSP124 finding.",
438
+ "propertyNames": {
439
+ "type": "string",
440
+ "pattern": "^[A-Za-z_][A-Za-z0-9_-]{0,63}$"
441
+ },
442
+ "additionalProperties": {
443
+ "type": "string",
444
+ "minLength": 1
445
+ }
446
+ },
447
+ "cookies": {
448
+ "type": "array",
449
+ "description": "Session cookie names the box's runtimes set, such as hud_session (#2727). A browser scopes a cookie to a host, not a port, so each resolves to <cookie>_<member name>.",
450
+ "uniqueItems": true,
451
+ "items": {
452
+ "type": "string",
453
+ "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,63}$"
454
+ }
455
+ }
456
+ },
457
+ "dependentRequired": {
458
+ "host": [
459
+ "slot"
460
+ ],
461
+ "slot": [
462
+ "host"
463
+ ],
464
+ "ports": [
465
+ "host"
466
+ ],
467
+ "state": [
468
+ "host"
469
+ ],
470
+ "cookies": [
471
+ "host"
472
+ ]
473
+ },
474
+ "patternProperties": {
475
+ "^x-": true
476
+ },
477
+ "additionalProperties": false
478
+ },
479
+ "capability": {
480
+ "type": "object",
481
+ "description": "A capability a box needs and does not hold the credential for, such as inference, fountain or a third-party API (#2726).",
482
+ "required": [
483
+ "name"
484
+ ],
485
+ "properties": {
486
+ "name": {
487
+ "$ref": "#/$defs/kindName",
488
+ "description": "The capability, such as inference or fountain. Unique within the box."
489
+ },
490
+ "broker": {
491
+ "type": "string",
492
+ "minLength": 1,
493
+ "description": "What brokers the capability: the runtime that holds the credential and swaps the box's own token for it, such as lobby or door. It may name a member of this workspace, or a runtime outside it. Without it the capability is unbrokered, and chant workspace check fails with WSP122."
494
+ },
495
+ "scope": {
496
+ "type": "array",
497
+ "uniqueItems": true,
498
+ "description": "What of the box's own the broker lets it reach, which the broker enforces. For Fountain: agent (start conversations with its own agent), vault (attach its own vault), conversations and sandboxes (its own). The words are the broker's; chant records them.",
499
+ "items": {
500
+ "type": "string",
501
+ "minLength": 1,
502
+ "pattern": "^[^\\u0000-\\u001f]+$"
503
+ }
504
+ }
505
+ },
506
+ "patternProperties": {
507
+ "^x-": true
508
+ },
509
+ "additionalProperties": false
510
+ },
357
511
  "recordKind": {
358
512
  "type": "object",
359
513
  "description": "A record kind the workspace declares (#2680): a kind file that exports recordKind. chant workspace check fails (WSP115) when the file is missing or does not load as a record kind.",
@@ -375,6 +529,78 @@
375
529
  },
376
530
  "additionalProperties": false
377
531
  },
532
+ "diagram": {
533
+ "type": "object",
534
+ "description": "A diagram artifact the workspace declares (#2764): a rendered image with a source, pinned to the renderer that made it. chant never runs the renderer.",
535
+ "required": [
536
+ "name",
537
+ "title",
538
+ "render",
539
+ "renderer"
540
+ ],
541
+ "properties": {
542
+ "name": {
543
+ "$ref": "#/$defs/name",
544
+ "description": "Unique across the declaration."
545
+ },
546
+ "title": {
547
+ "type": "string",
548
+ "minLength": 1,
549
+ "description": "Shown above the diagram."
550
+ },
551
+ "source": {
552
+ "oneOf": [
553
+ { "$ref": "#/$defs/path" },
554
+ { "type": "null" }
555
+ ],
556
+ "description": "The source file, from the workspace root, with / separators. Null for an SVG with no source. Default null."
557
+ },
558
+ "render": {
559
+ "$ref": "#/$defs/path",
560
+ "description": "The rendered image, from the workspace root, with / separators."
561
+ },
562
+ "renderer": {
563
+ "$ref": "#/$defs/diagramRenderer"
564
+ },
565
+ "sourceHash": {
566
+ "type": ["string", "null"],
567
+ "pattern": "^[0-9a-f]{64}$",
568
+ "description": "sha256 hex of the source's bytes when render was last produced from it. chant workspace check compares this against the source in the tree read and reports drift (WSP133) on a mismatch; without it, or without a source, the render is never checked for drift. Default null."
569
+ }
570
+ },
571
+ "patternProperties": {
572
+ "^x-": true
573
+ },
574
+ "additionalProperties": false
575
+ },
576
+ "diagramRenderer": {
577
+ "type": "object",
578
+ "description": "The renderer a diagram's render was made with. chant records the pin; it never installs or runs the renderer (ws-052).",
579
+ "required": [
580
+ "tool",
581
+ "version"
582
+ ],
583
+ "properties": {
584
+ "tool": {
585
+ "enum": ["d2", "mermaid", "graphviz"]
586
+ },
587
+ "version": {
588
+ "$ref": "#/$defs/version",
589
+ "description": "The exact release the render was made with, such as 0.9.0."
590
+ },
591
+ "args": {
592
+ "type": "array",
593
+ "description": "Passed before the input and output paths, in order, such as [\"--layout=elk\", \"--theme=0\", \"--pad=40\", \"--omit-version\"]. Empty when absent.",
594
+ "items": {
595
+ "type": "string"
596
+ }
597
+ }
598
+ },
599
+ "patternProperties": {
600
+ "^x-": true
601
+ },
602
+ "additionalProperties": false
603
+ },
378
604
  "generatedFile": {
379
605
  "type": "object",
380
606
  "description": "One generated file of a member (#2524 D14, #2541).",
@@ -469,6 +695,65 @@
469
695
  "additionalProperties": false
470
696
  }
471
697
  ]
698
+ },
699
+ "host": {
700
+ "type": "object",
701
+ "description": "A host boxes run on (#2727).",
702
+ "required": [
703
+ "name",
704
+ "ports"
705
+ ],
706
+ "properties": {
707
+ "name": {
708
+ "$ref": "#/$defs/name",
709
+ "description": "The host's name, unique among hosts. A box block names it in host."
710
+ },
711
+ "ports": {
712
+ "type": "object",
713
+ "description": "The TCP ports boxes on this host take theirs from. Slot n owns the block from + n * perBox to from + (n + 1) * perBox - 1, which must end at or before to.",
714
+ "required": [
715
+ "from",
716
+ "to",
717
+ "perBox"
718
+ ],
719
+ "properties": {
720
+ "from": {
721
+ "$ref": "#/$defs/port",
722
+ "description": "The first port of the range."
723
+ },
724
+ "to": {
725
+ "$ref": "#/$defs/port",
726
+ "description": "The last port of the range, inclusive."
727
+ },
728
+ "perBox": {
729
+ "type": "integer",
730
+ "minimum": 1,
731
+ "maximum": 65535,
732
+ "description": "How many ports each box's block holds. A box's port offsets are below it."
733
+ }
734
+ },
735
+ "additionalProperties": false
736
+ },
737
+ "stateRoot": {
738
+ "type": "string",
739
+ "minLength": 1,
740
+ "description": "Where boxes on this host keep state, as an environment reference such as ${XDG_STATE_HOME}/chant/boxes, which the runtime expands on the machine. A box's state directory is <stateRoot>/<member name>. A literal machine path, such as /Users/... or anything under $HOME, is a WSP124 finding. Default ${XDG_STATE_HOME}/chant/boxes."
741
+ }
742
+ },
743
+ "patternProperties": {
744
+ "^x-": true
745
+ },
746
+ "additionalProperties": false
747
+ },
748
+ "port": {
749
+ "type": "integer",
750
+ "minimum": 1,
751
+ "maximum": 65535
752
+ },
753
+ "fileGlob": {
754
+ "type": "string",
755
+ "description": "A glob over file paths, relative to the workspace root: * and ? within one segment, ** across segments, [...] classes and {a,b} alternatives. No leading /, no . or .. segments.",
756
+ "pattern": "^(?!\\.\\.?(/|$))[^/\\\\]+(/(?!\\.\\.?(/|$))[^/\\\\]+)*$"
472
757
  }
473
758
  }
474
759
  }
@@ -6,6 +6,7 @@ import { afterAll, describe, expect, test } from "vitest";
6
6
  import {
7
7
  compareVersions,
8
8
  DECLARATION_SCHEMA_ID,
9
+ declaredDiagrams,
9
10
  ownerOf,
10
11
  parseDeclaration,
11
12
  readDeclaration,
@@ -345,3 +346,60 @@ describe("generated files (#2541)", () => {
345
346
  expect(failure(base([{ name: "g", kind: "examples", glob: "examples/*", generated: [] }])).message).toContain('unknown field "generated"');
346
347
  });
347
348
  });
349
+
350
+ describe("diagram artifacts (#2764)", () => {
351
+ const renderer = { tool: "d2", version: "0.9.0", args: ["--layout=elk", "--theme=0", "--pad=40", "--omit-version"] };
352
+ const diagram = (extra: Record<string, unknown> = {}) => ({
353
+ name: "architecture",
354
+ title: "Studio architecture",
355
+ source: "docs/diagrams/architecture.d2",
356
+ render: "docs/diagrams/architecture.svg",
357
+ renderer,
358
+ ...extra,
359
+ });
360
+ const member = (diagrams: unknown[], extra: Record<string, unknown> = {}) => ({ name: "docs", dir: "docs", kind: "other", because: "the docs site", diagrams, ...extra });
361
+
362
+ test("a member's diagram is read with the workspace-relative source and render, and a null source is the default", () => {
363
+ const d = parse(base([member([diagram()])]));
364
+ expect(d.members[0].diagrams).toEqual([
365
+ { name: "architecture", title: "Studio architecture", source: "docs/diagrams/architecture.d2", render: "docs/diagrams/architecture.svg", renderer, sourceHash: null, member: "docs", pointer: "/members/0/diagrams/0" },
366
+ ]);
367
+ const noSource = parse(base([member([diagram({ source: undefined })])]));
368
+ expect(noSource.members[0].diagrams[0].source).toBeNull();
369
+ });
370
+
371
+ test("the workspace's own diagrams are in the top-level diagrams, with member null", () => {
372
+ const d = parse(base([{ name: "x", dir: "x", kind: "chant" }], { diagrams: [diagram({ name: "boundary" })] }));
373
+ expect(d.diagrams).toEqual([{ ...diagram({ name: "boundary" }), sourceHash: null, member: null, pointer: "/diagrams/0" }]);
374
+ expect(declaredDiagrams(d)).toEqual(d.diagrams);
375
+ });
376
+
377
+ test("declaredDiagrams lists the workspace's own first, then each member's, in file order", () => {
378
+ const d = parse(base([member([diagram()]), { name: "app", dir: "app", kind: "chant" }], { diagrams: [diagram({ name: "boundary", render: "docs/diagrams/boundary.svg" })] }));
379
+ expect(declaredDiagrams(d).map((x) => x.name)).toEqual(["boundary", "architecture"]);
380
+ });
381
+
382
+ test("a diagram name is unique across the declaration, workspace and members together", () => {
383
+ const clash = failure(base([member([diagram()])], { diagrams: [diagram()] }));
384
+ expect(clash.code).toBe("declaration-invalid");
385
+ expect(clash.message).toContain('the diagram name "architecture" is already used by the diagram at /diagrams/0');
386
+ });
387
+
388
+ test("renderer.tool is a closed list, and title, render and renderer are required", () => {
389
+ expect(failure(base([member([diagram({ renderer: { tool: "mscgen", version: "1.0.0" } })])])).code).toBe("declaration-invalid");
390
+ expect(failure(base([member([{ name: "a", source: null, render: "a.svg", renderer }])])).message).toContain('missing required field "title"');
391
+ expect(failure(base([member([{ name: "a", title: "A", source: null, renderer }])])).message).toContain('missing required field "render"');
392
+ expect(failure(base([member([{ name: "a", title: "A", source: null, render: "a.svg" }])])).message).toContain('missing required field "renderer"');
393
+ });
394
+
395
+ test("a sourceHash is a 64-character lowercase hex string, or absent", () => {
396
+ const hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
397
+ expect(parse(base([member([diagram({ sourceHash: hash })])])).members[0].diagrams[0].sourceHash).toBe(hash);
398
+ expect(failure(base([member([diagram({ sourceHash: "not-a-hash" })])])).code).toBe("declaration-invalid");
399
+ });
400
+
401
+ test("source and render stay inside the workspace, like every other path", () => {
402
+ expect(failure(base([member([diagram({ source: "/etc/passwd" })])])).code).toBe("declaration-invalid");
403
+ expect(failure(base([member([diagram({ render: "../out.svg" })])])).code).toBe("declaration-invalid");
404
+ });
405
+ });