@intentius/chant 0.101.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (739) hide show
  1. package/dist/agents/checks.d.ts.map +1 -1
  2. package/dist/attrref.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +2 -0
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts.map +1 -1
  6. package/dist/audit/nginx.d.ts.map +1 -1
  7. package/dist/audit/prior-art.d.ts +48 -0
  8. package/dist/audit/prior-art.d.ts.map +1 -1
  9. package/dist/behaviour-kinds.d.ts.map +1 -1
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/change-set.d.ts +232 -0
  12. package/dist/change-set.d.ts.map +1 -0
  13. package/dist/cli/commands/audit.d.ts +7 -0
  14. package/dist/cli/commands/audit.d.ts.map +1 -1
  15. package/dist/cli/commands/build.d.ts.map +1 -1
  16. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  17. package/dist/cli/commands/check-lexicon.d.ts +16 -0
  18. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  19. package/dist/cli/commands/import.d.ts +8 -0
  20. package/dist/cli/commands/import.d.ts.map +1 -1
  21. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  22. package/dist/cli/commands/init.d.ts +19 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/onboard.d.ts +9 -0
  25. package/dist/cli/commands/onboard.d.ts.map +1 -1
  26. package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
  27. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
  28. package/dist/cli/handlers/build.d.ts.map +1 -1
  29. package/dist/cli/handlers/change-set.d.ts +11 -0
  30. package/dist/cli/handlers/change-set.d.ts.map +1 -0
  31. package/dist/cli/handlers/dev.d.ts.map +1 -1
  32. package/dist/cli/handlers/fan-out.d.ts +33 -0
  33. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  34. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  35. package/dist/cli/handlers/misc.d.ts.map +1 -1
  36. package/dist/cli/handlers/operator.d.ts +16 -0
  37. package/dist/cli/handlers/operator.d.ts.map +1 -1
  38. package/dist/cli/handlers/pr.d.ts +31 -0
  39. package/dist/cli/handlers/pr.d.ts.map +1 -0
  40. package/dist/cli/handlers/run.d.ts.map +1 -1
  41. package/dist/cli/lsp/server.d.ts.map +1 -1
  42. package/dist/cli/main.d.ts.map +1 -1
  43. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  44. package/dist/cli/mcp/server.d.ts.map +1 -1
  45. package/dist/cli/mcp/tools/build.d.ts.map +1 -1
  46. package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
  47. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  48. package/dist/cli/mcp/tools/import.d.ts.map +1 -1
  49. package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
  50. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
  51. package/dist/cli/mcp/tools/search.d.ts.map +1 -1
  52. package/dist/cli/mcp/workspace-tools.d.ts +4 -3
  53. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  54. package/dist/cli/registry.d.ts +74 -3
  55. package/dist/cli/registry.d.ts.map +1 -1
  56. package/dist/codegen/fetch.d.ts.map +1 -1
  57. package/dist/codegen/naming.d.ts.map +1 -1
  58. package/dist/codegen/pinned-upgrade.d.ts +67 -3
  59. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  60. package/dist/codegen/registry.d.ts.map +1 -1
  61. package/dist/components/auto-release.d.ts +16 -0
  62. package/dist/components/auto-release.d.ts.map +1 -1
  63. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  64. package/dist/components/capability.d.ts +53 -0
  65. package/dist/components/capability.d.ts.map +1 -1
  66. package/dist/components/changed-files.d.ts +31 -0
  67. package/dist/components/changed-files.d.ts.map +1 -0
  68. package/dist/components/cli-support.d.ts +9 -1
  69. package/dist/components/cli-support.d.ts.map +1 -1
  70. package/dist/components/component.d.ts +24 -0
  71. package/dist/components/component.d.ts.map +1 -1
  72. package/dist/components/deploy-units.d.ts.map +1 -1
  73. package/dist/components/driver.d.ts +13 -0
  74. package/dist/components/driver.d.ts.map +1 -1
  75. package/dist/components/fan-out-output.d.ts +6 -0
  76. package/dist/components/fan-out-output.d.ts.map +1 -1
  77. package/dist/components/fan-out-record.d.ts +41 -0
  78. package/dist/components/fan-out-record.d.ts.map +1 -0
  79. package/dist/components/fan-out-run.d.ts +65 -0
  80. package/dist/components/fan-out-run.d.ts.map +1 -1
  81. package/dist/components/fan-out-support.d.ts +2 -0
  82. package/dist/components/fan-out-support.d.ts.map +1 -1
  83. package/dist/components/fan-out.d.ts +6 -0
  84. package/dist/components/fan-out.d.ts.map +1 -1
  85. package/dist/components/gated-wave-pipeline.d.ts +50 -0
  86. package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
  87. package/dist/components/index.d.ts +1 -1
  88. package/dist/components/index.d.ts.map +1 -1
  89. package/dist/components/layers.d.ts +25 -0
  90. package/dist/components/layers.d.ts.map +1 -0
  91. package/dist/components/pr-pipeline.d.ts +61 -0
  92. package/dist/components/pr-pipeline.d.ts.map +1 -0
  93. package/dist/components/pr-run.d.ts +119 -0
  94. package/dist/components/pr-run.d.ts.map +1 -0
  95. package/dist/components/promote.d.ts.map +1 -1
  96. package/dist/components/starter-plugin.d.ts.map +1 -1
  97. package/dist/components/verbs/process-runner.d.ts.map +1 -1
  98. package/dist/components/verbs/r2-sync.d.ts.map +1 -1
  99. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  100. package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
  101. package/dist/components/verbs/shell.d.ts.map +1 -1
  102. package/dist/components/verbs/sign.d.ts.map +1 -1
  103. package/dist/components/verbs/verify.d.ts.map +1 -1
  104. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  105. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  106. package/dist/components/verbs/wrangler.d.ts.map +1 -1
  107. package/dist/components/wave-plan.d.ts +49 -0
  108. package/dist/components/wave-plan.d.ts.map +1 -0
  109. package/dist/composite.d.ts.map +1 -1
  110. package/dist/config.d.ts +19 -7
  111. package/dist/config.d.ts.map +1 -1
  112. package/dist/declarable.d.ts +16 -0
  113. package/dist/declarable.d.ts.map +1 -1
  114. package/dist/discovery/cache.d.ts.map +1 -1
  115. package/dist/discovery/fold-import.d.ts +15 -5
  116. package/dist/discovery/fold-import.d.ts.map +1 -1
  117. package/dist/discovery/param-deps.d.ts +16 -0
  118. package/dist/discovery/param-deps.d.ts.map +1 -1
  119. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
  120. package/dist/discovery/specifier-resolve.d.ts +37 -0
  121. package/dist/discovery/specifier-resolve.d.ts.map +1 -0
  122. package/dist/errors.d.ts.map +1 -1
  123. package/dist/fold/fold.d.ts +3 -1
  124. package/dist/fold/fold.d.ts.map +1 -1
  125. package/dist/gated-waves.d.ts +147 -0
  126. package/dist/gated-waves.d.ts.map +1 -0
  127. package/dist/graph-detail.d.ts.map +1 -1
  128. package/dist/graph-ir.d.ts.map +1 -1
  129. package/dist/graph-layout.d.ts.map +1 -1
  130. package/dist/import/base-parser.d.ts.map +1 -1
  131. package/dist/import/embedded.d.ts +7 -0
  132. package/dist/import/embedded.d.ts.map +1 -1
  133. package/dist/import/parser-options.d.ts +14 -0
  134. package/dist/import/parser-options.d.ts.map +1 -0
  135. package/dist/import/parser.d.ts +17 -0
  136. package/dist/import/parser.d.ts.map +1 -1
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/kubectl-context.d.ts.map +1 -1
  140. package/dist/lexicon-output.d.ts.map +1 -1
  141. package/dist/lexicon-schema.d.ts +3 -3
  142. package/dist/lexicon.d.ts +103 -3
  143. package/dist/lexicon.d.ts.map +1 -1
  144. package/dist/lifecycle/assert-live.d.ts.map +1 -1
  145. package/dist/lifecycle/gate-ledger.d.ts +22 -0
  146. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  147. package/dist/lifecycle/git.d.ts +46 -1
  148. package/dist/lifecycle/git.d.ts.map +1 -1
  149. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  150. package/dist/lifecycle/observe.d.ts.map +1 -1
  151. package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
  152. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  153. package/dist/lifecycle/scenario.d.ts.map +1 -1
  154. package/dist/lifecycle/status.d.ts.map +1 -1
  155. package/dist/lifecycle/work-lease.d.ts +61 -2
  156. package/dist/lifecycle/work-lease.d.ts.map +1 -1
  157. package/dist/lint/config.d.ts +8 -8
  158. package/dist/lint/engine.d.ts +6 -0
  159. package/dist/lint/engine.d.ts.map +1 -1
  160. package/dist/lint/post-synth.d.ts +18 -0
  161. package/dist/lint/post-synth.d.ts.map +1 -1
  162. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  163. package/dist/op/activities/activity-contracts.d.ts +137 -11
  164. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  165. package/dist/op/activities/apply.d.ts +79 -9
  166. package/dist/op/activities/apply.d.ts.map +1 -1
  167. package/dist/op/activities/change-set.d.ts +62 -0
  168. package/dist/op/activities/change-set.d.ts.map +1 -0
  169. package/dist/op/activities/decide.d.ts +2 -0
  170. package/dist/op/activities/decide.d.ts.map +1 -1
  171. package/dist/op/activities/factory.d.ts +137 -0
  172. package/dist/op/activities/factory.d.ts.map +1 -0
  173. package/dist/op/activities/index.d.ts +5 -1
  174. package/dist/op/activities/index.d.ts.map +1 -1
  175. package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
  176. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  177. package/dist/op/activity-contract.d.ts +1 -1
  178. package/dist/op/activity-contract.d.ts.map +1 -1
  179. package/dist/op/activity-failure.d.ts.map +1 -1
  180. package/dist/op/activity-profiles.d.ts.map +1 -1
  181. package/dist/op/builders.d.ts +11 -0
  182. package/dist/op/builders.d.ts.map +1 -1
  183. package/dist/op/composites/apply-op.d.ts +12 -5
  184. package/dist/op/composites/apply-op.d.ts.map +1 -1
  185. package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
  186. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
  187. package/dist/op/decide-backend.d.ts +5 -1
  188. package/dist/op/decide-backend.d.ts.map +1 -1
  189. package/dist/op/decide-read-inputs.d.ts +4 -2
  190. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  191. package/dist/op/emulator-lifecycle.d.ts +21 -2
  192. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  193. package/dist/op/factory.d.ts +83 -0
  194. package/dist/op/factory.d.ts.map +1 -0
  195. package/dist/op/gate-approval.d.ts +5 -1
  196. package/dist/op/gate-approval.d.ts.map +1 -1
  197. package/dist/op/gate-wait.d.ts.map +1 -1
  198. package/dist/op/gate.d.ts +19 -3
  199. package/dist/op/gate.d.ts.map +1 -1
  200. package/dist/op/index.d.ts +6 -1
  201. package/dist/op/index.d.ts.map +1 -1
  202. package/dist/op/local-executor.d.ts +6 -0
  203. package/dist/op/local-executor.d.ts.map +1 -1
  204. package/dist/op/op-ir.d.ts +2 -0
  205. package/dist/op/op-ir.d.ts.map +1 -1
  206. package/dist/op/op-verb-class.d.ts.map +1 -1
  207. package/dist/op/operator.d.ts.map +1 -1
  208. package/dist/op/run-context.d.ts +39 -0
  209. package/dist/op/run-context.d.ts.map +1 -0
  210. package/dist/op/run-live.d.ts.map +1 -1
  211. package/dist/op/runtimes/local.d.ts.map +1 -1
  212. package/dist/op/source-archive.d.ts.map +1 -1
  213. package/dist/op/steward-beside.d.ts.map +1 -1
  214. package/dist/op/steward-points.d.ts.map +1 -1
  215. package/dist/op/steward.d.ts.map +1 -1
  216. package/dist/op/types.d.ts +16 -3
  217. package/dist/op/types.d.ts.map +1 -1
  218. package/dist/op/work-lease-run.d.ts +24 -4
  219. package/dist/op/work-lease-run.d.ts.map +1 -1
  220. package/dist/plan-summary.d.ts +207 -0
  221. package/dist/plan-summary.d.ts.map +1 -0
  222. package/dist/pr-forge.d.ts +105 -0
  223. package/dist/pr-forge.d.ts.map +1 -0
  224. package/dist/pr-loop.d.ts +178 -0
  225. package/dist/pr-loop.d.ts.map +1 -0
  226. package/dist/project-root.d.ts.map +1 -1
  227. package/dist/provenance.d.ts +21 -0
  228. package/dist/provenance.d.ts.map +1 -1
  229. package/dist/pseudo-parameter.d.ts.map +1 -1
  230. package/dist/reconcile.d.ts.map +1 -1
  231. package/dist/secret-materialization.d.ts.map +1 -1
  232. package/dist/telemetry-attribution.d.ts +31 -0
  233. package/dist/telemetry-attribution.d.ts.map +1 -1
  234. package/dist/terraform/emit-source.d.ts.map +1 -1
  235. package/dist/terraform/hcl2json.d.ts +45 -0
  236. package/dist/terraform/hcl2json.d.ts.map +1 -0
  237. package/dist/terraform/parse.d.ts +4 -40
  238. package/dist/terraform/parse.d.ts.map +1 -1
  239. package/dist/testing.d.ts.map +1 -1
  240. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
  241. package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
  242. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
  243. package/dist/workspace/agent-cli.d.ts +5 -0
  244. package/dist/workspace/agent-cli.d.ts.map +1 -1
  245. package/dist/workspace/box-cli.d.ts +12 -0
  246. package/dist/workspace/box-cli.d.ts.map +1 -0
  247. package/dist/workspace/box-factory.d.ts +97 -0
  248. package/dist/workspace/box-factory.d.ts.map +1 -0
  249. package/dist/workspace/box-listing.d.ts +85 -0
  250. package/dist/workspace/box-listing.d.ts.map +1 -0
  251. package/dist/workspace/box-publish.d.ts +147 -0
  252. package/dist/workspace/box-publish.d.ts.map +1 -0
  253. package/dist/workspace/broker-protocol.d.ts +190 -0
  254. package/dist/workspace/broker-protocol.d.ts.map +1 -0
  255. package/dist/workspace/changes.d.ts.map +1 -1
  256. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
  257. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  258. package/dist/workspace/checks.d.ts +5 -0
  259. package/dist/workspace/checks.d.ts.map +1 -1
  260. package/dist/workspace/compose-graph.d.ts +10 -0
  261. package/dist/workspace/compose-graph.d.ts.map +1 -1
  262. package/dist/workspace/composites.d.ts +2 -2
  263. package/dist/workspace/composites.d.ts.map +1 -1
  264. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
  265. package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
  266. package/dist/workspace/conformance/broker.d.ts +202 -0
  267. package/dist/workspace/conformance/broker.d.ts.map +1 -0
  268. package/dist/workspace/conformance/index.d.ts +68 -6
  269. package/dist/workspace/conformance/index.d.ts.map +1 -1
  270. package/dist/workspace/conformance/vitest.d.ts +19 -3
  271. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  272. package/dist/workspace/conformance/writer.d.ts +462 -0
  273. package/dist/workspace/conformance/writer.d.ts.map +1 -0
  274. package/dist/workspace/decide.d.ts +126 -12
  275. package/dist/workspace/decide.d.ts.map +1 -1
  276. package/dist/workspace/decision-points.schema.json +11 -4
  277. package/dist/workspace/declaration.d.ts +156 -4
  278. package/dist/workspace/declaration.d.ts.map +1 -1
  279. package/dist/workspace/declaration.schema.json +383 -5
  280. package/dist/workspace/environments.d.ts +36 -10
  281. package/dist/workspace/environments.d.ts.map +1 -1
  282. package/dist/workspace/factory-rules.d.ts +180 -0
  283. package/dist/workspace/factory-rules.d.ts.map +1 -0
  284. package/dist/workspace/generated-files.d.ts.map +1 -1
  285. package/dist/workspace/graph-cache.d.ts.map +1 -1
  286. package/dist/workspace/graph-cli.d.ts +2 -0
  287. package/dist/workspace/graph-cli.d.ts.map +1 -1
  288. package/dist/workspace/identity.d.ts +111 -0
  289. package/dist/workspace/identity.d.ts.map +1 -0
  290. package/dist/workspace/init.d.ts +21 -0
  291. package/dist/workspace/init.d.ts.map +1 -1
  292. package/dist/workspace/intent-cli.d.ts +7 -4
  293. package/dist/workspace/intent-cli.d.ts.map +1 -1
  294. package/dist/workspace/intent-record.d.ts +36 -2
  295. package/dist/workspace/intent-record.d.ts.map +1 -1
  296. package/dist/workspace/intent.d.ts +249 -8
  297. package/dist/workspace/intent.d.ts.map +1 -1
  298. package/dist/workspace/json-edit.d.ts +24 -0
  299. package/dist/workspace/json-edit.d.ts.map +1 -0
  300. package/dist/workspace/jsonc.d.ts +11 -0
  301. package/dist/workspace/jsonc.d.ts.map +1 -1
  302. package/dist/workspace/kinds.d.ts +66 -4
  303. package/dist/workspace/kinds.d.ts.map +1 -1
  304. package/dist/workspace/lexicon-symbols.d.ts +29 -0
  305. package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
  306. package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
  307. package/dist/workspace/lineage-lock.d.ts +2 -2
  308. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  309. package/dist/workspace/lineage-upgrade.d.ts +31 -2
  310. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  311. package/dist/workspace/links.d.ts.map +1 -1
  312. package/dist/workspace/point-answer.schema.json +42 -2
  313. package/dist/workspace/points-cli.d.ts +10 -3
  314. package/dist/workspace/points-cli.d.ts.map +1 -1
  315. package/dist/workspace/points.d.ts +66 -5
  316. package/dist/workspace/points.d.ts.map +1 -1
  317. package/dist/workspace/principal-classes.d.ts +114 -0
  318. package/dist/workspace/principal-classes.d.ts.map +1 -0
  319. package/dist/workspace/reason-codes.d.ts +53 -4
  320. package/dist/workspace/reason-codes.d.ts.map +1 -1
  321. package/dist/workspace/record-assets.d.ts.map +1 -1
  322. package/dist/workspace/record-sessions.d.ts +5 -7
  323. package/dist/workspace/record-sessions.d.ts.map +1 -1
  324. package/dist/workspace/records-checkout.d.ts +54 -0
  325. package/dist/workspace/records-checkout.d.ts.map +1 -0
  326. package/dist/workspace/records-cli.d.ts +34 -1
  327. package/dist/workspace/records-cli.d.ts.map +1 -1
  328. package/dist/workspace/records-close.d.ts +7 -3
  329. package/dist/workspace/records-close.d.ts.map +1 -1
  330. package/dist/workspace/records-since.d.ts.map +1 -1
  331. package/dist/workspace/records-write.d.ts +68 -7
  332. package/dist/workspace/records-write.d.ts.map +1 -1
  333. package/dist/workspace/records.d.ts +43 -9
  334. package/dist/workspace/records.d.ts.map +1 -1
  335. package/dist/workspace/runs-cli.d.ts +296 -0
  336. package/dist/workspace/runs-cli.d.ts.map +1 -0
  337. package/dist/workspace/runs.d.ts +544 -0
  338. package/dist/workspace/runs.d.ts.map +1 -0
  339. package/dist/workspace/session-kinds.d.ts +1 -1
  340. package/dist/workspace/session-kinds.d.ts.map +1 -1
  341. package/dist/workspace/source-block.d.ts +1 -1
  342. package/dist/workspace/source-block.d.ts.map +1 -1
  343. package/dist/workspace/squash.d.ts +80 -0
  344. package/dist/workspace/squash.d.ts.map +1 -0
  345. package/dist/workspace/status-gates.d.ts +17 -3
  346. package/dist/workspace/status-gates.d.ts.map +1 -1
  347. package/dist/workspace/status.d.ts +64 -0
  348. package/dist/workspace/status.d.ts.map +1 -1
  349. package/dist/workspace/symbols.d.ts +63 -0
  350. package/dist/workspace/symbols.d.ts.map +1 -0
  351. package/dist/workspace/trailer-joins.d.ts +46 -0
  352. package/dist/workspace/trailer-joins.d.ts.map +1 -0
  353. package/dist/workspace/trailers.d.ts +89 -0
  354. package/dist/workspace/trailers.d.ts.map +1 -0
  355. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  356. package/dist/workspace/trust/rotation.d.ts.map +1 -1
  357. package/dist/workspace/trust/run-commits.d.ts +46 -0
  358. package/dist/workspace/trust/run-commits.d.ts.map +1 -0
  359. package/dist/workspace/trust/run-statement.d.ts +128 -0
  360. package/dist/workspace/trust/run-statement.d.ts.map +1 -0
  361. package/dist/workspace/trust/seal.d.ts +38 -0
  362. package/dist/workspace/trust/seal.d.ts.map +1 -1
  363. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  364. package/dist/workspace/trust/verify-cli.d.ts +1 -1
  365. package/dist/workspace/trust/verify.d.ts +16 -2
  366. package/dist/workspace/trust/verify.d.ts.map +1 -1
  367. package/dist/workspace/wip-cli.d.ts +21 -0
  368. package/dist/workspace/wip-cli.d.ts.map +1 -0
  369. package/dist/workspace/wip.d.ts +268 -0
  370. package/dist/workspace/wip.d.ts.map +1 -0
  371. package/dist/workspace/work-cli.d.ts +39 -3
  372. package/dist/workspace/work-cli.d.ts.map +1 -1
  373. package/dist/workspace/work-evidence.d.ts +1 -1
  374. package/dist/workspace/work-evidence.d.ts.map +1 -1
  375. package/dist/workspace/work-size.d.ts +55 -0
  376. package/dist/workspace/work-size.d.ts.map +1 -0
  377. package/dist/workspace/work.d.ts +26 -1
  378. package/dist/workspace/work.d.ts.map +1 -1
  379. package/dist/workspace/workspace-kinds.schema.json +122 -0
  380. package/dist/workspace/workspace-principals.schema.json +60 -0
  381. package/dist/workspace/write-lock-cli.d.ts +60 -0
  382. package/dist/workspace/write-lock-cli.d.ts.map +1 -0
  383. package/dist/workspace/write-lock.d.ts +152 -0
  384. package/dist/workspace/write-lock.d.ts.map +1 -0
  385. package/dist/workspace/write-scope.d.ts +83 -19
  386. package/dist/workspace/write-scope.d.ts.map +1 -1
  387. package/dist/yaml.d.ts +21 -39
  388. package/dist/yaml.d.ts.map +1 -1
  389. package/package.json +7 -2
  390. package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
  391. package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
  392. package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
  393. package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
  394. package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
  395. package/src/__fixtures__/change-set/warden.plan.json +44 -0
  396. package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
  397. package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
  398. package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
  399. package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
  400. package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
  401. package/src/audit/core.test.ts +15 -0
  402. package/src/audit/core.ts +8 -2
  403. package/src/audit/discover.test.ts +11 -0
  404. package/src/audit/discover.ts +7 -2
  405. package/src/audit/prior-art.ts +15 -0
  406. package/src/change-set-bundle.test.ts +57 -0
  407. package/src/change-set.test.ts +215 -0
  408. package/src/change-set.ts +445 -0
  409. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
  410. package/src/cli/commands/audit-opt-in.test.ts +54 -0
  411. package/src/cli/commands/audit.ts +29 -2
  412. package/src/cli/commands/build.test.ts +19 -0
  413. package/src/cli/commands/build.ts +3 -2
  414. package/src/cli/commands/carve-emit-state.test.ts +4 -0
  415. package/src/cli/commands/carve-emit.ts +5 -19
  416. package/src/cli/commands/check-lexicon.test.ts +62 -1
  417. package/src/cli/commands/check-lexicon.ts +36 -6
  418. package/src/cli/commands/import-live.test.ts +18 -0
  419. package/src/cli/commands/import-parser-options.test.ts +133 -0
  420. package/src/cli/commands/import.ts +21 -3
  421. package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
  422. package/src/cli/commands/init.test.ts +8 -1
  423. package/src/cli/commands/init.ts +23 -8
  424. package/src/cli/commands/lint.test.ts +37 -0
  425. package/src/cli/commands/onboard.test.ts +53 -3
  426. package/src/cli/commands/onboard.ts +52 -4
  427. package/src/cli/commands/pinned-upgrade.ts +73 -33
  428. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
  429. package/src/cli/handlers/build.ts +13 -1
  430. package/src/cli/handlers/change-set.test.ts +56 -0
  431. package/src/cli/handlers/change-set.ts +44 -0
  432. package/src/cli/handlers/components.ts +2 -2
  433. package/src/cli/handlers/dev.ts +8 -6
  434. package/src/cli/handlers/fan-out.test.ts +221 -2
  435. package/src/cli/handlers/fan-out.ts +165 -75
  436. package/src/cli/handlers/graph.ts +3 -0
  437. package/src/cli/handlers/lifecycle.test.ts +67 -0
  438. package/src/cli/handlers/lifecycle.ts +6 -5
  439. package/src/cli/handlers/misc.ts +2 -0
  440. package/src/cli/handlers/operator.test.ts +21 -0
  441. package/src/cli/handlers/operator.ts +121 -6
  442. package/src/cli/handlers/pr.ts +373 -0
  443. package/src/cli/handlers/run.test.ts +111 -0
  444. package/src/cli/handlers/run.ts +86 -24
  445. package/src/cli/handlers/scenario.ts +2 -2
  446. package/src/cli/main.test.ts +21 -0
  447. package/src/cli/main.ts +246 -30
  448. package/src/cli/mcp/never-over-mcp.test.ts +101 -0
  449. package/src/cli/mcp/op-tools.ts +24 -2
  450. package/src/cli/mcp/workspace-tools.test.ts +5 -2
  451. package/src/cli/mcp/workspace-tools.ts +62 -7
  452. package/src/cli/registry.ts +74 -3
  453. package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
  454. package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
  455. package/src/codegen/pinned-upgrade.test.ts +104 -0
  456. package/src/codegen/pinned-upgrade.ts +250 -56
  457. package/src/codegen/testdata/postgres-tags.json +242 -0
  458. package/src/components/auto-release.ts +1 -1
  459. package/src/components/capability.ts +55 -0
  460. package/src/components/changed-files.ts +66 -0
  461. package/src/components/cli-support.ts +28 -5
  462. package/src/components/component.schema.json +17 -0
  463. package/src/components/component.ts +25 -0
  464. package/src/components/deploy-units.ts +3 -0
  465. package/src/components/driver.test.ts +52 -0
  466. package/src/components/driver.ts +31 -13
  467. package/src/components/fan-out-output.ts +42 -1
  468. package/src/components/fan-out-record.ts +69 -0
  469. package/src/components/fan-out-run.test.ts +17 -0
  470. package/src/components/fan-out-run.ts +304 -1
  471. package/src/components/fan-out-support.ts +3 -0
  472. package/src/components/fan-out-waves.test.ts +375 -0
  473. package/src/components/fan-out.ts +18 -17
  474. package/src/components/gated-wave-pipeline.ts +82 -0
  475. package/src/components/index.ts +1 -0
  476. package/src/components/layers.ts +30 -0
  477. package/src/components/pr-pipeline.ts +91 -0
  478. package/src/components/pr-run.test.ts +205 -0
  479. package/src/components/pr-run.ts +280 -0
  480. package/src/components/promote.ts +5 -0
  481. package/src/components/verbs/shell.test.ts +11 -0
  482. package/src/components/verbs/shell.ts +7 -3
  483. package/src/components/wave-plan.ts +124 -0
  484. package/src/config.test.ts +21 -0
  485. package/src/config.ts +15 -0
  486. package/src/declarable.test.ts +21 -0
  487. package/src/declarable.ts +19 -0
  488. package/src/discovery/fold-composite.test.ts +41 -5
  489. package/src/discovery/fold-import.test.ts +129 -0
  490. package/src/discovery/fold-import.ts +643 -131
  491. package/src/discovery/fold-package-composite.test.ts +264 -0
  492. package/src/discovery/fold-specifiers.test.ts +191 -0
  493. package/src/discovery/param-deps.test.ts +66 -1
  494. package/src/discovery/param-deps.ts +45 -0
  495. package/src/discovery/sandbox/bundle.ts +1 -1
  496. package/src/discovery/specifier-resolve.ts +344 -0
  497. package/src/fold/fold.test.ts +39 -1
  498. package/src/fold/fold.ts +83 -9
  499. package/src/fold-provenance.test.ts +140 -0
  500. package/src/gated-waves-bundle.test.ts +62 -0
  501. package/src/gated-waves.test.ts +118 -0
  502. package/src/gated-waves.ts +240 -0
  503. package/src/graph-ir.test.ts +83 -0
  504. package/src/graph-ir.ts +29 -0
  505. package/src/import/embedded.test.ts +20 -0
  506. package/src/import/embedded.ts +13 -0
  507. package/src/import/parser-options.ts +46 -0
  508. package/src/import/parser.ts +20 -0
  509. package/src/index.ts +1 -0
  510. package/src/lexicon.ts +106 -3
  511. package/src/lifecycle/gate-ledger.ts +23 -0
  512. package/src/lifecycle/git.ts +102 -16
  513. package/src/lifecycle/observe.test.ts +18 -0
  514. package/src/lifecycle/observe.ts +6 -4
  515. package/src/lifecycle/snapshot.ts +2 -2
  516. package/src/lifecycle/work-lease.test.ts +1 -1
  517. package/src/lifecycle/work-lease.ts +93 -2
  518. package/src/lint/engine.test.ts +55 -0
  519. package/src/lint/engine.ts +30 -4
  520. package/src/lint/output-docs.test.ts +59 -56
  521. package/src/lint/post-synth.test.ts +19 -0
  522. package/src/lint/post-synth.ts +19 -1
  523. package/src/meta/declared-imports.test.ts +1 -1
  524. package/src/op/activities/activity-contracts.ts +84 -0
  525. package/src/op/activities/apply.test.ts +189 -5
  526. package/src/op/activities/apply.ts +230 -8
  527. package/src/op/activities/change-set.ts +114 -0
  528. package/src/op/activities/decide.ts +3 -0
  529. package/src/op/activities/factory.ts +675 -0
  530. package/src/op/activities/index.ts +9 -0
  531. package/src/op/activities/lexicon-upgrade.test.ts +160 -6
  532. package/src/op/activities/lexicon-upgrade.ts +154 -51
  533. package/src/op/activity-contract.test.ts +21 -1
  534. package/src/op/activity-contract.ts +19 -9
  535. package/src/op/builders.ts +23 -0
  536. package/src/op/composites/apply-op.ts +12 -5
  537. package/src/op/composites/composites.test.ts +30 -3
  538. package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
  539. package/src/op/composites/lexicon-upgrade-op.ts +29 -8
  540. package/src/op/decide-backend.ts +5 -1
  541. package/src/op/decide-read-inputs.ts +33 -5
  542. package/src/op/emulator-lifecycle.test.ts +23 -0
  543. package/src/op/emulator-lifecycle.ts +52 -14
  544. package/src/op/factory.e2e.test.ts +232 -0
  545. package/src/op/factory.ts +118 -0
  546. package/src/op/gate-approval.test.ts +74 -0
  547. package/src/op/gate-approval.ts +5 -1
  548. package/src/op/gate.ts +31 -5
  549. package/src/op/index.ts +11 -1
  550. package/src/op/local-executor.test.ts +15 -0
  551. package/src/op/local-executor.ts +40 -12
  552. package/src/op/local-output.ts +1 -1
  553. package/src/op/op-ir.test.ts +9 -0
  554. package/src/op/op-ir.ts +4 -0
  555. package/src/op/op-verb-class.ts +3 -0
  556. package/src/op/operator.ts +4 -0
  557. package/src/op/run-context.test.ts +141 -0
  558. package/src/op/run-context.ts +51 -0
  559. package/src/op/runtimes/local.test.ts +14 -0
  560. package/src/op/runtimes/local.ts +2 -0
  561. package/src/op/steward-beside.ts +2 -0
  562. package/src/op/types.ts +16 -3
  563. package/src/op/work-lease-run.test.ts +47 -0
  564. package/src/op/work-lease-run.ts +76 -11
  565. package/src/plan-summary.test.ts +263 -0
  566. package/src/plan-summary.ts +845 -0
  567. package/src/pr-forge.test.ts +237 -0
  568. package/src/pr-forge.ts +332 -0
  569. package/src/pr-loop-bundle.test.ts +46 -0
  570. package/src/pr-loop.test.ts +171 -0
  571. package/src/pr-loop.ts +324 -0
  572. package/src/provenance.ts +35 -0
  573. package/src/telemetry-attribution.test.ts +23 -1
  574. package/src/telemetry-attribution.ts +51 -0
  575. package/src/terraform/hcl2json.test.ts +21 -0
  576. package/src/terraform/hcl2json.ts +81 -0
  577. package/src/terraform/parse.ts +11 -74
  578. package/src/workspace/agent-cli.ts +7 -3
  579. package/src/workspace/agent.schema.json +22 -0
  580. package/src/workspace/app-kind.test.ts +196 -0
  581. package/src/workspace/box-cli.ts +113 -0
  582. package/src/workspace/box-factory.test.ts +323 -0
  583. package/src/workspace/box-factory.ts +136 -0
  584. package/src/workspace/box-listing-write.schema.json +204 -0
  585. package/src/workspace/box-listing.test.ts +234 -0
  586. package/src/workspace/box-listing.ts +324 -0
  587. package/src/workspace/box-publish.schema.json +498 -0
  588. package/src/workspace/box-publish.test.ts +204 -0
  589. package/src/workspace/box-publish.ts +420 -0
  590. package/src/workspace/box-ship.test.ts +96 -0
  591. package/src/workspace/broker-protocol.schema.json +186 -0
  592. package/src/workspace/broker-protocol.test.ts +122 -0
  593. package/src/workspace/broker-protocol.ts +317 -0
  594. package/src/workspace/builder-tiers.test.ts +146 -0
  595. package/src/workspace/change-set.schema.json +460 -0
  596. package/src/workspace/changes.schema.json +12 -20
  597. package/src/workspace/changes.ts +4 -1
  598. package/src/workspace/chant-migrations.e2e.test.ts +17 -5
  599. package/src/workspace/checks/boxes.test.ts +5 -0
  600. package/src/workspace/checks.ts +39 -8
  601. package/src/workspace/component-environments.test.ts +105 -0
  602. package/src/workspace/compose-graph.ts +7 -0
  603. package/src/workspace/composites.schema.json +23 -4
  604. package/src/workspace/composites.test.ts +8 -8
  605. package/src/workspace/composites.ts +13 -2
  606. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
  607. package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
  608. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
  609. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
  610. package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
  611. package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
  612. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
  613. package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
  614. package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
  615. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
  616. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
  617. package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  618. package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  619. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
  620. package/src/workspace/conformance/broker.test.ts +122 -0
  621. package/src/workspace/conformance/broker.ts +792 -0
  622. package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
  623. package/src/workspace/conformance/index.mjs +51 -3
  624. package/src/workspace/conformance/index.ts +107 -15
  625. package/src/workspace/conformance/vitest.ts +76 -2
  626. package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
  627. package/src/workspace/conformance/writer.test.ts +186 -0
  628. package/src/workspace/conformance/writer.ts +1191 -0
  629. package/src/workspace/decide.test.ts +208 -4
  630. package/src/workspace/decide.ts +433 -73
  631. package/src/workspace/decision-points.schema.json +11 -4
  632. package/src/workspace/declaration.schema.json +383 -5
  633. package/src/workspace/declaration.ts +315 -10
  634. package/src/workspace/environments.ts +66 -14
  635. package/src/workspace/factory-rules.test.ts +62 -0
  636. package/src/workspace/factory-rules.ts +218 -0
  637. package/src/workspace/graph-cli.ts +6 -3
  638. package/src/workspace/graph.schema.json +314 -0
  639. package/src/workspace/identity.test.ts +219 -0
  640. package/src/workspace/identity.ts +186 -0
  641. package/src/workspace/init.ts +82 -2
  642. package/src/workspace/intent-cli.ts +84 -13
  643. package/src/workspace/intent-patch-id.test.ts +162 -0
  644. package/src/workspace/intent-record.schema.json +336 -1
  645. package/src/workspace/intent-record.ts +96 -16
  646. package/src/workspace/intent-reviews.test.ts +76 -0
  647. package/src/workspace/intent-squash.test.ts +213 -0
  648. package/src/workspace/intent-why.test.ts +274 -0
  649. package/src/workspace/intent.schema.json +950 -9
  650. package/src/workspace/intent.test.ts +11 -2
  651. package/src/workspace/intent.ts +722 -65
  652. package/src/workspace/json-edit.test.ts +121 -0
  653. package/src/workspace/json-edit.ts +142 -0
  654. package/src/workspace/jsonc.ts +20 -0
  655. package/src/workspace/kinds.ts +201 -39
  656. package/src/workspace/lexicon-symbols.test.ts +148 -0
  657. package/src/workspace/lexicon-symbols.ts +125 -0
  658. package/src/workspace/lineage-upgrade.test.ts +63 -0
  659. package/src/workspace/lineage-upgrade.ts +146 -5
  660. package/src/workspace/plan-summary.schema.json +155 -0
  661. package/src/workspace/point-answer.schema.json +42 -2
  662. package/src/workspace/points-cli.ts +42 -16
  663. package/src/workspace/points-write.schema.json +163 -4
  664. package/src/workspace/points.schema.json +157 -2
  665. package/src/workspace/points.test.ts +13 -1
  666. package/src/workspace/points.ts +118 -12
  667. package/src/workspace/pr-report.schema.json +95 -0
  668. package/src/workspace/principal-classes.test.ts +175 -0
  669. package/src/workspace/principal-classes.ts +307 -0
  670. package/src/workspace/profiles.test.ts +159 -0
  671. package/src/workspace/read-contract.test.ts +2 -2
  672. package/src/workspace/reason-codes.test.ts +23 -3
  673. package/src/workspace/reason-codes.ts +61 -4
  674. package/src/workspace/record-sessions.ts +9 -8
  675. package/src/workspace/records-amend.schema.json +80 -0
  676. package/src/workspace/records-checkout.ts +106 -0
  677. package/src/workspace/records-cli.ts +123 -17
  678. package/src/workspace/records-close.schema.json +79 -0
  679. package/src/workspace/records-close.ts +31 -7
  680. package/src/workspace/records-concurrent.e2e.test.ts +135 -0
  681. package/src/workspace/records-concurrent.test.ts +145 -0
  682. package/src/workspace/records-formats.test.ts +46 -10
  683. package/src/workspace/records-new.schema.json +9 -0
  684. package/src/workspace/records-review.schema.json +80 -0
  685. package/src/workspace/records-sessions-write.test.ts +69 -0
  686. package/src/workspace/records-sessions.test.ts +22 -0
  687. package/src/workspace/records-uncommitted.test.ts +171 -0
  688. package/src/workspace/records-write.ts +219 -30
  689. package/src/workspace/records.schema.json +88 -1
  690. package/src/workspace/records.ts +76 -8
  691. package/src/workspace/reference-kinds/app/package.json +10 -0
  692. package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
  693. package/src/workspace/run-statement.schema.json +622 -0
  694. package/src/workspace/runs-cli.ts +710 -0
  695. package/src/workspace/runs-statement.test.ts +239 -0
  696. package/src/workspace/runs-write.schema.json +994 -0
  697. package/src/workspace/runs.schema.json +1257 -0
  698. package/src/workspace/runs.test.ts +281 -0
  699. package/src/workspace/runs.ts +970 -0
  700. package/src/workspace/session-kinds.ts +3 -3
  701. package/src/workspace/squash.ts +198 -0
  702. package/src/workspace/status-contract.test.ts +10 -2
  703. package/src/workspace/status-gates.ts +25 -9
  704. package/src/workspace/status.schema.json +252 -4
  705. package/src/workspace/status.ts +110 -1
  706. package/src/workspace/symbols.ts +191 -0
  707. package/src/workspace/trailer-joins.test.ts +171 -0
  708. package/src/workspace/trailer-joins.ts +82 -0
  709. package/src/workspace/trailers.ts +148 -0
  710. package/src/workspace/trust/run-commits.ts +115 -0
  711. package/src/workspace/trust/run-statement.ts +226 -0
  712. package/src/workspace/trust/seal.ts +58 -1
  713. package/src/workspace/trust/verify-cli.ts +6 -5
  714. package/src/workspace/trust/verify.ts +39 -6
  715. package/src/workspace/wip-cli.ts +97 -0
  716. package/src/workspace/wip-write.schema.json +504 -0
  717. package/src/workspace/wip.schema.json +334 -0
  718. package/src/workspace/wip.test.ts +294 -0
  719. package/src/workspace/wip.ts +753 -0
  720. package/src/workspace/work-cli.e2e.test.ts +28 -1
  721. package/src/workspace/work-cli.ts +136 -8
  722. package/src/workspace/work-evidence.schema.json +5 -0
  723. package/src/workspace/work-history.schema.json +73 -1
  724. package/src/workspace/work-history.test.ts +48 -5
  725. package/src/workspace/work-kind-fields.test.ts +154 -0
  726. package/src/workspace/work-lease.schema.json +14 -1
  727. package/src/workspace/work-size.test.ts +77 -0
  728. package/src/workspace/work-size.ts +93 -0
  729. package/src/workspace/work.ts +82 -0
  730. package/src/workspace/workspace-kinds.schema.json +122 -0
  731. package/src/workspace/workspace-principals.schema.json +60 -0
  732. package/src/workspace/write-lock-cli.ts +131 -0
  733. package/src/workspace/write-lock.schema.json +172 -0
  734. package/src/workspace/write-lock.test.ts +189 -0
  735. package/src/workspace/write-lock.ts +474 -0
  736. package/src/workspace/write-scope.test.ts +144 -3
  737. package/src/workspace/write-scope.ts +192 -45
  738. package/src/yaml.test.ts +111 -1
  739. package/src/yaml.ts +141 -549
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Editing one property of a JSON or JSONC document in place (#3308): the
3
+ * rest of the text is left as it was, comments and trailing commas included.
4
+ */
5
+
6
+ import { describe, expect, test } from "vitest";
7
+ import { removeProperty, setProperty, valueAt } from "./json-edit";
8
+ import { parseJsonText } from "./jsonc";
9
+
10
+ const read = (text: string, jsonc = false) => {
11
+ const r = parseJsonText(text, { jsonc });
12
+ if (!r.ok) throw new Error(r.message);
13
+ return r.value;
14
+ };
15
+
16
+ const JSON_TEXT = `{
17
+ "name": "w",
18
+ "members": [
19
+ { "name": "a", "box": { "services": [] } },
20
+ {
21
+ "name": "b",
22
+ "box": {
23
+ "intent": "ws-001"
24
+ }
25
+ }
26
+ ]
27
+ }
28
+ `;
29
+
30
+ const JSONC_TEXT = `{
31
+ // the workspace
32
+ "name": "w",
33
+ "members": [
34
+ {
35
+ "name": "b",
36
+ "box": {
37
+ "listing": {
38
+ "title": "Old", // kept as is
39
+ "line": "one line",
40
+ },
41
+ },
42
+ },
43
+ ],
44
+ }
45
+ `;
46
+
47
+ describe("setProperty", () => {
48
+ test("replaces a value in place and leaves every other byte", () => {
49
+ const out = setProperty(JSON_TEXT, false, "/members/1/box", "intent", "ws-002");
50
+ expect(out).toBe(JSON_TEXT.replace('"ws-001"', '"ws-002"'));
51
+ });
52
+
53
+ test("adds a key after the last one, indented like it, and an object value on its own lines", () => {
54
+ const out = setProperty(JSON_TEXT, false, "/members/1/box", "listing", { title: "B", published: false });
55
+ expect(out).toContain(` "intent": "ws-001",\n "listing": {\n "title": "B",\n "published": false\n }\n }`);
56
+ expect(read(out)).toEqual({ ...(read(JSON_TEXT) as object), members: [{ name: "a", box: { services: [] } }, { name: "b", box: { intent: "ws-001", listing: { title: "B", published: false } } }] });
57
+ });
58
+
59
+ test("keeps an object on one line on one line", () => {
60
+ const out = setProperty(JSON_TEXT, false, "/members/0/box", "listing", { title: "A" });
61
+ expect(out).toContain(`{ "name": "a", "box": { "services": [], "listing": {"title":"A"} } }`);
62
+ expect(valueAt(read(out), "/members/0/box/listing")).toEqual({ title: "A" });
63
+ });
64
+
65
+ test("fills an empty object", () => {
66
+ const out = setProperty('{\n "box": {}\n}\n', false, "/box", "listing", { title: "T" });
67
+ expect(out).toBe('{\n "box": {\n "listing": {\n "title": "T"\n }\n }\n}\n');
68
+ });
69
+
70
+ test("in JSONC, keeps comments with their lines and the trailing comma style", () => {
71
+ const out = setProperty(JSONC_TEXT, true, "/members/0/box/listing", "published", false);
72
+ expect(out).toContain(` "line": "one line",\n "published": false,\n },`);
73
+ const out2 = setProperty(JSONC_TEXT, true, "/members/0/box/listing", "title", "New");
74
+ expect(out2).toBe(JSONC_TEXT.replace('"Old"', '"New"'));
75
+ expect(out2).toContain("// kept as is");
76
+ });
77
+
78
+ test("puts a new key after a comment that ends the last property's line", () => {
79
+ const text = '{\n "a": 1, // one\n "b": 2 // two\n}\n';
80
+ const out = setProperty(text, true, "", "c", 3);
81
+ expect(out).toBe('{\n "a": 1, // one\n "b": 2, // two\n "c": 3\n}\n');
82
+ });
83
+
84
+ test("keeps CRLF line endings", () => {
85
+ const text = '{\r\n "box": {\r\n "intent": "x"\r\n }\r\n}\r\n';
86
+ const out = setProperty(text, false, "/box", "listing", { title: "T" });
87
+ expect(out).toBe('{\r\n "box": {\r\n "intent": "x",\r\n "listing": {\r\n "title": "T"\r\n }\r\n }\r\n}\r\n');
88
+ });
89
+
90
+ test("refuses when there is no object at the pointer", () => {
91
+ expect(() => setProperty(JSON_TEXT, false, "/members/5/box", "listing", {})).toThrow(/no object at \/members\/5\/box/);
92
+ });
93
+ });
94
+
95
+ describe("removeProperty", () => {
96
+ test("removes a key with the comma after it, and its line", () => {
97
+ const text = '{\n "a": 1,\n "b": 2,\n "c": 3\n}\n';
98
+ expect(removeProperty(text, false, "", "b")).toBe('{\n "a": 1,\n "c": 3\n}\n');
99
+ });
100
+
101
+ test("removes the last key with the comma before it", () => {
102
+ const text = '{\n "a": 1,\n "b": 2\n}\n';
103
+ expect(removeProperty(text, false, "", "b")).toBe('{\n "a": 1\n}\n');
104
+ });
105
+
106
+ test("removes a key on a one-line object", () => {
107
+ expect(removeProperty('{ "a": 1, "b": 2 }', false, "", "a")).toBe('{ "b": 2 }');
108
+ expect(removeProperty('{ "a": 1, "b": 2 }', false, "", "b")).toBe('{ "a": 1 }');
109
+ });
110
+
111
+ test("leaves {} when the only key goes, and the text unchanged when the key is not there", () => {
112
+ expect(removeProperty('{\n "box": {\n "listing": {\n "a": 1\n }\n }\n}', false, "/box/listing", "a")).toBe('{\n "box": {\n "listing": {}\n }\n}');
113
+ expect(removeProperty('{ "a": 1 }', false, "", "z")).toBe('{ "a": 1 }');
114
+ });
115
+
116
+ test("in JSONC, removes a key with its trailing comma and keeps the comments of the others", () => {
117
+ const out = removeProperty(JSONC_TEXT, true, "/members/0/box/listing", "line");
118
+ expect(out).toContain(`"title": "Old", // kept as is\n },`);
119
+ expect(valueAt(read(out, true), "/members/0/box/listing")).toEqual({ title: "Old" });
120
+ });
121
+ });
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Edit one property of a JSON or JSONC document in place (#3308), for the
3
+ * write commands that change a field of the workspace declaration.
4
+ *
5
+ * Only the text of the property changed is touched: the rest of the file
6
+ * keeps its indentation, key order, line endings, comments and trailing
7
+ * commas. A new property goes after the last one of its object, indented
8
+ * like it. The caller re-parses the result and compares it with the value it
9
+ * meant to write, so an edit this module gets wrong is never written.
10
+ */
11
+
12
+ import { parseJsonText, pointerToken } from "./jsonc";
13
+
14
+ export class JsonEditError extends Error {
15
+ constructor(message: string) {
16
+ super(message);
17
+ this.name = "JsonEditError";
18
+ }
19
+ }
20
+
21
+ type Parsed = Extract<ReturnType<typeof parseJsonText>, { ok: true }>;
22
+
23
+ function parse(text: string, jsonc: boolean): Parsed {
24
+ const r = parseJsonText(text, { jsonc });
25
+ if (!r.ok) throw new JsonEditError(`the file does not parse: ${r.message} at line ${r.location.line}, column ${r.location.column}`);
26
+ return r;
27
+ }
28
+
29
+ /** The value at a JSON Pointer, or undefined. */
30
+ export function valueAt(root: unknown, pointer: string): unknown {
31
+ if (pointer === "") return root;
32
+ let at: unknown = root;
33
+ for (const raw of pointer.slice(1).split("/")) {
34
+ const token = raw.replace(/~1/g, "/").replace(/~0/g, "~");
35
+ if (at === null || typeof at !== "object") return undefined;
36
+ if (Array.isArray(at)) at = at[Number(token)];
37
+ else at = Object.prototype.hasOwnProperty.call(at, token) ? (at as Record<string, unknown>)[token] : undefined;
38
+ }
39
+ return at;
40
+ }
41
+
42
+ const isObject = (v: unknown): v is Record<string, unknown> => v !== null && typeof v === "object" && !Array.isArray(v);
43
+
44
+ /** The text's line ending, and the indentation one level adds (the first indented line's, else two spaces). */
45
+ function style(text: string): { eol: string; unit: string } {
46
+ const eol = text.includes("\r\n") ? "\r\n" : "\n";
47
+ const m = /\n([ \t]+)\S/.exec(text);
48
+ return { eol, unit: m ? (m[1].startsWith("\t") ? "\t" : m[1]) : " " };
49
+ }
50
+
51
+ function lineStart(text: string, offset: number): number {
52
+ return text.lastIndexOf("\n", offset - 1) + 1;
53
+ }
54
+
55
+ function lineIndent(text: string, offset: number): string {
56
+ const start = lineStart(text, offset);
57
+ return /^[ \t]*/.exec(text.slice(start))![0];
58
+ }
59
+
60
+ /** The offset of the next character after `from` that is not whitespace or a comment. */
61
+ function skipTrivia(text: string, from: number): number {
62
+ let i = from;
63
+ for (;;) {
64
+ const c = text[i];
65
+ if (c === " " || c === "\t" || c === "\n" || c === "\r") i++;
66
+ else if (c === "/" && text[i + 1] === "/") {
67
+ while (i < text.length && text[i] !== "\n") i++;
68
+ } else if (c === "/" && text[i + 1] === "*") {
69
+ const end = text.indexOf("*/", i + 2);
70
+ i = end < 0 ? text.length : end + 2;
71
+ } else return i;
72
+ }
73
+ }
74
+
75
+ function render(value: unknown, indent: string, unit: string, eol: string): string {
76
+ return JSON.stringify(value, null, unit).split("\n").join(eol + indent);
77
+ }
78
+
79
+ /**
80
+ * Set `key` of the object at `objectPointer` to `value`: replace the value's
81
+ * text when the key is there, else add the key after the object's last one.
82
+ * Throws a {@link JsonEditError} when there is no object at the pointer.
83
+ */
84
+ export function setProperty(text: string, jsonc: boolean, objectPointer: string, key: string, value: unknown): string {
85
+ const r = parse(text, jsonc);
86
+ const parent = valueAt(r.value, objectPointer);
87
+ if (!isObject(parent)) throw new JsonEditError(`there is no object at ${objectPointer || "the root"}`);
88
+ const { eol, unit } = style(text);
89
+ const child = r.span(`${objectPointer}/${pointerToken(key)}`);
90
+ if (child) return text.slice(0, child.start) + render(value, lineIndent(text, child.key ?? child.start), unit, eol) + text.slice(child.end);
91
+
92
+ const obj = r.span(objectPointer)!;
93
+ const parentIndent = lineIndent(text, obj.key ?? obj.start);
94
+ const keys = Object.keys(parent);
95
+ if (keys.length === 0) {
96
+ const indent = parentIndent + unit;
97
+ return `${text.slice(0, obj.start)}{${eol}${indent}${JSON.stringify(key)}: ${render(value, indent, unit, eol)}${eol}${parentIndent}}${text.slice(obj.end)}`;
98
+ }
99
+ const last = r.span(`${objectPointer}/${pointerToken(keys[keys.length - 1])}`)!;
100
+ const next = skipTrivia(text, last.end);
101
+ const trailingComma = text[next] === ",";
102
+ if (lineStart(text, last.key!) === lineStart(text, obj.start)) {
103
+ // An object on one line stays on one line.
104
+ const entry = `${JSON.stringify(key)}: ${JSON.stringify(value)}`;
105
+ return trailingComma ? `${text.slice(0, next + 1)} ${entry},${text.slice(next + 1)}` : `${text.slice(0, last.end)}, ${entry}${text.slice(last.end)}`;
106
+ }
107
+ const indent = lineIndent(text, last.key!);
108
+ const after = trailingComma ? next + 1 : last.end;
109
+ // After a comment that ends the last property's line, so the comment stays with it.
110
+ const eolAt = text.indexOf("\n", after);
111
+ const lineEnd = eolAt < 0 ? text.length : text[eolAt - 1] === "\r" ? eolAt - 1 : eolAt;
112
+ const at = /^[ \t]*(\/\/.*)?$/.test(text.slice(after, lineEnd)) ? lineEnd : after;
113
+ const entry = `${eol}${indent}${JSON.stringify(key)}: ${render(value, indent, unit, eol)}`;
114
+ if (trailingComma) return `${text.slice(0, at)}${entry},${text.slice(at)}`;
115
+ return `${text.slice(0, last.end)},${text.slice(last.end, at)}${entry}${text.slice(at)}`;
116
+ }
117
+
118
+ /** Remove `key` from the object at `objectPointer`, with the comma that went with it. Unchanged when the key is not there. */
119
+ export function removeProperty(text: string, jsonc: boolean, objectPointer: string, key: string): string {
120
+ const r = parse(text, jsonc);
121
+ const parent = valueAt(r.value, objectPointer);
122
+ if (!isObject(parent)) throw new JsonEditError(`there is no object at ${objectPointer || "the root"}`);
123
+ const child = r.span(`${objectPointer}/${pointerToken(key)}`);
124
+ if (!child) return text;
125
+ const keys = Object.keys(parent);
126
+ const obj = r.span(objectPointer)!;
127
+ if (keys.length === 1) return `${text.slice(0, obj.start)}{}${text.slice(obj.end)}`;
128
+ const next = skipTrivia(text, child.end);
129
+ if (text[next] === ",") {
130
+ const start = lineStart(text, child.key!);
131
+ const ownLine = /^[ \t]*$/.test(text.slice(start, child.key!));
132
+ let to = next + 1;
133
+ const eolAt = text.indexOf("\n", to);
134
+ if (ownLine && /^[ \t\r]*$/.test(text.slice(to, eolAt < 0 ? text.length : eolAt))) to = eolAt < 0 ? text.length : eolAt + 1;
135
+ else while (text[to] === " ") to++;
136
+ return text.slice(0, ownLine ? start : child.key!) + text.slice(to);
137
+ }
138
+ // The last property, with no trailing comma: remove from the comma after the one before it.
139
+ const prev = r.span(`${objectPointer}/${pointerToken(keys[keys.indexOf(key) - 1])}`)!;
140
+ const comma = skipTrivia(text, prev.end);
141
+ return text.slice(0, comma) + text.slice(child.end);
142
+ }
@@ -31,6 +31,13 @@ export type JsonParseResult =
31
31
  * `key` is set. Falls back to the nearest ancestor that has a position.
32
32
  */
33
33
  locate(pointer: string, key?: boolean): TextLocation;
34
+ /**
35
+ * Where the value at `pointer` is in the text, as offsets: its key's
36
+ * opening quote (null for an array item or the root), the value's first
37
+ * character, and the offset just past its last. Undefined when there is
38
+ * no value at `pointer`. For editing the text in place (#3308).
39
+ */
40
+ span(pointer: string): { key: number | null; start: number; end: number } | undefined;
34
41
  }
35
42
  | { ok: false; message: string; location: TextLocation };
36
43
 
@@ -63,6 +70,7 @@ export function parseJsonText(text: string, options: JsonParseOptions): JsonPars
63
70
  };
64
71
 
65
72
  const values = new Map<string, number>();
73
+ const ends = new Map<string, number>();
66
74
  const keys = new Map<string, number>();
67
75
  let i = text.charCodeAt(0) === 0xfeff ? 1 : 0;
68
76
 
@@ -113,6 +121,12 @@ export function parseJsonText(text: string, options: JsonParseOptions): JsonPars
113
121
  function parseValue(pointer: string): unknown {
114
122
  skip();
115
123
  values.set(pointer, i);
124
+ const value = parseAt(pointer);
125
+ ends.set(pointer, i);
126
+ return value;
127
+ }
128
+
129
+ function parseAt(pointer: string): unknown {
116
130
  const c = text[i];
117
131
  if (c === "{") return parseObject(pointer);
118
132
  if (c === "[") return parseArray(pointer);
@@ -223,6 +237,12 @@ export function parseJsonText(text: string, options: JsonParseOptions): JsonPars
223
237
  if (p === "") return toLocation(0);
224
238
  }
225
239
  },
240
+ span(pointer) {
241
+ const start = values.get(pointer);
242
+ const end = ends.get(pointer);
243
+ if (start === undefined || end === undefined) return undefined;
244
+ return { key: keys.get(pointer) ?? null, start, end };
245
+ },
226
246
  };
227
247
  } catch (err) {
228
248
  if (!(err instanceof JsonSyntaxError)) throw err;
@@ -45,8 +45,34 @@ export interface FileProbe {
45
45
  * `live {` block is found without parsing HCL (#2545).
46
46
  */
47
47
  anyBlock?: { in: string[]; blocks: string[] };
48
+ /**
49
+ * A file directly in the directory whose name matches one of `in` parses
50
+ * as JSON and has a value at one of `pointers`, each a JSON Pointer. This
51
+ * is how an app member's `package.json` with a `start` script is found
52
+ * without claiming every Node package (#3151).
53
+ */
54
+ anyJsonKey?: { in: string[]; pointers: string[] };
55
+ }
56
+
57
+ /** A string, integer or boolean field a kind declares for its members (#3151). */
58
+ export interface ScalarKindField {
59
+ type: "string" | "integer" | "boolean";
60
+ description: string;
61
+ /** The value a member that doesn't set the field gets; null when the kind gives none. */
62
+ default?: string | number | boolean;
63
+ /** For a string field, a regular expression the value must match. */
64
+ pattern?: string;
48
65
  }
49
66
 
67
+ /** An object field: named scalar fields, each with its own default (#3151). */
68
+ export interface ObjectKindField {
69
+ type: "object";
70
+ description: string;
71
+ properties: Record<string, ScalarKindField>;
72
+ }
73
+
74
+ export type KindField = ScalarKindField | ObjectKindField;
75
+
50
76
  /** What a kind's probe checks in a directory. */
51
77
  export type KindProbe =
52
78
  /** Files, or blocks in files, sit directly in the directory. */
@@ -99,6 +125,8 @@ export interface MemberKind {
99
125
  packageDir?: string;
100
126
  /** How `workspace graph` reads a member of this kind (#2874); unset, the member is `kind-not-run`. */
101
127
  graph?: KindGraph;
128
+ /** The fields a member entry of this kind may set, with their defaults (#3151); unset, the kind declares none. */
129
+ fields?: Record<string, KindField>;
102
130
  }
103
131
 
104
132
  export interface KindRegistry {
@@ -187,8 +215,18 @@ export function builtinKindRegistry(): KindRegistry {
187
215
  export function probeKind(kind: MemberKind, tree: WorkspaceTree, dir: string): boolean {
188
216
  if ("directory" in kind.probe) return true;
189
217
  if ("chantProject" in kind.probe) return holdsChantProject(tree, dir);
190
- const { anyFile, anyBlock } = kind.probe;
218
+ const { anyFile, anyBlock, anyJsonKey } = kind.probe;
191
219
  if (anyFile && filesMatching(tree, dir, anyFile).length > 0) return true;
220
+ if (anyJsonKey) {
221
+ for (const file of filesMatching(tree, dir, anyJsonKey.in)) {
222
+ try {
223
+ const json = JSON.parse(tree.read(file)) as unknown;
224
+ if (anyJsonKey.pointers.some((p) => atPointer(json, p) !== undefined)) return true;
225
+ } catch {
226
+ // A file that isn't JSON is no evidence either way.
227
+ }
228
+ }
229
+ }
192
230
  if (anyBlock) {
193
231
  const opener = new RegExp(`^\\s*(?:${anyBlock.blocks.map(escapeRegExp).join("|")})\\s*\\{`, "m");
194
232
  for (const file of filesMatching(tree, dir, anyBlock.in)) {
@@ -227,6 +265,17 @@ function filesMatching(tree: WorkspaceTree, dir: string, names: readonly string[
227
265
  return out.sort();
228
266
  }
229
267
 
268
+ /** The value at JSON Pointer `pointer` in `json`, or undefined when there is none. */
269
+ function atPointer(json: unknown, pointer: string): unknown {
270
+ let at: unknown = json;
271
+ for (const raw of pointer.split("/").slice(1)) {
272
+ const token = raw.replace(/~1/g, "/").replace(/~0/g, "~");
273
+ if (at === null || typeof at !== "object" || !Object.prototype.hasOwnProperty.call(at, token)) return undefined;
274
+ at = (at as Record<string, unknown>)[token];
275
+ }
276
+ return at;
277
+ }
278
+
230
279
  function escapeRegExp(text: string): string {
231
280
  return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
232
281
  }
@@ -337,7 +386,7 @@ export function parseKindData(text: string, source: string): KindData {
337
386
  const problems: string[] = [];
338
387
  const kinds: MemberKind[] = [];
339
388
  const seen = new Set<string>();
340
- for (const k of (raw as { kinds: { name: string; description: string; precedence: number; probe: FileProbe; outputs?: string[]; graph?: KindGraph }[] }).kinds) {
389
+ for (const k of (raw as { kinds: { name: string; description: string; precedence: number; probe: FileProbe; outputs?: string[]; graph?: KindGraph; fields?: Record<string, KindField> }[] }).kinds) {
341
390
  if (BUILTIN_KIND_NAMES.includes(k.name)) {
342
391
  problems.push(`${source}: kind ${k.name} is built in and can't be supplied by a package`);
343
392
  continue;
@@ -353,13 +402,16 @@ export function parseKindData(text: string, source: string): KindData {
353
402
  probe: {
354
403
  ...(k.probe.anyFile ? { anyFile: [...k.probe.anyFile] } : {}),
355
404
  ...(k.probe.anyBlock ? { anyBlock: { in: [...k.probe.anyBlock.in], blocks: [...k.probe.anyBlock.blocks] } } : {}),
405
+ ...(k.probe.anyJsonKey ? { anyJsonKey: { in: [...k.probe.anyJsonKey.in], pointers: [...k.probe.anyJsonKey.pointers] } } : {}),
356
406
  },
357
407
  precedence: k.precedence,
358
408
  shape: "member",
359
409
  outputs: { from: "declared", names: [...(k.outputs ?? [])] },
360
410
  source,
361
411
  ...(k.graph ? { graph: { lexicon: k.graph.lexicon, config: structuredClone(k.graph.config) } } : {}),
412
+ ...(k.fields ? { fields: structuredClone(k.fields) } : {}),
362
413
  });
414
+ for (const problem of fieldDefaultProblems(k.fields ?? {})) problems.push(`${source}: kind ${k.name} ${problem}`);
363
415
  }
364
416
  return { kinds, problems };
365
417
  }
@@ -370,14 +422,15 @@ export interface PackageKinds extends KindData {
370
422
  }
371
423
 
372
424
  /**
373
- * Where a package's `exports` send `./workspace-kinds`, or undefined when
374
- * the package doesn't export that subpath. Only the literal key counts: a
375
- * `./*` pattern maps the subpath to code, which chant never runs for kinds.
425
+ * Where a package's `exports` send `./workspace-kinds` (or another data
426
+ * subpath, such as `./workspace-principals`), or undefined when the package
427
+ * doesn't export it. Only the literal key counts: a `./*` pattern maps the
428
+ * subpath to code, which chant never runs for plugin data.
376
429
  */
377
- export function kindsExportTarget(pkg: Record<string, unknown>): string | undefined | { problem: string } {
430
+ export function kindsExportTarget(pkg: Record<string, unknown>, subpath: string = KINDS_SUBPATH): string | undefined | { problem: string } {
378
431
  const exports = pkg.exports;
379
432
  if (!exports || typeof exports !== "object" || Array.isArray(exports)) return undefined;
380
- const entry = (exports as Record<string, unknown>)[KINDS_SUBPATH];
433
+ const entry = (exports as Record<string, unknown>)[subpath];
381
434
  if (entry === undefined) return undefined;
382
435
  let target: unknown = entry;
383
436
  if (target && typeof target === "object" && !Array.isArray(target)) {
@@ -385,10 +438,10 @@ export function kindsExportTarget(pkg: Record<string, unknown>): string | undefi
385
438
  target = conditions.default ?? conditions.import ?? conditions.require;
386
439
  }
387
440
  if (typeof target !== "string") {
388
- return { problem: `exports["${KINDS_SUBPATH}"] must name one file, as a string or a "default" condition` };
441
+ return { problem: `exports["${subpath}"] must name one file, as a string or a "default" condition` };
389
442
  }
390
443
  if (!target.startsWith("./") || !target.endsWith(".json")) {
391
- return { problem: `exports["${KINDS_SUBPATH}"] is ${target}; it must name a .json file inside the package, since chant reads kinds as data and never runs a package's code` };
444
+ return { problem: `exports["${subpath}"] is ${target}; it must name a .json file inside the package, since chant reads plugin data as data and never runs a package's code` };
392
445
  }
393
446
  return target;
394
447
  }
@@ -499,6 +552,37 @@ export interface LoadedKinds {
499
552
  problems: KindLoadProblem[];
500
553
  }
501
554
 
555
+ /**
556
+ * The directory a pin's plugin data is read from: an installed package at
557
+ * the pinned version, looked up from `workspaceRoot`, or a path pin's
558
+ * directory, checked against its integrity digest when it has one. Null for
559
+ * a pin that names neither. Shared by the kinds and the principal classes
560
+ * (#3080), so both read a pin the same way.
561
+ */
562
+ export function pinnedPackageDir(pin: PinLike, workspaceRoot: string): { dir: string; source: string } | { problem: string } | null {
563
+ if (pin.package) {
564
+ const dir = findInstalledPackage(pin.package, workspaceRoot);
565
+ if (!dir) return { problem: `pinned package ${pin.package} is not installed; install it to read the kinds it supplies` };
566
+ let installed: unknown;
567
+ try {
568
+ installed = (JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")) as { version?: unknown }).version;
569
+ } catch {
570
+ installed = undefined;
571
+ }
572
+ if (pin.version && installed !== pin.version) return { problem: `${pin.package} is pinned at ${pin.version}, and ${String(installed ?? "an unknown version")} is installed` };
573
+ return { dir, source: pin.package };
574
+ }
575
+ if (pin.path) {
576
+ const dir = join(workspaceRoot, ...pin.path.split("/"));
577
+ if (pin.integrity) {
578
+ const checked = checkPinIntegrity(dir, pin.integrity, pin.path);
579
+ if (!checked.ok) return { problem: checked.message };
580
+ }
581
+ return { dir, source: pin.path };
582
+ }
583
+ return null;
584
+ }
585
+
502
586
  /**
503
587
  * Build the registry for a workspace: the built-in kinds plus the kinds
504
588
  * every pin publishes. `workspaceRoot` is the absolute workspace root; a
@@ -514,38 +598,13 @@ export function loadKindRegistry(pins: readonly PinLike[], workspaceRoot: string
514
598
  const owner = new Map<string, string>();
515
599
  const clashing = new Set<string>();
516
600
  pins.forEach((pin, i) => {
517
- let dir: string | undefined;
518
- let source: string;
519
- if (pin.package) {
520
- source = pin.package;
521
- dir = findInstalledPackage(pin.package, workspaceRoot);
522
- if (!dir) {
523
- problems.push({ pin: i, message: `pinned package ${pin.package} is not installed; install it to read the kinds it supplies` });
524
- return;
525
- }
526
- let installed: unknown;
527
- try {
528
- installed = (JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")) as { version?: unknown }).version;
529
- } catch {
530
- installed = undefined;
531
- }
532
- if (pin.version && installed !== pin.version) {
533
- problems.push({ pin: i, message: `${pin.package} is pinned at ${pin.version}, and ${String(installed ?? "an unknown version")} is installed` });
534
- return;
535
- }
536
- } else if (pin.path) {
537
- source = pin.path;
538
- dir = join(workspaceRoot, ...pin.path.split("/"));
539
- if (pin.integrity) {
540
- const checked = checkPinIntegrity(dir, pin.integrity, pin.path);
541
- if (!checked.ok) {
542
- problems.push({ pin: i, message: checked.message });
543
- return;
544
- }
545
- }
546
- } else {
601
+ const found = pinnedPackageDir(pin, workspaceRoot);
602
+ if (found === null) return;
603
+ if ("problem" in found) {
604
+ problems.push({ pin: i, message: found.problem });
547
605
  return;
548
606
  }
607
+ const { dir, source } = found;
549
608
  const read = readPackageKinds(dir, source);
550
609
  for (const p of read.problems) problems.push({ pin: i, message: p });
551
610
  for (const k of read.kinds) {
@@ -583,3 +642,106 @@ export function kindsFileShips(packageDir: string, file: string): boolean {
583
642
  return rel === e || rel.startsWith(`${e}/`);
584
643
  });
585
644
  }
645
+
646
+ // ── Member fields (#3151) ────────────────────────────────────────────────────
647
+
648
+ /** A value a member sets, or a kind's default: what a scalar field holds. */
649
+ export type FieldValue = string | number | boolean;
650
+
651
+ /** Why a value doesn't fit `field`, phrased to follow "the value", or undefined when it fits. */
652
+ function scalarProblem(field: ScalarKindField, value: unknown): string | undefined {
653
+ const ok = field.type === "integer" ? typeof value === "number" && Number.isInteger(value) : typeof value === field.type;
654
+ if (!ok) return `is ${JSON.stringify(value)}, and the field is ${field.type === "integer" ? "an integer" : `a ${field.type}`}`;
655
+ if (field.pattern !== undefined && typeof value === "string") {
656
+ let re: RegExp;
657
+ try {
658
+ re = new RegExp(field.pattern, "u");
659
+ } catch {
660
+ return undefined; // Reported once, against the kind, by fieldDefaultProblems.
661
+ }
662
+ if (!re.test(value)) return `is ${JSON.stringify(value)}, which does not match ${field.pattern}`;
663
+ }
664
+ return undefined;
665
+ }
666
+
667
+ /** What is wrong with a kind's own field declarations: a pattern that isn't a regular expression, or a default of the wrong type. */
668
+ function fieldDefaultProblems(fields: Record<string, KindField>): string[] {
669
+ const out: string[] = [];
670
+ const scalar = (name: string, f: ScalarKindField) => {
671
+ if (f.pattern !== undefined) {
672
+ try {
673
+ new RegExp(f.pattern, "u");
674
+ } catch {
675
+ out.push(`declares field ${name} with pattern ${f.pattern}, which is not a regular expression`);
676
+ return;
677
+ }
678
+ }
679
+ if (f.default === undefined) return;
680
+ const problem = scalarProblem(f, f.default);
681
+ if (problem) out.push(`declares field ${name} whose default ${problem}`);
682
+ };
683
+ for (const [name, f] of Object.entries(fields)) {
684
+ if (f.type === "object") for (const [inner, g] of Object.entries(f.properties)) scalar(`${name}.${inner}`, g);
685
+ else scalar(name, f);
686
+ }
687
+ return out;
688
+ }
689
+
690
+ /** One problem with a member's fields: the field's path under `fields` (`scripts/start`), and why. */
691
+ export interface MemberFieldProblem {
692
+ path: string;
693
+ message: string;
694
+ }
695
+
696
+ export interface MemberFields {
697
+ /** Every field the kind declares, set from the entry or its default (null when it has none); null when the kind declares no fields. */
698
+ fields: Record<string, FieldValue | null | Record<string, FieldValue | null>> | null;
699
+ problems: MemberFieldProblem[];
700
+ }
701
+
702
+ /**
703
+ * A member's fields (#3151): the ones its entry sets, checked against what
704
+ * its kind declares, with every other declared field at its default. A field
705
+ * the kind doesn't declare, or a value of the wrong type, is a problem, and
706
+ * the field reads as its default. A kind no registry knows has no fields to
707
+ * check against, so it reads as null with no problem (WSP003 reports it).
708
+ */
709
+ export function resolveMemberFields(kind: MemberKind | undefined, given: Record<string, unknown> | null): MemberFields {
710
+ if (kind === undefined) return { fields: null, problems: [] };
711
+ const declared = kind.fields;
712
+ const problems: MemberFieldProblem[] = [];
713
+ if (declared === undefined) {
714
+ if (given !== null) problems.push({ path: "", message: `kind ${kind.name} declares no fields, and the entry sets ${Object.keys(given).join(", ") || "an empty fields block"}` });
715
+ return { fields: null, problems };
716
+ }
717
+ const set = given ?? {};
718
+ for (const name of Object.keys(set)) {
719
+ if (!(name in declared)) problems.push({ path: name, message: `kind ${kind.name} declares no field ${name}; its fields are ${Object.keys(declared).join(", ")}` });
720
+ }
721
+ const scalar = (path: string, field: ScalarKindField, value: unknown): FieldValue | null => {
722
+ if (value !== undefined) {
723
+ const problem = scalarProblem(field, value);
724
+ if (!problem) return value as FieldValue;
725
+ problems.push({ path, message: `field ${path.replace("/", ".")} ${problem}` });
726
+ }
727
+ return field.default ?? null;
728
+ };
729
+ const fields: NonNullable<MemberFields["fields"]> = {};
730
+ for (const [name, field] of Object.entries(declared)) {
731
+ if (field.type !== "object") {
732
+ fields[name] = scalar(name, field, set[name]);
733
+ continue;
734
+ }
735
+ const raw = set[name];
736
+ let inner: Record<string, unknown> = {};
737
+ if (raw !== undefined) {
738
+ if (raw !== null && typeof raw === "object" && !Array.isArray(raw)) inner = raw as Record<string, unknown>;
739
+ else problems.push({ path: name, message: `field ${name} is ${JSON.stringify(raw)}, and the field is an object` });
740
+ }
741
+ for (const key of Object.keys(inner)) {
742
+ if (!(key in field.properties)) problems.push({ path: `${name}/${key}`, message: `kind ${kind.name} declares no field ${name}.${key}; ${name} has ${Object.keys(field.properties).join(", ")}` });
743
+ }
744
+ fields[name] = Object.fromEntries(Object.entries(field.properties).map(([key, f]) => [key, scalar(`${name}/${key}`, f, inner[key])]));
745
+ }
746
+ return { fields, problems };
747
+ }