@intentius/chant 0.100.0 → 0.102.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 (608) 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/discover.d.ts.map +1 -1
  4. package/dist/audit/nginx.d.ts.map +1 -1
  5. package/dist/audit/prior-art.d.ts +48 -0
  6. package/dist/audit/prior-art.d.ts.map +1 -1
  7. package/dist/behaviour-kinds.d.ts.map +1 -1
  8. package/dist/build.d.ts +6 -0
  9. package/dist/build.d.ts.map +1 -1
  10. package/dist/builder.d.ts.map +1 -1
  11. package/dist/cli/build-options.d.ts +2 -0
  12. package/dist/cli/build-options.d.ts.map +1 -1
  13. package/dist/cli/commands/build.d.ts.map +1 -1
  14. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  15. package/dist/cli/commands/check-lexicon.d.ts +16 -0
  16. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  17. package/dist/cli/commands/import.d.ts +8 -0
  18. package/dist/cli/commands/import.d.ts.map +1 -1
  19. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  20. package/dist/cli/commands/init.d.ts +19 -0
  21. package/dist/cli/commands/init.d.ts.map +1 -1
  22. package/dist/cli/commands/onboard.d.ts +9 -0
  23. package/dist/cli/commands/onboard.d.ts.map +1 -1
  24. package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
  25. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
  26. package/dist/cli/handlers/dev.d.ts.map +1 -1
  27. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  28. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  29. package/dist/cli/handlers/misc.d.ts.map +1 -1
  30. package/dist/cli/handlers/operator.d.ts +9 -0
  31. package/dist/cli/handlers/operator.d.ts.map +1 -1
  32. package/dist/cli/handlers/run.d.ts.map +1 -1
  33. package/dist/cli/lsp/server.d.ts.map +1 -1
  34. package/dist/cli/main.d.ts.map +1 -1
  35. package/dist/cli/mcp/server.d.ts.map +1 -1
  36. package/dist/cli/mcp/tools/build.d.ts.map +1 -1
  37. package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
  38. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  39. package/dist/cli/mcp/tools/import.d.ts.map +1 -1
  40. package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
  41. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
  42. package/dist/cli/mcp/tools/search.d.ts.map +1 -1
  43. package/dist/cli/mcp/workspace-tools.d.ts +9 -1
  44. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  45. package/dist/cli/registry.d.ts +33 -2
  46. package/dist/cli/registry.d.ts.map +1 -1
  47. package/dist/codegen/fetch.d.ts.map +1 -1
  48. package/dist/codegen/naming.d.ts.map +1 -1
  49. package/dist/codegen/pinned-upgrade.d.ts +67 -3
  50. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  51. package/dist/codegen/registry.d.ts.map +1 -1
  52. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  53. package/dist/components/capability.d.ts.map +1 -1
  54. package/dist/components/driver.d.ts.map +1 -1
  55. package/dist/components/fan-out.d.ts.map +1 -1
  56. package/dist/components/starter-plugin.d.ts.map +1 -1
  57. package/dist/components/verbs/process-runner.d.ts.map +1 -1
  58. package/dist/components/verbs/r2-sync.d.ts.map +1 -1
  59. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  60. package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
  61. package/dist/components/verbs/sign.d.ts.map +1 -1
  62. package/dist/components/verbs/verify.d.ts.map +1 -1
  63. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  64. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  65. package/dist/components/verbs/wrangler.d.ts.map +1 -1
  66. package/dist/composite.d.ts.map +1 -1
  67. package/dist/config.d.ts +30 -7
  68. package/dist/config.d.ts.map +1 -1
  69. package/dist/declarable.d.ts +16 -0
  70. package/dist/declarable.d.ts.map +1 -1
  71. package/dist/discovery/cache.d.ts.map +1 -1
  72. package/dist/discovery/fold-import.d.ts +15 -5
  73. package/dist/discovery/fold-import.d.ts.map +1 -1
  74. package/dist/discovery/param-deps.d.ts +16 -0
  75. package/dist/discovery/param-deps.d.ts.map +1 -1
  76. package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
  77. package/dist/discovery/specifier-resolve.d.ts +37 -0
  78. package/dist/discovery/specifier-resolve.d.ts.map +1 -0
  79. package/dist/errors.d.ts.map +1 -1
  80. package/dist/fold/fold.d.ts +3 -1
  81. package/dist/fold/fold.d.ts.map +1 -1
  82. package/dist/graph-detail.d.ts.map +1 -1
  83. package/dist/graph-ir.d.ts.map +1 -1
  84. package/dist/graph-layout.d.ts.map +1 -1
  85. package/dist/import/base-parser.d.ts.map +1 -1
  86. package/dist/import/embedded.d.ts +7 -0
  87. package/dist/import/embedded.d.ts.map +1 -1
  88. package/dist/import/parser-options.d.ts +14 -0
  89. package/dist/import/parser-options.d.ts.map +1 -0
  90. package/dist/import/parser.d.ts +17 -0
  91. package/dist/import/parser.d.ts.map +1 -1
  92. package/dist/kubectl-context.d.ts.map +1 -1
  93. package/dist/lexicon-output.d.ts.map +1 -1
  94. package/dist/lexicon-schema.d.ts +3 -3
  95. package/dist/lexicon.d.ts +78 -3
  96. package/dist/lexicon.d.ts.map +1 -1
  97. package/dist/lifecycle/assert-live.d.ts.map +1 -1
  98. package/dist/lifecycle/gate-ledger.d.ts +15 -0
  99. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  100. package/dist/lifecycle/git.d.ts.map +1 -1
  101. package/dist/lifecycle/member-ledger.d.ts.map +1 -1
  102. package/dist/lifecycle/observe.d.ts.map +1 -1
  103. package/dist/lifecycle/plan-digest.d.ts +26 -5
  104. package/dist/lifecycle/plan-digest.d.ts.map +1 -1
  105. package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
  106. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  107. package/dist/lifecycle/scenario.d.ts.map +1 -1
  108. package/dist/lifecycle/status.d.ts.map +1 -1
  109. package/dist/lifecycle/work-lease.d.ts +61 -2
  110. package/dist/lifecycle/work-lease.d.ts.map +1 -1
  111. package/dist/lint/config.d.ts +4 -4
  112. package/dist/lint/engine.d.ts +6 -0
  113. package/dist/lint/engine.d.ts.map +1 -1
  114. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  115. package/dist/op/activities/activity-contracts.d.ts +12 -11
  116. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  117. package/dist/op/activities/apply.d.ts +79 -9
  118. package/dist/op/activities/apply.d.ts.map +1 -1
  119. package/dist/op/activities/decide.d.ts.map +1 -1
  120. package/dist/op/activities/index.d.ts +1 -1
  121. package/dist/op/activities/index.d.ts.map +1 -1
  122. package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
  123. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
  124. package/dist/op/activities/propose-upgrade.d.ts +2 -0
  125. package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
  126. package/dist/op/activity-contract.d.ts +1 -1
  127. package/dist/op/activity-failure.d.ts.map +1 -1
  128. package/dist/op/activity-profiles.d.ts.map +1 -1
  129. package/dist/op/builders.d.ts.map +1 -1
  130. package/dist/op/composites/apply-op.d.ts +12 -5
  131. package/dist/op/composites/apply-op.d.ts.map +1 -1
  132. package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
  133. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
  134. package/dist/op/decide-backend.d.ts.map +1 -1
  135. package/dist/op/decide-read-inputs.d.ts.map +1 -1
  136. package/dist/op/emulator-lifecycle.d.ts +21 -2
  137. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  138. package/dist/op/gate-approval.d.ts +5 -1
  139. package/dist/op/gate-approval.d.ts.map +1 -1
  140. package/dist/op/gate-wait.d.ts.map +1 -1
  141. package/dist/op/gate.d.ts +19 -3
  142. package/dist/op/gate.d.ts.map +1 -1
  143. package/dist/op/index.d.ts +3 -1
  144. package/dist/op/index.d.ts.map +1 -1
  145. package/dist/op/local-executor.d.ts +6 -0
  146. package/dist/op/local-executor.d.ts.map +1 -1
  147. package/dist/op/operator.d.ts.map +1 -1
  148. package/dist/op/run-context.d.ts +39 -0
  149. package/dist/op/run-context.d.ts.map +1 -0
  150. package/dist/op/run-live.d.ts.map +1 -1
  151. package/dist/op/runtimes/local.d.ts.map +1 -1
  152. package/dist/op/source-archive.d.ts.map +1 -1
  153. package/dist/op/steward-beside.d.ts.map +1 -1
  154. package/dist/op/steward-points.d.ts.map +1 -1
  155. package/dist/op/steward.d.ts.map +1 -1
  156. package/dist/op/types.d.ts +8 -3
  157. package/dist/op/types.d.ts.map +1 -1
  158. package/dist/op/work-lease-run.d.ts +24 -4
  159. package/dist/op/work-lease-run.d.ts.map +1 -1
  160. package/dist/project-root.d.ts.map +1 -1
  161. package/dist/provenance.d.ts +21 -0
  162. package/dist/provenance.d.ts.map +1 -1
  163. package/dist/pseudo-parameter.d.ts.map +1 -1
  164. package/dist/reconcile.d.ts.map +1 -1
  165. package/dist/secret-materialization.d.ts.map +1 -1
  166. package/dist/serializer.d.ts +8 -0
  167. package/dist/serializer.d.ts.map +1 -1
  168. package/dist/telemetry-attribution.d.ts +77 -0
  169. package/dist/telemetry-attribution.d.ts.map +1 -0
  170. package/dist/terraform/emit-source.d.ts.map +1 -1
  171. package/dist/terraform/parse.d.ts.map +1 -1
  172. package/dist/testing.d.ts.map +1 -1
  173. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
  174. package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
  175. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
  176. package/dist/workspace/agent-cli.d.ts +88 -0
  177. package/dist/workspace/agent-cli.d.ts.map +1 -0
  178. package/dist/workspace/box-factory.d.ts +73 -0
  179. package/dist/workspace/box-factory.d.ts.map +1 -0
  180. package/dist/workspace/changes-cli.d.ts.map +1 -1
  181. package/dist/workspace/changes.d.ts +8 -1
  182. package/dist/workspace/changes.d.ts.map +1 -1
  183. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
  184. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  185. package/dist/workspace/checks/links.d.ts +1 -0
  186. package/dist/workspace/checks/links.d.ts.map +1 -1
  187. package/dist/workspace/checks/live.d.ts +40 -0
  188. package/dist/workspace/checks/live.d.ts.map +1 -0
  189. package/dist/workspace/checks.d.ts +26 -2
  190. package/dist/workspace/checks.d.ts.map +1 -1
  191. package/dist/workspace/compose-graph.d.ts +73 -0
  192. package/dist/workspace/compose-graph.d.ts.map +1 -1
  193. package/dist/workspace/conformance/index.d.ts +67 -6
  194. package/dist/workspace/conformance/index.d.ts.map +1 -1
  195. package/dist/workspace/conformance/vitest.d.ts +12 -3
  196. package/dist/workspace/conformance/vitest.d.ts.map +1 -1
  197. package/dist/workspace/conformance/writer.d.ts +368 -0
  198. package/dist/workspace/conformance/writer.d.ts.map +1 -0
  199. package/dist/workspace/decide.d.ts +1 -1
  200. package/dist/workspace/decide.d.ts.map +1 -1
  201. package/dist/workspace/declaration.d.ts +119 -0
  202. package/dist/workspace/declaration.d.ts.map +1 -1
  203. package/dist/workspace/declaration.schema.json +368 -4
  204. package/dist/workspace/export-cli.d.ts +12 -0
  205. package/dist/workspace/export-cli.d.ts.map +1 -0
  206. package/dist/workspace/export.d.ts +145 -0
  207. package/dist/workspace/export.d.ts.map +1 -0
  208. package/dist/workspace/generated-files.d.ts.map +1 -1
  209. package/dist/workspace/graph-cache.d.ts.map +1 -1
  210. package/dist/workspace/graph-cli.d.ts +2 -0
  211. package/dist/workspace/graph-cli.d.ts.map +1 -1
  212. package/dist/workspace/identity.d.ts +111 -0
  213. package/dist/workspace/identity.d.ts.map +1 -0
  214. package/dist/workspace/import.d.ts +73 -0
  215. package/dist/workspace/import.d.ts.map +1 -0
  216. package/dist/workspace/intent-cli.d.ts +7 -4
  217. package/dist/workspace/intent-cli.d.ts.map +1 -1
  218. package/dist/workspace/intent-record.d.ts +8 -1
  219. package/dist/workspace/intent-record.d.ts.map +1 -1
  220. package/dist/workspace/intent.d.ts +149 -5
  221. package/dist/workspace/intent.d.ts.map +1 -1
  222. package/dist/workspace/kinds.d.ts +24 -6
  223. package/dist/workspace/kinds.d.ts.map +1 -1
  224. package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
  225. package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
  226. package/dist/workspace/lineage-adopt.d.ts +106 -0
  227. package/dist/workspace/lineage-adopt.d.ts.map +1 -0
  228. package/dist/workspace/lineage-check.d.ts +9 -2
  229. package/dist/workspace/lineage-check.d.ts.map +1 -1
  230. package/dist/workspace/lineage-cli.d.ts +6 -1
  231. package/dist/workspace/lineage-cli.d.ts.map +1 -1
  232. package/dist/workspace/lineage-hash-index.d.ts +110 -0
  233. package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
  234. package/dist/workspace/lineage-init.d.ts +10 -0
  235. package/dist/workspace/lineage-init.d.ts.map +1 -1
  236. package/dist/workspace/lineage-lock.d.ts +149 -2
  237. package/dist/workspace/lineage-lock.d.ts.map +1 -1
  238. package/dist/workspace/lineage-migrations.d.ts +15 -3
  239. package/dist/workspace/lineage-migrations.d.ts.map +1 -1
  240. package/dist/workspace/lineage-provenance.d.ts +18 -0
  241. package/dist/workspace/lineage-provenance.d.ts.map +1 -0
  242. package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
  243. package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
  244. package/dist/workspace/lineage-upgrade.d.ts +30 -1
  245. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  246. package/dist/workspace/lineage-versions.d.ts +116 -0
  247. package/dist/workspace/lineage-versions.d.ts.map +1 -0
  248. package/dist/workspace/links.d.ts +31 -5
  249. package/dist/workspace/links.d.ts.map +1 -1
  250. package/dist/workspace/ls-generated.d.ts +37 -0
  251. package/dist/workspace/ls-generated.d.ts.map +1 -0
  252. package/dist/workspace/ls.d.ts +4 -0
  253. package/dist/workspace/ls.d.ts.map +1 -1
  254. package/dist/workspace/member-commands.d.ts.map +1 -1
  255. package/dist/workspace/nested-graph.d.ts +56 -0
  256. package/dist/workspace/nested-graph.d.ts.map +1 -0
  257. package/dist/workspace/nesting.d.ts +21 -0
  258. package/dist/workspace/nesting.d.ts.map +1 -0
  259. package/dist/workspace/pin-cli.d.ts +10 -0
  260. package/dist/workspace/pin-cli.d.ts.map +1 -0
  261. package/dist/workspace/pin-integrity.d.ts +51 -0
  262. package/dist/workspace/pin-integrity.d.ts.map +1 -0
  263. package/dist/workspace/points.d.ts.map +1 -1
  264. package/dist/workspace/principal-classes.d.ts +114 -0
  265. package/dist/workspace/principal-classes.d.ts.map +1 -0
  266. package/dist/workspace/reason-codes.d.ts +47 -3
  267. package/dist/workspace/reason-codes.d.ts.map +1 -1
  268. package/dist/workspace/record-assets.d.ts.map +1 -1
  269. package/dist/workspace/record-sessions.d.ts +7 -11
  270. package/dist/workspace/record-sessions.d.ts.map +1 -1
  271. package/dist/workspace/records-checkout.d.ts +54 -0
  272. package/dist/workspace/records-checkout.d.ts.map +1 -0
  273. package/dist/workspace/records-cli.d.ts +57 -2
  274. package/dist/workspace/records-cli.d.ts.map +1 -1
  275. package/dist/workspace/records-close.d.ts +5 -2
  276. package/dist/workspace/records-close.d.ts.map +1 -1
  277. package/dist/workspace/records-since.d.ts.map +1 -1
  278. package/dist/workspace/records-write.d.ts +23 -4
  279. package/dist/workspace/records-write.d.ts.map +1 -1
  280. package/dist/workspace/records.d.ts +58 -5
  281. package/dist/workspace/records.d.ts.map +1 -1
  282. package/dist/workspace/returns.d.ts +129 -0
  283. package/dist/workspace/returns.d.ts.map +1 -0
  284. package/dist/workspace/runs-cli.d.ts +164 -0
  285. package/dist/workspace/runs-cli.d.ts.map +1 -0
  286. package/dist/workspace/runs.d.ts +423 -0
  287. package/dist/workspace/runs.d.ts.map +1 -0
  288. package/dist/workspace/source-block.d.ts +1 -1
  289. package/dist/workspace/source-block.d.ts.map +1 -1
  290. package/dist/workspace/status-gates.d.ts +15 -3
  291. package/dist/workspace/status-gates.d.ts.map +1 -1
  292. package/dist/workspace/status.d.ts +10 -0
  293. package/dist/workspace/status.d.ts.map +1 -1
  294. package/dist/workspace/symbols.d.ts +52 -0
  295. package/dist/workspace/symbols.d.ts.map +1 -0
  296. package/dist/workspace/template-manifest.d.ts +11 -3
  297. package/dist/workspace/template-manifest.d.ts.map +1 -1
  298. package/dist/workspace/trailer-joins.d.ts +46 -0
  299. package/dist/workspace/trailer-joins.d.ts.map +1 -0
  300. package/dist/workspace/trailers.d.ts +89 -0
  301. package/dist/workspace/trailers.d.ts.map +1 -0
  302. package/dist/workspace/trust/attestor.d.ts +8 -0
  303. package/dist/workspace/trust/attestor.d.ts.map +1 -1
  304. package/dist/workspace/trust/dsse.d.ts +58 -0
  305. package/dist/workspace/trust/dsse.d.ts.map +1 -0
  306. package/dist/workspace/trust/evidence-cli.d.ts +66 -0
  307. package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
  308. package/dist/workspace/trust/evidence.d.ts +93 -0
  309. package/dist/workspace/trust/evidence.d.ts.map +1 -0
  310. package/dist/workspace/trust/policy.d.ts +54 -1
  311. package/dist/workspace/trust/policy.d.ts.map +1 -1
  312. package/dist/workspace/trust/provenance.d.ts +21 -1
  313. package/dist/workspace/trust/provenance.d.ts.map +1 -1
  314. package/dist/workspace/trust/rotation.d.ts +132 -0
  315. package/dist/workspace/trust/rotation.d.ts.map +1 -0
  316. package/dist/workspace/trust/seal.d.ts +33 -0
  317. package/dist/workspace/trust/seal.d.ts.map +1 -1
  318. package/dist/workspace/trust/signers-cli.d.ts +49 -0
  319. package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
  320. package/dist/workspace/trust/ssh-commit.d.ts +12 -0
  321. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
  322. package/dist/workspace/trust/test-repo.d.ts +13 -0
  323. package/dist/workspace/trust/test-repo.d.ts.map +1 -1
  324. package/dist/workspace/trust/verify.d.ts +15 -0
  325. package/dist/workspace/trust/verify.d.ts.map +1 -1
  326. package/dist/workspace/work-cli.d.ts +39 -3
  327. package/dist/workspace/work-cli.d.ts.map +1 -1
  328. package/dist/workspace/work-evidence.d.ts +1 -1
  329. package/dist/workspace/work-evidence.d.ts.map +1 -1
  330. package/dist/workspace/work.d.ts +26 -1
  331. package/dist/workspace/work.d.ts.map +1 -1
  332. package/dist/workspace/workspace-principals.schema.json +60 -0
  333. package/dist/workspace/write-scope.d.ts +259 -0
  334. package/dist/workspace/write-scope.d.ts.map +1 -0
  335. package/dist/yaml.d.ts +21 -39
  336. package/dist/yaml.d.ts.map +1 -1
  337. package/package.json +2 -2
  338. package/src/audit/prior-art.ts +15 -0
  339. package/src/build.ts +8 -0
  340. package/src/cli/build-options.ts +4 -1
  341. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
  342. package/src/cli/commands/build.ts +2 -0
  343. package/src/cli/commands/carve-emit-state.test.ts +4 -0
  344. package/src/cli/commands/carve-emit.ts +5 -19
  345. package/src/cli/commands/check-lexicon.test.ts +62 -1
  346. package/src/cli/commands/check-lexicon.ts +36 -6
  347. package/src/cli/commands/import-live.test.ts +87 -1
  348. package/src/cli/commands/import-parser-options.test.ts +133 -0
  349. package/src/cli/commands/import.ts +69 -25
  350. package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
  351. package/src/cli/commands/init.test.ts +8 -1
  352. package/src/cli/commands/init.ts +23 -8
  353. package/src/cli/commands/lint.test.ts +37 -0
  354. package/src/cli/commands/onboard.test.ts +53 -3
  355. package/src/cli/commands/onboard.ts +52 -4
  356. package/src/cli/commands/pinned-upgrade.ts +73 -33
  357. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
  358. package/src/cli/handlers/components.ts +2 -2
  359. package/src/cli/handlers/dev.ts +8 -6
  360. package/src/cli/handlers/fan-out.test.ts +6 -6
  361. package/src/cli/handlers/fan-out.ts +2 -1
  362. package/src/cli/handlers/graph.test.ts +42 -0
  363. package/src/cli/handlers/graph.ts +22 -0
  364. package/src/cli/handlers/lifecycle.test.ts +67 -0
  365. package/src/cli/handlers/lifecycle.ts +6 -5
  366. package/src/cli/handlers/misc.ts +2 -0
  367. package/src/cli/handlers/operator.ts +88 -4
  368. package/src/cli/handlers/run.test.ts +111 -0
  369. package/src/cli/handlers/run.ts +85 -24
  370. package/src/cli/handlers/scenario.ts +2 -2
  371. package/src/cli/main.test.ts +33 -0
  372. package/src/cli/main.ts +168 -17
  373. package/src/cli/mcp/workspace-tools.test.ts +5 -2
  374. package/src/cli/mcp/workspace-tools.ts +62 -4
  375. package/src/cli/registry.ts +33 -2
  376. package/src/cli/serve-mcp-workspace.test.ts +1 -1
  377. package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
  378. package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
  379. package/src/codegen/pinned-upgrade.test.ts +104 -0
  380. package/src/codegen/pinned-upgrade.ts +250 -56
  381. package/src/codegen/release-wiring.test.ts +5 -1
  382. package/src/codegen/testdata/postgres-tags.json +242 -0
  383. package/src/components/fan-out-output.test.ts +1 -1
  384. package/src/components/fan-out.test.ts +1 -1
  385. package/src/components/promote.test.ts +1 -1
  386. package/src/config.test.ts +21 -0
  387. package/src/config.ts +27 -0
  388. package/src/content-digest.test.ts +2 -2
  389. package/src/declarable.test.ts +21 -0
  390. package/src/declarable.ts +19 -0
  391. package/src/discovery/fold-composite.test.ts +41 -5
  392. package/src/discovery/fold-import.test.ts +129 -0
  393. package/src/discovery/fold-import.ts +643 -131
  394. package/src/discovery/fold-package-composite.test.ts +264 -0
  395. package/src/discovery/fold-specifiers.test.ts +191 -0
  396. package/src/discovery/param-deps.test.ts +66 -1
  397. package/src/discovery/param-deps.ts +45 -0
  398. package/src/discovery/specifier-resolve.ts +344 -0
  399. package/src/fold/fold.test.ts +39 -1
  400. package/src/fold/fold.ts +83 -9
  401. package/src/fold-provenance.test.ts +140 -0
  402. package/src/graph-ir.test.ts +83 -0
  403. package/src/graph-ir.ts +29 -0
  404. package/src/import/embedded.test.ts +20 -0
  405. package/src/import/embedded.ts +13 -0
  406. package/src/import/parser-options.ts +46 -0
  407. package/src/import/parser.ts +20 -0
  408. package/src/lexicon.ts +79 -3
  409. package/src/lifecycle/gate-ledger.test.ts +14 -0
  410. package/src/lifecycle/gate-ledger.ts +18 -1
  411. package/src/lifecycle/observe.test.ts +18 -0
  412. package/src/lifecycle/observe.ts +6 -4
  413. package/src/lifecycle/plan-digest.test.ts +54 -3
  414. package/src/lifecycle/plan-digest.ts +38 -8
  415. package/src/lifecycle/snapshot.ts +2 -2
  416. package/src/lifecycle/work-lease.test.ts +1 -1
  417. package/src/lifecycle/work-lease.ts +93 -2
  418. package/src/lint/engine.test.ts +55 -0
  419. package/src/lint/engine.ts +30 -4
  420. package/src/lint/output-docs.test.ts +59 -56
  421. package/src/op/activities/activity-contracts.ts +1 -0
  422. package/src/op/activities/apply.test.ts +189 -5
  423. package/src/op/activities/apply.ts +230 -8
  424. package/src/op/activities/index.ts +3 -0
  425. package/src/op/activities/lexicon-upgrade.test.ts +160 -6
  426. package/src/op/activities/lexicon-upgrade.ts +154 -51
  427. package/src/op/activities/propose-upgrade.ts +8 -5
  428. package/src/op/composites/apply-op.ts +12 -5
  429. package/src/op/composites/composites.test.ts +30 -3
  430. package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
  431. package/src/op/composites/lexicon-upgrade-op.ts +29 -8
  432. package/src/op/emulator-lifecycle.test.ts +23 -0
  433. package/src/op/emulator-lifecycle.ts +52 -14
  434. package/src/op/gate-approval.test.ts +91 -0
  435. package/src/op/gate-approval.ts +5 -1
  436. package/src/op/gate.ts +34 -8
  437. package/src/op/index.ts +3 -1
  438. package/src/op/local-executor.test.ts +15 -0
  439. package/src/op/local-executor.ts +40 -12
  440. package/src/op/local-output.ts +1 -1
  441. package/src/op/operator.ts +4 -0
  442. package/src/op/run-context.test.ts +141 -0
  443. package/src/op/run-context.ts +51 -0
  444. package/src/op/runtimes/local.test.ts +14 -0
  445. package/src/op/runtimes/local.ts +2 -0
  446. package/src/op/steward-beside.ts +2 -0
  447. package/src/op/types.ts +8 -3
  448. package/src/op/work-lease-run.test.ts +47 -0
  449. package/src/op/work-lease-run.ts +73 -11
  450. package/src/provenance.ts +35 -0
  451. package/src/serializer.ts +9 -0
  452. package/src/telemetry-attribution.test.ts +91 -0
  453. package/src/telemetry-attribution.ts +145 -0
  454. package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
  455. package/src/workspace/agent-cli.ts +138 -0
  456. package/src/workspace/agent.schema.json +378 -0
  457. package/src/workspace/behold-kinds.test.ts +1 -1
  458. package/src/workspace/box-factory.test.ts +320 -0
  459. package/src/workspace/box-factory.ts +103 -0
  460. package/src/workspace/changes-cli.ts +5 -0
  461. package/src/workspace/changes.schema.json +171 -1
  462. package/src/workspace/changes.ts +61 -4
  463. package/src/workspace/check-live.test.ts +192 -0
  464. package/src/workspace/check.schema.json +64 -0
  465. package/src/workspace/checks/boxes.test.ts +2 -0
  466. package/src/workspace/checks/links.ts +23 -2
  467. package/src/workspace/checks/live.ts +113 -0
  468. package/src/workspace/checks.test.ts +2 -2
  469. package/src/workspace/checks.ts +49 -8
  470. package/src/workspace/compose-graph.test.ts +47 -0
  471. package/src/workspace/compose-graph.ts +127 -3
  472. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
  473. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
  474. package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
  475. package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
  476. package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
  477. package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
  478. package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -0
  479. package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
  480. package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
  481. package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +578 -0
  482. package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
  483. package/src/workspace/conformance/index.mjs +30 -3
  484. package/src/workspace/conformance/index.ts +103 -15
  485. package/src/workspace/conformance/vitest.ts +44 -2
  486. package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
  487. package/src/workspace/conformance/writer.test.ts +156 -0
  488. package/src/workspace/conformance/writer.ts +880 -0
  489. package/src/workspace/decide.ts +7 -1
  490. package/src/workspace/declaration.schema.json +368 -4
  491. package/src/workspace/declaration.ts +270 -1
  492. package/src/workspace/declared-kinds.test.ts +33 -0
  493. package/src/workspace/evidence.schema.json +279 -0
  494. package/src/workspace/export-cli.ts +180 -0
  495. package/src/workspace/export-import.test.ts +282 -0
  496. package/src/workspace/export.ts +486 -0
  497. package/src/workspace/graph-cli.ts +51 -2
  498. package/src/workspace/graph-contract.test.ts +89 -4
  499. package/src/workspace/graph.schema.json +453 -1
  500. package/src/workspace/identity.test.ts +196 -0
  501. package/src/workspace/identity.ts +186 -0
  502. package/src/workspace/import.ts +325 -0
  503. package/src/workspace/intent-cli.ts +64 -10
  504. package/src/workspace/intent-record.schema.json +208 -0
  505. package/src/workspace/intent-record.ts +35 -1
  506. package/src/workspace/intent-why.test.ts +274 -0
  507. package/src/workspace/intent.schema.json +718 -7
  508. package/src/workspace/intent.test.ts +11 -2
  509. package/src/workspace/intent.ts +495 -32
  510. package/src/workspace/kinds.test.ts +5 -5
  511. package/src/workspace/kinds.ts +62 -33
  512. package/src/workspace/lineage-adopt-cli.ts +103 -0
  513. package/src/workspace/lineage-adopt.test.ts +552 -0
  514. package/src/workspace/lineage-adopt.ts +452 -0
  515. package/src/workspace/lineage-check.ts +26 -5
  516. package/src/workspace/lineage-cli.ts +12 -2
  517. package/src/workspace/lineage-hash-index.ts +305 -0
  518. package/src/workspace/lineage-init.test.ts +9 -0
  519. package/src/workspace/lineage-init.ts +29 -9
  520. package/src/workspace/lineage-lock.ts +54 -0
  521. package/src/workspace/lineage-migrations.test.ts +27 -0
  522. package/src/workspace/lineage-migrations.ts +44 -14
  523. package/src/workspace/lineage-provenance.ts +40 -0
  524. package/src/workspace/lineage-upgrade-cli.ts +9 -5
  525. package/src/workspace/lineage-upgrade.test.ts +92 -1
  526. package/src/workspace/lineage-upgrade.ts +111 -16
  527. package/src/workspace/lineage-versions.ts +348 -0
  528. package/src/workspace/links.test.ts +121 -2
  529. package/src/workspace/links.ts +97 -6
  530. package/src/workspace/ls-contract.test.ts +84 -1
  531. package/src/workspace/ls-generated.ts +111 -0
  532. package/src/workspace/ls.schema.json +19 -0
  533. package/src/workspace/ls.ts +8 -1
  534. package/src/workspace/member-commands.ts +3 -1
  535. package/src/workspace/nested-graph.test.ts +176 -0
  536. package/src/workspace/nested-graph.ts +169 -0
  537. package/src/workspace/nesting.ts +37 -0
  538. package/src/workspace/pin-cli.test.ts +71 -0
  539. package/src/workspace/pin-cli.ts +57 -0
  540. package/src/workspace/pin-integrity.test.ts +121 -0
  541. package/src/workspace/pin-integrity.ts +104 -0
  542. package/src/workspace/points-write.schema.json +2 -0
  543. package/src/workspace/principal-classes.test.ts +175 -0
  544. package/src/workspace/principal-classes.ts +307 -0
  545. package/src/workspace/read-contract.test.ts +24 -0
  546. package/src/workspace/reason-codes.test.ts +20 -2
  547. package/src/workspace/reason-codes.ts +53 -3
  548. package/src/workspace/record-sessions.ts +12 -14
  549. package/src/workspace/records-amend.schema.json +6 -0
  550. package/src/workspace/records-checkout.ts +106 -0
  551. package/src/workspace/records-cli.ts +195 -22
  552. package/src/workspace/records-close.schema.json +7 -2
  553. package/src/workspace/records-close.ts +10 -2
  554. package/src/workspace/records-formats.test.ts +13 -5
  555. package/src/workspace/records-new.schema.json +6 -0
  556. package/src/workspace/records-review.schema.json +6 -0
  557. package/src/workspace/records-sessions.test.ts +23 -6
  558. package/src/workspace/records-uncommitted.test.ts +171 -0
  559. package/src/workspace/records-write.test.ts +65 -8
  560. package/src/workspace/records-write.ts +92 -6
  561. package/src/workspace/records.schema.json +127 -4
  562. package/src/workspace/records.ts +123 -5
  563. package/src/workspace/returns.ts +328 -0
  564. package/src/workspace/runs-cli.ts +381 -0
  565. package/src/workspace/runs-write.schema.json +583 -0
  566. package/src/workspace/runs.schema.json +810 -0
  567. package/src/workspace/runs.test.ts +242 -0
  568. package/src/workspace/runs.ts +709 -0
  569. package/src/workspace/signers.schema.json +206 -0
  570. package/src/workspace/status-contract.test.ts +5 -0
  571. package/src/workspace/status-gates.ts +24 -9
  572. package/src/workspace/status.schema.json +127 -2
  573. package/src/workspace/status.ts +21 -1
  574. package/src/workspace/symbols.ts +180 -0
  575. package/src/workspace/template-manifest.ts +22 -4
  576. package/src/workspace/trailer-joins.test.ts +171 -0
  577. package/src/workspace/trailer-joins.ts +82 -0
  578. package/src/workspace/trailers.ts +148 -0
  579. package/src/workspace/trust/attestor.ts +15 -0
  580. package/src/workspace/trust/dsse.ts +134 -0
  581. package/src/workspace/trust/evidence-cli.ts +195 -0
  582. package/src/workspace/trust/evidence.test.ts +241 -0
  583. package/src/workspace/trust/evidence.ts +207 -0
  584. package/src/workspace/trust/policy.ts +110 -3
  585. package/src/workspace/trust/provenance.ts +41 -4
  586. package/src/workspace/trust/record-seal.test.ts +1 -1
  587. package/src/workspace/trust/rotation.test.ts +258 -0
  588. package/src/workspace/trust/rotation.ts +336 -0
  589. package/src/workspace/trust/seal.ts +63 -1
  590. package/src/workspace/trust/signers-cli.ts +178 -0
  591. package/src/workspace/trust/ssh-commit.ts +53 -4
  592. package/src/workspace/trust/test-repo.ts +18 -0
  593. package/src/workspace/trust/trust.test.ts +8 -2
  594. package/src/workspace/trust/verify-cli.ts +1 -0
  595. package/src/workspace/trust/verify.ts +22 -0
  596. package/src/workspace/work-cli.e2e.test.ts +28 -1
  597. package/src/workspace/work-cli.ts +133 -8
  598. package/src/workspace/work-evidence.schema.json +6 -0
  599. package/src/workspace/work-history.schema.json +73 -1
  600. package/src/workspace/work-history.test.ts +48 -5
  601. package/src/workspace/work-kind-fields.test.ts +154 -0
  602. package/src/workspace/work-lease.schema.json +14 -1
  603. package/src/workspace/work.ts +82 -0
  604. package/src/workspace/workspace-principals.schema.json +60 -0
  605. package/src/workspace/write-scope.test.ts +466 -0
  606. package/src/workspace/write-scope.ts +573 -0
  607. package/src/yaml.test.ts +111 -1
  608. package/src/yaml.ts +141 -549
@@ -106,6 +106,36 @@ export async function coverageReportCheck(plugin: LexiconPlugin | undefined): Pr
106
106
  };
107
107
  }
108
108
 
109
+ /**
110
+ * #3104 — how many composites a lexicon ships.
111
+ *
112
+ * This counted every `.ts` file in `src/composites/` except `index.ts`, so
113
+ * `catalog.ts`, `catalog.test.ts`, `composites.test.ts` and helper modules all
114
+ * counted: otel reported "4 composite(s)" for `NodeAgent` alone. The same rule
115
+ * as #1342 applies: a capability is what the plugin exposes, and a lexicon
116
+ * with composites exposes them through `composites()`, the catalog generated
117
+ * from its real exports (#2662). Ask that when it is there. Only a lexicon
118
+ * without it falls back to the files, and then not to tests, the catalog, the
119
+ * barrel or helper modules.
120
+ */
121
+ export function countComposites(
122
+ plugin: LexiconPlugin | undefined,
123
+ dir: string,
124
+ ): { count: number; detail: string } {
125
+ if (registers(plugin, "composites")) {
126
+ const { items, error } = safeList(plugin!.composites!.bind(plugin));
127
+ if (error !== undefined) return { count: 0, detail: `composites() threw: ${error}` };
128
+ const names = new Set(items.map((e) => e.name));
129
+ return { count: names.size, detail: `${names.size} composite(s) in composites()` };
130
+ }
131
+ const files = listTsFiles(join(dir, "src/composites"), ["index.ts", "catalog.ts", "helpers.ts", "shared.ts"])
132
+ .filter((f) => !f.endsWith(".test.ts") && !f.endsWith(".d.ts") && !f.endsWith("-helpers.ts"));
133
+ return {
134
+ count: files.length,
135
+ detail: `${files.length} composite file(s) in src/composites/; the plugin has no composites()`,
136
+ };
137
+ }
138
+
109
139
  /**
110
140
  * #2535 — a lexicon that supplies member kinds publishes them as data at a
111
141
  * `./workspace-kinds` subpath (ws-031). The file must be JSON, validate as
@@ -551,12 +581,12 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
551
581
  : "reads no config namespace of its own",
552
582
  });
553
583
 
554
- const compositeFiles = listTsFiles(join(dir, "src/composites"), ["index.ts"]);
584
+ const composites = countComposites(plugin, dir);
555
585
  items.push({
556
- name: "At least 1 composite in src/composites/",
586
+ name: "At least 1 composite",
557
587
  tier: 2,
558
- pass: compositeFiles.length > 0,
559
- detail: compositeFiles.length > 0 ? `${compositeFiles.length} composite(s)` : undefined,
588
+ pass: composites.count > 0,
589
+ detail: composites.detail,
560
590
  });
561
591
 
562
592
  items.push({
@@ -678,8 +708,8 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
678
708
  items.push({
679
709
  name: "At least 5 composites",
680
710
  tier: 3,
681
- pass: compositeFiles.length >= 5,
682
- detail: `${compositeFiles.length} composite(s)`,
711
+ pass: composites.count >= 5,
712
+ detail: composites.detail,
683
713
  });
684
714
 
685
715
  const hasActions = existsSync(join(dir, "src/actions")) &&
@@ -6,7 +6,8 @@ import { join } from "node:path";
6
6
  import { tmpdir } from "node:os";
7
7
  import type { LexiconPlugin, ExportedTemplate, ResourceSelector } from "../../lexicon";
8
8
  import type { TypeScriptGenerator } from "../../import/generator";
9
- import type { TemplateIR } from "../../import/parser";
9
+ import type { TemplateIR, ParseContext } from "../../import/parser";
10
+ import type { EmbeddedContentImporter } from "../../import/embedded";
10
11
 
11
12
  const generator: TypeScriptGenerator = {
12
13
  generate(ir: TemplateIR) {
@@ -105,6 +106,24 @@ describe("liveImportFromPlugins (#114)", () => {
105
106
  expect(result.error).toContain("live export");
106
107
  });
107
108
 
109
+ test("warnings an exporter returns reach the result (#3336)", async () => {
110
+ const withWarnings: ExportedTemplate = { ...sampleIR, warnings: ["bucket is kept by Terraform; left out"] };
111
+ const result = await liveImportFromPlugins([fakeExporter("fake", withWarnings)], {
112
+ environment: "prod",
113
+ output: outputDir,
114
+ force: true,
115
+ });
116
+ expect(result.success).toBe(true);
117
+ expect(result.warnings).toContain("bucket is kept by Terraform; left out");
118
+ });
119
+
120
+ test("warnings from an export with no resources are kept on the error result (#3336)", async () => {
121
+ const empty = fakeExporter("fake", { resources: [], parameters: [], warnings: ["everything is kept by Prisma"] });
122
+ const result = await liveImportFromPlugins([empty], { environment: "prod", output: outputDir });
123
+ expect(result.success).toBe(false);
124
+ expect(result.warnings).toContain("everything is kept by Prisma");
125
+ });
126
+
108
127
  test("--lexicon narrows to the named exporter", async () => {
109
128
  const result = await liveImportFromPlugins(
110
129
  [fakeExporter("a", sampleIR), fakeExporter("b", sampleIR)],
@@ -151,4 +170,71 @@ describe("liveImportFromPlugins (#114)", () => {
151
170
  expect(result.success).toBe(true);
152
171
  expect(seenStack).toBe("loom-backend");
153
172
  });
173
+
174
+ // #2995: an export with `reparse` goes through the same embedded-content
175
+ // delegation as file import.
176
+ describe("embedded content (#2995)", () => {
177
+ const configText = "service:\n pipelines: {}\n";
178
+
179
+ function hostExporter(): LexiconPlugin {
180
+ const parse = (context?: ParseContext): TemplateIR => {
181
+ const ref = context?.embedded?.resolve({
182
+ host: "fake",
183
+ hostType: "Fake::ConfigMap",
184
+ location: "ConfigMap cfg data[\"config.yaml\"]",
185
+ directory: "cfg",
186
+ text: configText,
187
+ expectedOwner: { lexicon: "owner", what: "an owner config" },
188
+ });
189
+ return {
190
+ resources: [{ logicalId: "cfg", type: "Fake::ConfigMap", properties: { data: ref ?? configText } }],
191
+ parameters: [],
192
+ };
193
+ };
194
+ return {
195
+ ...fakeExporter("fake", { resources: [], parameters: [] }),
196
+ async exportResources(): Promise<ExportedTemplate> {
197
+ return { ...parse(), reparse: (context) => parse(context) };
198
+ },
199
+ };
200
+ }
201
+
202
+ const importer: EmbeddedContentImporter = {
203
+ what: "an owner config",
204
+ matches: (c) => typeof c.document === "object" && c.document !== null && "service" in c.document,
205
+ import: () => ({
206
+ files: [{ path: "config.ts", content: "export const config = {};\n" }],
207
+ value: { bindings: [{ from: "config.ts", name: "config" }], shape: "single" },
208
+ }),
209
+ };
210
+ const owner: LexiconPlugin = {
211
+ name: "owner",
212
+ serializer: {} as never,
213
+ generate: async () => {},
214
+ validate: async () => {},
215
+ coverage: async () => {},
216
+ package: async () => {},
217
+ embeddedImporters: () => [importer],
218
+ };
219
+
220
+ test("a loaded owner imports the content and its modules are written beside the host's", async () => {
221
+ const result = await liveImportFromPlugins([hostExporter(), owner], { environment: "prod", output: outputDir, force: true });
222
+ expect(result.success).toBe(true);
223
+ expect(result.warnings).toEqual([]);
224
+ expect(result.generatedFiles).toEqual(["main.ts", "cfg/config.ts"]);
225
+ const main = await readFile(join(outputDir, "main.ts"), "utf-8");
226
+ expect(main).toContain('"$embedded"');
227
+ expect(main).toContain('"from":"cfg/config.ts"');
228
+ expect(await readFile(join(outputDir, "cfg/config.ts"), "utf-8")).toContain("export const config");
229
+ });
230
+
231
+ test("with no owner the content is kept as read, with a warning", async () => {
232
+ const result = await liveImportFromPlugins([hostExporter()], { environment: "prod", output: outputDir, force: true });
233
+ expect(result.success).toBe(true);
234
+ expect(result.generatedFiles).toEqual(["main.ts"]);
235
+ expect(result.warnings.join("\n")).toContain("no installed lexicon imports it");
236
+ const main = await readFile(join(outputDir, "main.ts"), "utf-8");
237
+ expect(main).toContain(JSON.stringify(configText));
238
+ });
239
+ });
154
240
  });
@@ -0,0 +1,133 @@
1
+ import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
2
+ import { mkdir, rm, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import type { LexiconPlugin } from "../../lexicon";
6
+ import type { ParserOptions } from "../../import/parser";
7
+ import { resolveParserOptions } from "../../import/parser-options";
8
+ import { parseArgs } from "../main";
9
+ import { importCommand, importFromContent } from "./import";
10
+
11
+ const { seen, withOptions, withoutOptions } = vi.hoisted(() => {
12
+ const seen: unknown[] = [];
13
+ const parser = {
14
+ parse: () => ({ resources: [], parameters: [], warnings: ["parsed"] }),
15
+ };
16
+ const generator = { generate: () => [{ path: "x.ts", content: "export {};\n" }] };
17
+ const withOptions = {
18
+ name: "with-options",
19
+ detectTemplate: (d: unknown) => typeof d === "object" && d !== null && "marker" in d,
20
+ parserOptions: () => [
21
+ { name: "flag", type: "boolean", description: "a switch" },
22
+ { name: "level", type: "number", description: "a number" },
23
+ { name: "label", type: "string", description: "a string" },
24
+ ],
25
+ templateParser: (options?: ParserOptions) => {
26
+ seen.push(options);
27
+ return parser;
28
+ },
29
+ templateGenerator: () => generator,
30
+ } as unknown as LexiconPlugin;
31
+ const withoutOptions = {
32
+ name: "without-options",
33
+ templateParser: () => parser,
34
+ templateGenerator: () => generator,
35
+ } as unknown as LexiconPlugin;
36
+ return { seen, withOptions, withoutOptions };
37
+ });
38
+
39
+ vi.mock("../plugins", () => ({
40
+ resolveProjectLexicons: async () => ["with-options"],
41
+ loadPlugins: async (names: string[]) => names.map((n) => (n === "without-options" ? withoutOptions : withOptions)),
42
+ }));
43
+
44
+ describe("resolveParserOptions (#2994)", () => {
45
+ const specs = withOptions as Pick<LexiconPlugin, "name" | "parserOptions">;
46
+
47
+ test("no entries is an empty record", () => {
48
+ expect(resolveParserOptions(specs, undefined)).toEqual({ options: {} });
49
+ });
50
+
51
+ test("converts to the declared types; a bare boolean is true", () => {
52
+ expect(resolveParserOptions(specs, ["flag", "level=3", "label=a=b"])).toEqual({
53
+ options: { flag: true, level: 3, label: "a=b" },
54
+ });
55
+ expect(resolveParserOptions(specs, ["flag=false"])).toEqual({ options: { flag: false } });
56
+ });
57
+
58
+ test("refuses an unknown name and lists what the lexicon accepts", () => {
59
+ const r = resolveParserOptions(specs, ["nope"]);
60
+ expect(r).toMatchObject({ error: expect.stringContaining('Unknown parser option "nope" for lexicon "with-options"') });
61
+ expect((r as { error: string }).error).toContain("flag (boolean): a switch");
62
+ });
63
+
64
+ test("a lexicon with no options says so", () => {
65
+ const r = resolveParserOptions({ name: "plain" }, ["x"]);
66
+ expect((r as { error: string }).error).toBe('Unknown parser option "x" for lexicon "plain"; lexicon "plain" declares no parser options.');
67
+ });
68
+
69
+ test("refuses a bad value", () => {
70
+ expect(resolveParserOptions(specs, ["flag=maybe"])).toHaveProperty("error");
71
+ expect(resolveParserOptions(specs, ["level=abc"])).toHaveProperty("error");
72
+ expect(resolveParserOptions(specs, ["level"])).toHaveProperty("error");
73
+ expect(resolveParserOptions(specs, ["label"])).toHaveProperty("error");
74
+ });
75
+ });
76
+
77
+ describe("chant import --parser-option (#2994)", () => {
78
+ let dir: string;
79
+ let templatePath: string;
80
+
81
+ beforeEach(async () => {
82
+ seen.length = 0;
83
+ dir = join(tmpdir(), `chant-import-parser-options-${Date.now()}-${Math.random()}`);
84
+ await mkdir(dir, { recursive: true });
85
+ templatePath = join(dir, "t.json");
86
+ await writeFile(templatePath, JSON.stringify({ marker: true }));
87
+ });
88
+
89
+ afterEach(async () => {
90
+ await rm(dir, { recursive: true, force: true });
91
+ });
92
+
93
+ test("the flag is parsed, repeatable", () => {
94
+ const args = parseArgs(["import", "t.json", "--lexicon", "x", "--parser-option", "a", "--parser-option", "b=1"]);
95
+ expect(args.parserOption).toEqual(["a", "b=1"]);
96
+ });
97
+
98
+ test("--lexicon: the parser receives the typed options", async () => {
99
+ const result = await importCommand({
100
+ templatePath, output: join(dir, "out"), lexicon: "with-options", parserOptions: ["flag", "level=2"],
101
+ });
102
+ expect(result.success).toBe(true);
103
+ expect(seen).toEqual([{ flag: true, level: 2 }]);
104
+ });
105
+
106
+ test("detection: the options go to the detected lexicon", async () => {
107
+ const result = await importCommand({ templatePath, output: join(dir, "out"), parserOptions: ["label=x"] });
108
+ expect(result.success).toBe(true);
109
+ expect(seen).toEqual([{ label: "x" }]);
110
+ });
111
+
112
+ test("no options: the parser gets an empty record", async () => {
113
+ await importCommand({ templatePath, output: join(dir, "out"), lexicon: "with-options" });
114
+ expect(seen).toEqual([{}]);
115
+ });
116
+
117
+ test("an unknown option is refused before parsing", async () => {
118
+ const result = await importCommand({
119
+ templatePath, output: join(dir, "out"), lexicon: "with-options", parserOptions: ["bogus"],
120
+ });
121
+ expect(result.success).toBe(false);
122
+ expect(result.error).toContain('Unknown parser option "bogus"');
123
+ expect(seen).toEqual([]);
124
+ });
125
+
126
+ test("content import refuses an option on a lexicon that declares none", async () => {
127
+ const result = await importFromContent({
128
+ content: "{}", lexicon: "without-options", output: join(dir, "out"), parserOptions: ["x"],
129
+ });
130
+ expect(result.success).toBe(false);
131
+ expect(result.error).toContain('lexicon "without-options" declares no parser options');
132
+ });
133
+ });
@@ -1,12 +1,13 @@
1
1
  import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from "fs";
2
2
  import { join, resolve, basename, dirname } from "path";
3
3
  import { formatSuccess, formatWarning, formatError } from "../format";
4
- import type { TemplateIR, ResourceIR, ParameterIR, TemplateParser } from "../../import/parser";
4
+ import type { TemplateIR, ResourceIR, ParameterIR, ParseContext } from "../../import/parser";
5
5
  import type { GeneratedFile, TypeScriptGenerator } from "../../import/generator";
6
6
  import { listInstalledLexicons, loadPlugin, loadPlugins, resolveProjectLexicons } from "../plugins";
7
- import type { LexiconPlugin, ResourceSelector } from "../../lexicon";
7
+ import type { ExportedTemplate, LexiconPlugin, ResourceSelector } from "../../lexicon";
8
8
  import { parseYAMLDocument, splitYAMLDocuments } from "../../yaml";
9
9
  import { importLexiconPackage } from "../../lexicon-module";
10
+ import { resolveParserOptions } from "../../import/parser-options";
10
11
  import { EmbeddedImports, type EmbeddedContent, type RegisteredEmbeddedImporter } from "../../import/embedded";
11
12
 
12
13
  /**
@@ -24,6 +25,12 @@ export interface ImportOptions {
24
25
  * JSON/YAML check: the raw content goes straight to that plugin's parser.
25
26
  */
26
27
  lexicon?: string;
28
+ /**
29
+ * `--parser-option` entries (`key` or `key=value`) for the lexicon's parser
30
+ * (#2994). Checked against the lexicon's `parserOptions()`; an unknown name
31
+ * fails the import before anything is parsed.
32
+ */
33
+ parserOptions?: string[];
27
34
  }
28
35
 
29
36
  /**
@@ -345,6 +352,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
345
352
  lexicon: options.lexicon,
346
353
  output: options.output,
347
354
  force: options.force,
355
+ parserOptions: options.parserOptions,
348
356
  });
349
357
  }
350
358
 
@@ -383,7 +391,7 @@ export async function importCommand(options: ImportOptions): Promise<ImportResul
383
391
  );
384
392
  }
385
393
 
386
- const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir);
394
+ const result = await parseAndWrite(plugin, content, outputDir, options.force, warnings, generatedFiles, plugin.name, projectDir, options.parserOptions);
387
395
  return { ...result, detected: true };
388
396
  }
389
397
 
@@ -402,6 +410,8 @@ export interface ContentImportOptions {
402
410
  lexicon: string;
403
411
  output?: string;
404
412
  force?: boolean;
413
+ /** `--parser-option` entries for the lexicon's parser (#2994); see {@link ImportOptions.parserOptions}. */
414
+ parserOptions?: string[];
405
415
  }
406
416
 
407
417
  export async function importFromContent(options: ContentImportOptions): Promise<ImportResult> {
@@ -422,19 +432,20 @@ export async function importFromContent(options: ContentImportOptions): Promise<
422
432
  return { success: false, generatedFiles: [], warnings: [], error: `Lexicon "${options.lexicon}" not available.` };
423
433
  }
424
434
  const projectDir = resolve(options.output ? dirname(options.output) : ".");
425
- return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir);
435
+ return parseAndWrite(plugin, options.content, outputDir, options.force, [], [], plugin.name, projectDir, options.parserOptions);
426
436
  }
427
437
 
428
438
  /**
429
439
  * The importers for the content a host's parser offered (#2962): those of the
430
- * project's lexicons, and of each installed lexicon whose `detectTemplate`
431
- * recognizes one of the offered documents. The recognizing is done with the
440
+ * plugins already loaded, of the project's lexicons, and of each installed
441
+ * lexicon whose `detectTemplate` recognizes one of the offered documents
442
+ * (#2995 adds the loaded ones). The recognizing is done with the
432
443
  * lexicon's light `/detect` module, so a lexicon is loaded in full only when
433
444
  * it may own something; one that fails to load is skipped.
434
445
  */
435
446
  async function embeddedImportersFor(
436
447
  offered: readonly EmbeddedContent[],
437
- host: LexiconPlugin,
448
+ loaded: readonly LexiconPlugin[],
438
449
  projectDir: string,
439
450
  ): Promise<RegisteredEmbeddedImporter[]> {
440
451
  const documents = offered.map((c) => c.document).filter((d) => typeof d === "object" && d !== null);
@@ -446,7 +457,8 @@ async function embeddedImportersFor(
446
457
  } catch {
447
458
  projectNames = [];
448
459
  }
449
- const candidates: string[] = [...projectNames];
460
+ // Plugins already loaded (the host, or live import's exporters) are asked too.
461
+ const candidates: string[] = [...new Set([...loaded.map((p) => p.name), ...projectNames])];
450
462
  for (const name of listInstalledLexicons(projectDir)) {
451
463
  if (candidates.includes(name)) continue;
452
464
  try {
@@ -471,7 +483,7 @@ async function embeddedImportersFor(
471
483
  for (const name of candidates) {
472
484
  let plugin: LexiconPlugin;
473
485
  try {
474
- plugin = name === host.name ? host : await loadPlugin(name);
486
+ plugin = loaded.find((p) => p.name === name) ?? (await loadPlugin(name));
475
487
  } catch {
476
488
  continue;
477
489
  }
@@ -488,22 +500,24 @@ async function embeddedImportersFor(
488
500
 
489
501
  /**
490
502
  * Parse, resolving embedded content (#2962). A first parse with a probe
491
- * collects what the parser offers; when it offers anything, the owners'
492
- * importers are loaded and the content is parsed again with them. A parser
493
- * that offers nothing is parsed once, and nothing is loaded.
503
+ * collects what the parsers offer; when they offer anything, the owners'
504
+ * importers are loaded and each is parsed again with them, through one
505
+ * resolver so their directories stay distinct. A parse is a template
506
+ * parser over a file's content, or an export's `reparse` (#2995). Parsers
507
+ * that offer nothing are parsed once, and nothing is loaded. `loaded` are
508
+ * plugins already loaded, reused when one of them owns content.
494
509
  */
495
510
  async function parseWithEmbedded(
496
- plugin: LexiconPlugin,
497
- parser: TemplateParser,
498
- content: string,
511
+ parses: ReadonlyArray<(context: ParseContext) => TemplateIR>,
512
+ loaded: readonly LexiconPlugin[],
499
513
  projectDir: string,
500
- ): Promise<{ ir: TemplateIR; embedded?: EmbeddedImports }> {
514
+ ): Promise<{ irs: TemplateIR[]; embedded?: EmbeddedImports }> {
501
515
  const probe = new EmbeddedImports([], { quiet: true });
502
- const ir = parser.parse(content, { embedded: probe });
503
- if (probe.offered.length === 0) return { ir };
504
- const importers = await embeddedImportersFor(probe.offered, plugin, projectDir);
516
+ const irs = parses.map((parse) => parse({ embedded: probe }));
517
+ if (probe.offered.length === 0) return { irs };
518
+ const importers = await embeddedImportersFor(probe.offered, loaded, projectDir);
505
519
  const embedded = new EmbeddedImports(importers);
506
- return { ir: parser.parse(content, { embedded }), embedded };
520
+ return { irs: parses.map((parse) => parse({ embedded })), embedded };
507
521
  }
508
522
 
509
523
  /** The shared tail of every template import: parse → generate → write. */
@@ -516,6 +530,7 @@ async function parseAndWrite(
516
530
  generatedFiles: string[],
517
531
  lexicon: string,
518
532
  projectDir: string,
533
+ parserOptionEntries?: readonly string[],
519
534
  ): Promise<ImportResult> {
520
535
  // A lexicon can recognize a template (detectTemplate) without being able to
521
536
  // import it (grafana had no parser until #2945). Every path funnels through here, so
@@ -530,12 +545,19 @@ async function parseAndWrite(
530
545
  };
531
546
  }
532
547
 
548
+ const resolved = resolveParserOptions(plugin, parserOptionEntries);
549
+ if ("error" in resolved) {
550
+ return { success: false, generatedFiles: [], warnings: [], error: resolved.error, lexicon: plugin.name };
551
+ }
552
+
533
553
  // Parse template
534
554
  let ir: TemplateIR;
535
555
  let embedded: EmbeddedImports | undefined;
536
556
  try {
537
- const parser = plugin.templateParser();
538
- ({ ir, embedded } = await parseWithEmbedded(plugin, parser, content, projectDir));
557
+ const parser = plugin.templateParser(resolved.options);
558
+ let irs: TemplateIR[];
559
+ ({ irs, embedded } = await parseWithEmbedded([(context) => parser.parse(content, context)], [plugin], projectDir));
560
+ ir = irs[0];
539
561
  } catch (err) {
540
562
  return {
541
563
  success: false,
@@ -701,6 +723,7 @@ export async function liveImportFromPlugins(
701
723
  options: LiveImportOptions,
702
724
  ): Promise<ImportResult> {
703
725
  const outputDir = resolve(options.output ?? "./infra/");
726
+ const projectDir = resolve(options.output ? dirname(options.output) : ".");
704
727
  const warnings: string[] = [];
705
728
 
706
729
  let exporters = plugins.filter((p) => p.exportResources && p.templateGenerator);
@@ -720,10 +743,10 @@ export async function liveImportFromPlugins(
720
743
  }
721
744
 
722
745
  // Collect IR from every exporter, tagging which lexicon produced output.
723
- const irParts: TemplateIR[] = [];
746
+ let irParts: ExportedTemplate[] = [];
724
747
  let generatorLexicon: LexiconPlugin | undefined;
725
748
  for (const plugin of exporters) {
726
- let ir: TemplateIR;
749
+ let ir: ExportedTemplate;
727
750
  try {
728
751
  ir = await plugin.exportResources!({
729
752
  environment: options.environment,
@@ -736,6 +759,8 @@ export async function liveImportFromPlugins(
736
759
  warnings.push(`${plugin.name}: live export failed — ${err instanceof Error ? err.message : String(err)}`);
737
760
  continue;
738
761
  }
762
+ // What the exporter left out or could not carry (#3336).
763
+ if (ir.warnings) warnings.push(...ir.warnings);
739
764
  if (ir.resources.length === 0) continue;
740
765
  irParts.push(ir);
741
766
  generatorLexicon ??= plugin;
@@ -754,6 +779,23 @@ export async function liveImportFromPlugins(
754
779
  warnings.push("Multiple lexicons exported resources; generated with the first. Use --lexicon to target one.");
755
780
  }
756
781
 
782
+ // Content embedded in exported resources goes to the lexicon that owns it,
783
+ // as in file import (#2995). An export without `reparse` keeps it as read.
784
+ let embedded: EmbeddedImports | undefined;
785
+ if (irParts.some((part) => part.reparse)) {
786
+ try {
787
+ const parses = irParts.map((part) => part.reparse ?? (() => part));
788
+ let irs: TemplateIR[];
789
+ ({ irs, embedded } = await parseWithEmbedded(parses, plugins, projectDir));
790
+ irParts = irs;
791
+ } catch (err) {
792
+ warnings.push(
793
+ `Embedded content is kept as written, because resolving it failed: ${err instanceof Error ? err.message : String(err)}`,
794
+ );
795
+ }
796
+ if (embedded) warnings.push(...embedded.warnings);
797
+ }
798
+
757
799
  const ir = mergeIR(irParts);
758
800
  const generator = generatorLexicon.templateGenerator!();
759
801
 
@@ -761,8 +803,10 @@ export async function liveImportFromPlugins(
761
803
  mkdirSync(outputDir, { recursive: true });
762
804
  }
763
805
 
764
- const { files, warnings: layoutWarnings } = generateOrganizedFiles(ir, generator);
806
+ const { files: hostFiles, warnings: layoutWarnings } = generateOrganizedFiles(ir, generator);
765
807
  warnings.push(...layoutWarnings);
808
+ // The owners' modules for embedded content, each in a directory of its own.
809
+ const files = [...hostFiles, ...(embedded?.files ?? [])];
766
810
  const generatedFiles: string[] = [];
767
811
  for (const file of files) {
768
812
  const filePath = join(outputDir, file.path);
@@ -37,7 +37,7 @@ export function generatePackageJson(name: string, names: { packageName: string }
37
37
  // (the `workspace:` protocol is rejected outside a workspace).
38
38
  "@intentius/chant": "*",
39
39
  "tsc-alias": "^1.8.17",
40
- typescript: "^5.9.3",
40
+ typescript: "^5.9.3 || ^7.0.0",
41
41
  },
42
42
  };
43
43
 
@@ -87,7 +87,9 @@ describe("initCommand", () => {
87
87
 
88
88
  expect(pkg.dependencies["@intentius/chant"]).toBeDefined();
89
89
  expect(pkg.dependencies["@intentius/chant-lexicon-aws"]).toBeDefined();
90
- expect(pkg.devDependencies["typescript"]).toBeDefined();
90
+ // #3089: the project's TypeScript admits 7, and @types/node backs `types: ["node"]`.
91
+ expect(pkg.devDependencies["typescript"]).toBe("^5.9.3 || ^7.0.0");
92
+ expect(pkg.devDependencies["@types/node"]).toBeDefined();
91
93
  expect(pkg.scripts.build).toBe("chant build src --lexicon aws");
92
94
  expect(pkg.scripts.dev).toBe("chant build src --lexicon aws --watch");
93
95
  expect(pkg.scripts.lint).toBe("chant lint src");
@@ -115,6 +117,11 @@ describe("initCommand", () => {
115
117
  expect(tsconfig.compilerOptions.rootDir).toBe("./src");
116
118
  expect(tsconfig.include).toContain("src");
117
119
  expect(tsconfig.compilerOptions.paths).toBeUndefined();
120
+ // #3089: bundler resolution accepts the extensionless `./config` imports
121
+ // the templates use; NodeNext rejects them (TS2835).
122
+ expect(tsconfig.compilerOptions.module).toBe("esnext");
123
+ expect(tsconfig.compilerOptions.moduleResolution).toBe("bundler");
124
+ expect(tsconfig.compilerOptions.types).toEqual(["node"]);
118
125
  });
119
126
  });
120
127
 
@@ -62,6 +62,16 @@ export interface InitResult {
62
62
  lexiconModule?: string;
63
63
  }
64
64
 
65
+ /**
66
+ * The devDependencies a scaffolded project gets, from `chant init` and from
67
+ * `chant carve` (#3233). The project's TypeScript is for its editor and `tsc`
68
+ * only; chant parses with its own copy, so any 5.9+ or 7 release works (#3089).
69
+ */
70
+ export const SCAFFOLD_DEV_DEPENDENCIES = {
71
+ "@types/node": "^24.0.0",
72
+ typescript: "^5.9.3 || ^7.0.0",
73
+ } as const;
74
+
65
75
  /**
66
76
  * Generate package.json content
67
77
  */
@@ -88,23 +98,28 @@ function generatePackageJson(
88
98
  ...extraScripts,
89
99
  },
90
100
  dependencies,
91
- devDependencies: {
92
- typescript: "^5.0.0",
93
- },
101
+ devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES },
94
102
  };
95
103
 
96
104
  return JSON.stringify(pkg, null, 2);
97
105
  }
98
106
 
99
107
  /**
100
- * Generate tsconfig.json content with path mappings for .chant/ types
108
+ * Generate tsconfig.json content.
109
+ *
110
+ * `bundler` resolution, because chant resolves a project's imports the way tsx
111
+ * and fold do: `./config` with no extension. NodeNext rejects that form
112
+ * (TS2835), and its suggested `./config.js` makes fold fall back to running the
113
+ * file (#3089). `types` names node because TypeScript 6 and later no longer load
114
+ * every `@types` package by default.
101
115
  */
102
- function generateTsConfig(lexicon: string): string {
116
+ export function generateTsConfig(): string {
103
117
  const config = {
104
118
  compilerOptions: {
105
119
  target: "ES2022",
106
- module: "NodeNext",
107
- moduleResolution: "NodeNext",
120
+ module: "esnext",
121
+ moduleResolution: "bundler",
122
+ types: ["node"],
108
123
  strict: true,
109
124
  esModuleInterop: true,
110
125
  skipLibCheck: true,
@@ -307,7 +322,7 @@ export async function initCommand(options: InitOptions): Promise<InitResult> {
307
322
  // Generate tsconfig.json
308
323
  writeIfNotExists(
309
324
  join(targetDir, "tsconfig.json"),
310
- generateTsConfig(options.lexicon),
325
+ generateTsConfig(),
311
326
  "tsconfig.json",
312
327
  createdFiles,
313
328
  warnings,
@@ -281,6 +281,43 @@ export const b = new Bucket({ config: { y: 2 } });
281
281
  expect(result.diagnostics.some(d => d.ruleId === "COR001")).toBe(true);
282
282
  expect(result.diagnostics.filter(d => d.ruleId === "COR001")).toHaveLength(2);
283
283
  });
284
+
285
+ // #2511: a project-local rule that throws is an error, never a clean pass.
286
+ test("a project-local rule that throws fails the lint and names the rule, file and message", async () => {
287
+ await mkdir(join(testDir, ".chant", "rules"), { recursive: true });
288
+ await writeFile(
289
+ join(testDir, ".chant", "rules", "local.ts"),
290
+ `
291
+ export const boom = {
292
+ id: "LOCAL_BOOM",
293
+ severity: "warning",
294
+ category: "correctness",
295
+ check() { throw new Error("cannot read sibling file"); },
296
+ };
297
+ export const fine = {
298
+ id: "LOCAL_FINE",
299
+ severity: "warning",
300
+ category: "correctness",
301
+ check(ctx) {
302
+ return [{ file: ctx.filePath, line: 1, column: 1, ruleId: "LOCAL_FINE", severity: "warning", message: "fine ran" }];
303
+ },
304
+ };
305
+ `,
306
+ );
307
+ const file = join(testDir, "clean.ts");
308
+ await writeFile(file, `// chant-disable\nexport const config = { a: 1 };\n`);
309
+
310
+ const result = await lintCommand({ path: testDir, format: "stylish" });
311
+
312
+ expect(result.success).toBe(false);
313
+ const threw = result.diagnostics.filter((d) => d.ruleId === "LOCAL_BOOM");
314
+ expect(threw).toHaveLength(1);
315
+ expect(threw[0].severity).toBe("error");
316
+ expect(threw[0].file).toBe(file);
317
+ expect(threw[0].message).toContain("LOCAL_BOOM");
318
+ expect(threw[0].message).toContain(file);
319
+ expect(threw[0].message).toContain("cannot read sibling file");
320
+ });
284
321
  });
285
322
 
286
323
  describe("isLintRule", () => {