@intentius/chant 0.56.0 → 0.58.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 (515) hide show
  1. package/dist/audit/catalog.d.ts +51 -1
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/core.d.ts +20 -1
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts +14 -8
  6. package/dist/audit/discover.d.ts.map +1 -1
  7. package/dist/audit/lineage.d.ts +10 -0
  8. package/dist/audit/lineage.d.ts.map +1 -0
  9. package/dist/audit/prior-art.d.ts +385 -0
  10. package/dist/audit/prior-art.d.ts.map +1 -0
  11. package/dist/audit/proof.d.ts +16 -0
  12. package/dist/audit/proof.d.ts.map +1 -1
  13. package/dist/audit/report-html.d.ts.map +1 -1
  14. package/dist/audit/report-model.d.ts +8 -1
  15. package/dist/audit/report-model.d.ts.map +1 -1
  16. package/dist/audit/report.d.ts.map +1 -1
  17. package/dist/audit/rules-doc.d.ts +3 -0
  18. package/dist/audit/rules-doc.d.ts.map +1 -1
  19. package/dist/audit/secrets.d.ts +15 -0
  20. package/dist/audit/secrets.d.ts.map +1 -1
  21. package/dist/audit/terraform-state.d.ts +46 -0
  22. package/dist/audit/terraform-state.d.ts.map +1 -0
  23. package/dist/build.d.ts +17 -1
  24. package/dist/build.d.ts.map +1 -1
  25. package/dist/claimed-fields.d.ts +161 -0
  26. package/dist/claimed-fields.d.ts.map +1 -0
  27. package/dist/cli/build-params-cli.d.ts +2 -2
  28. package/dist/cli/command-group.d.ts +14 -0
  29. package/dist/cli/command-group.d.ts.map +1 -1
  30. package/dist/cli/commands/audit.d.ts +17 -1
  31. package/dist/cli/commands/audit.d.ts.map +1 -1
  32. package/dist/cli/commands/build.d.ts.map +1 -1
  33. package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
  34. package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
  35. package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
  36. package/dist/cli/commands/import.d.ts.map +1 -1
  37. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
  38. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
  39. package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
  40. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  41. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  42. package/dist/cli/commands/init.d.ts.map +1 -1
  43. package/dist/cli/commands/lint.d.ts.map +1 -1
  44. package/dist/cli/commands/onboard.d.ts +2 -0
  45. package/dist/cli/commands/onboard.d.ts.map +1 -1
  46. package/dist/cli/handlers/build.d.ts.map +1 -1
  47. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  48. package/dist/cli/handlers/operator.d.ts +82 -16
  49. package/dist/cli/handlers/operator.d.ts.map +1 -1
  50. package/dist/cli/handlers/run.d.ts +49 -42
  51. package/dist/cli/handlers/run.d.ts.map +1 -1
  52. package/dist/cli/main.d.ts +28 -1
  53. package/dist/cli/main.d.ts.map +1 -1
  54. package/dist/cli/mcp/op-tools.d.ts +16 -1
  55. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  56. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  57. package/dist/cli/mcp/resources/context.d.ts.map +1 -1
  58. package/dist/cli/registry.d.ts +26 -9
  59. package/dist/cli/registry.d.ts.map +1 -1
  60. package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
  61. package/dist/components/auto-release.d.ts +10 -20
  62. package/dist/components/auto-release.d.ts.map +1 -1
  63. package/dist/components/capability.d.ts +4 -4
  64. package/dist/components/cli-support.d.ts +20 -21
  65. package/dist/components/cli-support.d.ts.map +1 -1
  66. package/dist/components/component.d.ts +3 -3
  67. package/dist/components/component.d.ts.map +1 -1
  68. package/dist/components/driver-output.d.ts.map +1 -1
  69. package/dist/components/driver.d.ts +66 -36
  70. package/dist/components/driver.d.ts.map +1 -1
  71. package/dist/components/index.d.ts +1 -2
  72. package/dist/components/index.d.ts.map +1 -1
  73. package/dist/components/manifest-persistence.d.ts +1 -9
  74. package/dist/components/manifest-persistence.d.ts.map +1 -1
  75. package/dist/components/run-progress.d.ts +6 -6
  76. package/dist/components/run-progress.d.ts.map +1 -1
  77. package/dist/components/verbs/run-agent.d.ts +9 -15
  78. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  79. package/dist/components/verbs/verify.d.ts +2 -2
  80. package/dist/deep-observation.d.ts +17 -0
  81. package/dist/deep-observation.d.ts.map +1 -1
  82. package/dist/discovery/files.d.ts +4 -4
  83. package/dist/discovery/fold-import.d.ts.map +1 -1
  84. package/dist/discovery/param-deps.d.ts +33 -0
  85. package/dist/discovery/param-deps.d.ts.map +1 -1
  86. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  87. package/dist/discovery/sandbox/config-wire.d.ts +2 -2
  88. package/dist/fold/foldable-helpers.d.ts +5 -1
  89. package/dist/fold/foldable-helpers.d.ts.map +1 -1
  90. package/dist/fold-provenance.d.ts +236 -0
  91. package/dist/fold-provenance.d.ts.map +1 -0
  92. package/dist/graph-ops.d.ts +1 -1
  93. package/dist/held-elsewhere.d.ts +85 -0
  94. package/dist/held-elsewhere.d.ts.map +1 -0
  95. package/dist/import/ir-utils.d.ts +1 -1
  96. package/dist/import/ir-utils.d.ts.map +1 -1
  97. package/dist/import/parser.d.ts +33 -0
  98. package/dist/import/parser.d.ts.map +1 -1
  99. package/dist/index.d.ts +3 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/kubectl-context.d.ts +3 -3
  102. package/dist/lexicon-config.d.ts +4 -4
  103. package/dist/lexicon-plugin-helpers.d.ts +1 -1
  104. package/dist/lexicon.d.ts +104 -14
  105. package/dist/lexicon.d.ts.map +1 -1
  106. package/dist/lifecycle/change-set.d.ts +13 -0
  107. package/dist/lifecycle/change-set.d.ts.map +1 -1
  108. package/dist/lifecycle/deep-diff.d.ts +133 -6
  109. package/dist/lifecycle/deep-diff.d.ts.map +1 -1
  110. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  111. package/dist/lifecycle/gate-ledger.d.ts +71 -3
  112. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  113. package/dist/lifecycle/index.d.ts +1 -0
  114. package/dist/lifecycle/index.d.ts.map +1 -1
  115. package/dist/lifecycle/release-ledger.d.ts +2 -2
  116. package/dist/lifecycle/run-ledger.d.ts +53 -0
  117. package/dist/lifecycle/run-ledger.d.ts.map +1 -0
  118. package/dist/lifecycle/symptoms.d.ts +3 -3
  119. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  120. package/dist/lint/config.d.ts +81 -2
  121. package/dist/lint/config.d.ts.map +1 -1
  122. package/dist/lint/post-synth.d.ts +55 -2
  123. package/dist/lint/post-synth.d.ts.map +1 -1
  124. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
  125. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
  126. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
  127. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
  128. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
  129. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
  130. package/dist/lint/rules/comp/index.d.ts +1 -1
  131. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  132. package/dist/lint/rules/op/index.d.ts +16 -0
  133. package/dist/lint/rules/op/index.d.ts.map +1 -0
  134. package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
  135. package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
  136. package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
  137. package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
  138. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
  139. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
  140. package/dist/lint/rules/op/support.d.ts +12 -0
  141. package/dist/lint/rules/op/support.d.ts.map +1 -0
  142. package/dist/lint/suppressions.d.ts +108 -0
  143. package/dist/lint/suppressions.d.ts.map +1 -0
  144. package/dist/live-endpoint.d.ts +1 -1
  145. package/dist/op/activities/activity-contracts.d.ts +54 -0
  146. package/dist/op/activities/activity-contracts.d.ts.map +1 -0
  147. package/dist/op/activities/apply.d.ts +262 -0
  148. package/dist/op/activities/apply.d.ts.map +1 -0
  149. package/dist/op/activities/build.d.ts +13 -0
  150. package/dist/op/activities/build.d.ts.map +1 -0
  151. package/dist/op/activities/converge.d.ts +110 -0
  152. package/dist/op/activities/converge.d.ts.map +1 -0
  153. package/dist/op/activities/env-teardown.d.ts +76 -0
  154. package/dist/op/activities/env-teardown.d.ts.map +1 -0
  155. package/dist/op/activities/guard-validate.d.ts +64 -0
  156. package/dist/op/activities/guard-validate.d.ts.map +1 -0
  157. package/dist/op/activities/http-check.d.ts +34 -0
  158. package/dist/op/activities/http-check.d.ts.map +1 -0
  159. package/dist/op/activities/index.d.ts +31 -0
  160. package/dist/op/activities/index.d.ts.map +1 -0
  161. package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
  162. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
  163. package/dist/op/activities/lifecycle.d.ts +42 -0
  164. package/dist/op/activities/lifecycle.d.ts.map +1 -0
  165. package/dist/op/activities/pipeline-audit.d.ts +84 -0
  166. package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
  167. package/dist/op/activities/policy.d.ts +17 -0
  168. package/dist/op/activities/policy.d.ts.map +1 -0
  169. package/dist/op/activities/reconcile.d.ts +89 -0
  170. package/dist/op/activities/reconcile.d.ts.map +1 -0
  171. package/dist/op/activities/shell.d.ts +13 -0
  172. package/dist/op/activities/shell.d.ts.map +1 -0
  173. package/dist/op/activities/teardown.d.ts +10 -0
  174. package/dist/op/activities/teardown.d.ts.map +1 -0
  175. package/dist/op/activities/util.d.ts +7 -0
  176. package/dist/op/activities/util.d.ts.map +1 -0
  177. package/dist/op/activities/wait.d.ts +28 -0
  178. package/dist/op/activities/wait.d.ts.map +1 -0
  179. package/dist/op/activities/workflow-audit.d.ts +92 -0
  180. package/dist/op/activities/workflow-audit.d.ts.map +1 -0
  181. package/dist/op/activity-contract-registry.d.ts +76 -0
  182. package/dist/op/activity-contract-registry.d.ts.map +1 -0
  183. package/dist/op/activity-contract.d.ts +25 -18
  184. package/dist/op/activity-contract.d.ts.map +1 -1
  185. package/dist/op/activity-failure.d.ts +28 -0
  186. package/dist/op/activity-failure.d.ts.map +1 -0
  187. package/dist/op/activity-profiles.d.ts +118 -0
  188. package/dist/op/activity-profiles.d.ts.map +1 -0
  189. package/dist/op/activity-registry.d.ts +22 -38
  190. package/dist/op/activity-registry.d.ts.map +1 -1
  191. package/dist/op/activity-runtime.d.ts +3 -14
  192. package/dist/op/activity-runtime.d.ts.map +1 -1
  193. package/dist/op/builders.d.ts +84 -29
  194. package/dist/op/builders.d.ts.map +1 -1
  195. package/dist/op/composites/apply-op.d.ts +113 -0
  196. package/dist/op/composites/apply-op.d.ts.map +1 -0
  197. package/dist/op/composites/converge-op.d.ts +120 -0
  198. package/dist/op/composites/converge-op.d.ts.map +1 -0
  199. package/dist/op/composites/index.d.ts +26 -0
  200. package/dist/op/composites/index.d.ts.map +1 -0
  201. package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
  202. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
  203. package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
  204. package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
  205. package/dist/op/composites/reconcile-op.d.ts +57 -0
  206. package/dist/op/composites/reconcile-op.d.ts.map +1 -0
  207. package/dist/op/composites/watch-op.d.ts +60 -0
  208. package/dist/op/composites/watch-op.d.ts.map +1 -0
  209. package/dist/op/composites/workflow-audit-op.d.ts +57 -0
  210. package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
  211. package/dist/op/converge-rule.d.ts +12 -10
  212. package/dist/op/converge-rule.d.ts.map +1 -1
  213. package/dist/op/cron.d.ts +51 -0
  214. package/dist/op/cron.d.ts.map +1 -0
  215. package/dist/op/discover.d.ts +9 -0
  216. package/dist/op/discover.d.ts.map +1 -1
  217. package/dist/op/duration.d.ts +11 -0
  218. package/dist/op/duration.d.ts.map +1 -0
  219. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  220. package/dist/op/gate.d.ts +90 -0
  221. package/dist/op/gate.d.ts.map +1 -0
  222. package/dist/op/generate-pipeline.d.ts +9 -0
  223. package/dist/op/generate-pipeline.d.ts.map +1 -1
  224. package/dist/op/index.d.ts +23 -7
  225. package/dist/op/index.d.ts.map +1 -1
  226. package/dist/op/local-executor.d.ts +114 -28
  227. package/dist/op/local-executor.d.ts.map +1 -1
  228. package/dist/op/local-output.d.ts +11 -1
  229. package/dist/op/local-output.d.ts.map +1 -1
  230. package/dist/op/op-ir.d.ts +184 -0
  231. package/dist/op/op-ir.d.ts.map +1 -0
  232. package/dist/op/op-verb-class.d.ts +10 -2
  233. package/dist/op/op-verb-class.d.ts.map +1 -1
  234. package/dist/op/operator.d.ts +30 -5
  235. package/dist/op/operator.d.ts.map +1 -1
  236. package/dist/op/receipt-store.d.ts +1 -1
  237. package/dist/op/receipt-store.d.ts.map +1 -1
  238. package/dist/op/resource.d.ts +15 -1
  239. package/dist/op/resource.d.ts.map +1 -1
  240. package/dist/op/runtime.d.ts +200 -0
  241. package/dist/op/runtime.d.ts.map +1 -0
  242. package/dist/op/runtimes/local.d.ts +29 -0
  243. package/dist/op/runtimes/local.d.ts.map +1 -0
  244. package/dist/op/step-output-ref.d.ts +15 -13
  245. package/dist/op/step-output-ref.d.ts.map +1 -1
  246. package/dist/op/types.d.ts +79 -27
  247. package/dist/op/types.d.ts.map +1 -1
  248. package/dist/ownership.d.ts +1 -1
  249. package/dist/provenance.d.ts +21 -0
  250. package/dist/provenance.d.ts.map +1 -1
  251. package/dist/serializer-walker.d.ts.map +1 -1
  252. package/dist/stack-output.d.ts +5 -0
  253. package/dist/stack-output.d.ts.map +1 -1
  254. package/package.json +6 -1
  255. package/src/audit/catalog.test.ts +79 -3
  256. package/src/audit/catalog.ts +111 -13
  257. package/src/audit/core.test.ts +26 -0
  258. package/src/audit/core.ts +61 -17
  259. package/src/audit/discover.test.ts +39 -0
  260. package/src/audit/discover.ts +91 -15
  261. package/src/audit/lineage.ts +100 -0
  262. package/src/audit/prior-art.ts +153 -0
  263. package/src/audit/proof.test.ts +67 -0
  264. package/src/audit/proof.ts +70 -0
  265. package/src/audit/report-html.ts +9 -4
  266. package/src/audit/report-model.ts +16 -2
  267. package/src/audit/report.test.ts +33 -0
  268. package/src/audit/report.ts +5 -3
  269. package/src/audit/rules-doc.test.ts +34 -2
  270. package/src/audit/rules-doc.ts +82 -9
  271. package/src/audit/secrets.ts +15 -3
  272. package/src/audit/terraform-state.test.ts +144 -0
  273. package/src/audit/terraform-state.ts +131 -0
  274. package/src/build.ts +31 -1
  275. package/src/claimed-fields.test.ts +145 -0
  276. package/src/claimed-fields.ts +208 -0
  277. package/src/cli/build-params-cli.ts +2 -2
  278. package/src/cli/command-group.ts +14 -0
  279. package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
  280. package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
  281. package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
  282. package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
  283. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
  284. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
  285. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
  286. package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
  287. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
  288. package/src/cli/commands/audit.test.ts +189 -11
  289. package/src/cli/commands/audit.ts +73 -27
  290. package/src/cli/commands/build.test.ts +292 -9
  291. package/src/cli/commands/build.ts +156 -24
  292. package/src/cli/commands/check-lexicon-docs.ts +1 -1
  293. package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
  294. package/src/cli/commands/check-lexicon-examples.ts +42 -10
  295. package/src/cli/commands/import.ts +6 -0
  296. package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
  297. package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
  298. package/src/cli/commands/init-lexicon.test.ts +97 -2
  299. package/src/cli/commands/init-lexicon.ts +4 -2
  300. package/src/cli/commands/init.test.ts +35 -1
  301. package/src/cli/commands/init.ts +14 -3
  302. package/src/cli/commands/lint.test.ts +48 -0
  303. package/src/cli/commands/lint.ts +123 -0
  304. package/src/cli/commands/onboard.test.ts +75 -0
  305. package/src/cli/commands/onboard.ts +54 -23
  306. package/src/cli/handlers/build.test.ts +81 -1
  307. package/src/cli/handlers/build.ts +15 -1
  308. package/src/cli/handlers/graph.test.ts +3 -3
  309. package/src/cli/handlers/lifecycle.test.ts +195 -12
  310. package/src/cli/handlers/lifecycle.ts +123 -6
  311. package/src/cli/handlers/misc.ts +1 -1
  312. package/src/cli/handlers/operator.test.ts +183 -11
  313. package/src/cli/handlers/operator.ts +260 -55
  314. package/src/cli/handlers/run.test.ts +431 -1287
  315. package/src/cli/handlers/run.ts +365 -915
  316. package/src/cli/main.test.ts +23 -15
  317. package/src/cli/main.ts +88 -33
  318. package/src/cli/mcp/op-tools.ts +147 -88
  319. package/src/cli/mcp/resource-handlers.ts +10 -37
  320. package/src/cli/mcp/resources/context.ts +11 -12
  321. package/src/cli/mcp/server.test.ts +25 -27
  322. package/src/cli/mcp/server.ts +2 -2
  323. package/src/cli/registry.ts +26 -9
  324. package/src/codegen/docs.ts +1 -1
  325. package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
  326. package/src/codegen/generate-post-synth-barrel.ts +1 -1
  327. package/src/components/README.md +3 -2
  328. package/src/components/auto-release.test.ts +4 -20
  329. package/src/components/auto-release.ts +17 -42
  330. package/src/components/capability.ts +4 -4
  331. package/src/components/cli-support.test.ts +10 -5
  332. package/src/components/cli-support.ts +52 -44
  333. package/src/components/component.schema.json +2 -2
  334. package/src/components/component.ts +3 -3
  335. package/src/components/driver-output.ts +14 -2
  336. package/src/components/driver.test.ts +92 -22
  337. package/src/components/driver.ts +193 -83
  338. package/src/components/index.ts +1 -6
  339. package/src/components/manifest-persistence.test.ts +2 -20
  340. package/src/components/manifest-persistence.ts +4 -24
  341. package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
  342. package/src/components/run-progress.ts +6 -6
  343. package/src/components/verbs/run-agent.ts +11 -17
  344. package/src/components/verbs/verify.ts +2 -2
  345. package/src/deep-observation.test.ts +75 -0
  346. package/src/deep-observation.ts +48 -0
  347. package/src/discovery/collect.test.ts +3 -3
  348. package/src/discovery/files.ts +4 -4
  349. package/src/discovery/fold-import.ts +105 -2
  350. package/src/discovery/param-deps.test.ts +112 -1
  351. package/src/discovery/param-deps.ts +193 -0
  352. package/src/discovery/sandbox/bundle.ts +15 -1
  353. package/src/discovery/sandbox/config-wire.test.ts +2 -2
  354. package/src/discovery/sandbox/config-wire.ts +2 -2
  355. package/src/fold/fold.test.ts +56 -0
  356. package/src/fold/foldable-helpers.ts +81 -1
  357. package/src/fold-provenance-exclusion.test.ts +186 -0
  358. package/src/fold-provenance.test.ts +495 -0
  359. package/src/fold-provenance.ts +441 -0
  360. package/src/graph-ops.test.ts +2 -2
  361. package/src/graph-ops.ts +1 -1
  362. package/src/held-elsewhere.test.ts +102 -0
  363. package/src/held-elsewhere.ts +114 -0
  364. package/src/import/ir-utils.ts +11 -1
  365. package/src/import/parser.ts +35 -0
  366. package/src/index.ts +3 -0
  367. package/src/kubectl-context.ts +3 -3
  368. package/src/lexicon-config.test.ts +5 -5
  369. package/src/lexicon-config.ts +4 -4
  370. package/src/lexicon-plugin-helpers.ts +1 -1
  371. package/src/lexicon.ts +120 -14
  372. package/src/lifecycle/change-set.test.ts +49 -0
  373. package/src/lifecycle/change-set.ts +67 -0
  374. package/src/lifecycle/converge-ledger.ts +1 -1
  375. package/src/lifecycle/deep-diff.test.ts +267 -14
  376. package/src/lifecycle/deep-diff.ts +217 -14
  377. package/src/lifecycle/deep-observe.test.ts +3 -1
  378. package/src/lifecycle/deep-observe.ts +16 -6
  379. package/src/lifecycle/gate-ledger.test.ts +74 -2
  380. package/src/lifecycle/gate-ledger.ts +143 -36
  381. package/src/lifecycle/index.ts +1 -0
  382. package/src/lifecycle/release-ledger.ts +2 -2
  383. package/src/lifecycle/run-ledger.test.ts +268 -0
  384. package/src/lifecycle/run-ledger.ts +201 -0
  385. package/src/lifecycle/symptoms.ts +3 -3
  386. package/src/lint/config.test.ts +82 -1
  387. package/src/lint/config.ts +112 -3
  388. package/src/lint/policy.test.ts +1 -1
  389. package/src/lint/post-synth.test.ts +31 -0
  390. package/src/lint/post-synth.ts +54 -1
  391. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
  392. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
  393. package/src/lint/rules/comp/comp.test.ts +1 -1
  394. package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
  395. package/src/lint/rules/comp/index.ts +3 -3
  396. package/src/lint/rules/op/index.ts +23 -0
  397. package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
  398. package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
  399. package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
  400. package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
  401. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
  402. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
  403. package/src/lint/rules/op/support.ts +11 -0
  404. package/src/lint/suppressions.test.ts +163 -0
  405. package/src/lint/suppressions.ts +204 -0
  406. package/src/live-endpoint.ts +1 -1
  407. package/src/op/activities/activity-contracts.ts +66 -0
  408. package/src/op/activities/apply.test.ts +567 -0
  409. package/src/op/activities/apply.ts +662 -0
  410. package/src/op/activities/build.ts +26 -0
  411. package/src/op/activities/converge.test.ts +330 -0
  412. package/src/op/activities/converge.ts +449 -0
  413. package/src/op/activities/env-teardown.test.ts +187 -0
  414. package/src/op/activities/env-teardown.ts +171 -0
  415. package/src/op/activities/guard-validate.test.ts +139 -0
  416. package/src/op/activities/guard-validate.ts +223 -0
  417. package/src/op/activities/http-check.test.ts +48 -0
  418. package/src/op/activities/http-check.ts +55 -0
  419. package/src/op/activities/index.ts +119 -0
  420. package/src/op/activities/lexicon-upgrade.test.ts +492 -0
  421. package/src/op/activities/lexicon-upgrade.ts +673 -0
  422. package/src/op/activities/lifecycle.ts +85 -0
  423. package/src/op/activities/pipeline-audit.test.ts +67 -0
  424. package/src/op/activities/pipeline-audit.ts +201 -0
  425. package/src/op/activities/policy.test.ts +19 -0
  426. package/src/op/activities/policy.ts +37 -0
  427. package/src/op/activities/reconcile.test.ts +81 -0
  428. package/src/op/activities/reconcile.ts +187 -0
  429. package/src/op/activities/shell.ts +26 -0
  430. package/src/op/activities/teardown.ts +22 -0
  431. package/src/op/activities/util.ts +6 -0
  432. package/src/op/activities/wait.ts +69 -0
  433. package/src/op/activities/workflow-audit.test.ts +90 -0
  434. package/src/op/activities/workflow-audit.ts +203 -0
  435. package/src/op/activity-contract-registry.test.ts +98 -0
  436. package/src/op/activity-contract-registry.ts +114 -0
  437. package/src/op/activity-contract.test.ts +1 -1
  438. package/src/op/activity-contract.ts +37 -33
  439. package/src/op/activity-failure.ts +34 -0
  440. package/src/op/activity-profiles.test.ts +56 -0
  441. package/src/op/activity-profiles.ts +116 -0
  442. package/src/op/activity-registry.test.ts +37 -28
  443. package/src/op/activity-registry.ts +27 -56
  444. package/src/op/activity-runtime.ts +3 -47
  445. package/src/op/builders-exports.test.ts +0 -49
  446. package/src/op/builders-typed.test.ts +164 -0
  447. package/src/op/builders.ts +123 -39
  448. package/src/op/composites/apply-op.ts +208 -0
  449. package/src/op/composites/composites.test.ts +366 -0
  450. package/src/op/composites/converge-op.test.ts +168 -0
  451. package/src/op/composites/converge-op.ts +214 -0
  452. package/src/op/composites/index.ts +26 -0
  453. package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
  454. package/src/op/composites/lexicon-upgrade-op.ts +134 -0
  455. package/src/op/composites/pipeline-audit-op.test.ts +25 -0
  456. package/src/op/composites/pipeline-audit-op.ts +78 -0
  457. package/src/op/composites/reconcile-op.test.ts +51 -0
  458. package/src/op/composites/reconcile-op.ts +107 -0
  459. package/src/op/composites/watch-op.ts +108 -0
  460. package/src/op/composites/workflow-audit-op.test.ts +25 -0
  461. package/src/op/composites/workflow-audit-op.ts +88 -0
  462. package/src/op/converge-rule.ts +12 -10
  463. package/src/op/cron.test.ts +128 -0
  464. package/src/op/cron.ts +149 -0
  465. package/src/op/discover-root.test.ts +105 -1
  466. package/src/op/discover.test.ts +6 -2
  467. package/src/op/discover.ts +84 -16
  468. package/src/op/duration.ts +21 -0
  469. package/src/op/effect-step.test.ts +26 -11
  470. package/src/op/emulator-lifecycle.ts +1 -2
  471. package/src/op/gate.ts +155 -0
  472. package/src/op/generate-pipeline.test.ts +65 -3
  473. package/src/op/generate-pipeline.ts +19 -2
  474. package/src/op/index.ts +39 -6
  475. package/src/op/local-executor.test.ts +163 -34
  476. package/src/op/local-executor.ts +370 -102
  477. package/src/op/local-output.test.ts +95 -11
  478. package/src/op/local-output.ts +33 -4
  479. package/src/op/op-ir.test.ts +281 -0
  480. package/src/op/op-ir.ts +417 -0
  481. package/src/op/op-verb-class.ts +19 -5
  482. package/src/op/op.test.ts +26 -5
  483. package/src/op/operator.test.ts +175 -6
  484. package/src/op/operator.ts +63 -16
  485. package/src/op/receipt-store.ts +1 -1
  486. package/src/op/resource.ts +20 -2
  487. package/src/op/runtime.ts +203 -0
  488. package/src/op/runtimes/local.test.ts +181 -0
  489. package/src/op/runtimes/local.ts +212 -0
  490. package/src/op/step-output-ref.ts +15 -13
  491. package/src/op/types.ts +84 -24
  492. package/src/ownership.ts +1 -1
  493. package/src/provenance.test.ts +6 -0
  494. package/src/provenance.ts +21 -1
  495. package/src/serializer-walker.test.ts +42 -0
  496. package/src/serializer-walker.ts +21 -2
  497. package/src/stack-output.ts +6 -1
  498. package/dist/cli/handlers/op-progress.d.ts +0 -90
  499. package/dist/cli/handlers/op-progress.d.ts.map +0 -1
  500. package/dist/cli/handlers/run-client.d.ts +0 -127
  501. package/dist/cli/handlers/run-client.d.ts.map +0 -1
  502. package/dist/cli/handlers/run-report.d.ts +0 -5
  503. package/dist/cli/handlers/run-report.d.ts.map +0 -1
  504. package/dist/components/temporal-codegen-loader.d.ts +0 -27
  505. package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
  506. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
  507. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
  508. package/src/cli/handlers/op-progress.test.ts +0 -268
  509. package/src/cli/handlers/op-progress.ts +0 -248
  510. package/src/cli/handlers/run-client.test.ts +0 -82
  511. package/src/cli/handlers/run-client.ts +0 -219
  512. package/src/cli/handlers/run-report.test.ts +0 -62
  513. package/src/cli/handlers/run-report.ts +0 -122
  514. package/src/components/temporal-codegen-loader.ts +0 -41
  515. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
@@ -1,10 +1,11 @@
1
1
  import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
- import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, readdirSync, realpathSync } from "fs";
2
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, readdirSync, realpathSync, symlinkSync } from "fs";
3
3
  import { execFileSync } from "child_process";
4
4
  import { join, dirname } from "path";
5
5
  import { tmpdir } from "os";
6
- import { fileURLToPath } from "url";
6
+ import { fileURLToPath, pathToFileURL } from "url";
7
7
  import { initLexiconCommand } from "./init-lexicon";
8
+ import { checkLexicon } from "./check-lexicon";
8
9
 
9
10
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
11
  const FIXTURE_DIR = join(__dirname, "__fixtures__", "init-lexicon-output");
@@ -44,6 +45,8 @@ describe("initLexiconCommand", () => {
44
45
  "src/codegen/naming.ts",
45
46
  "src/codegen/package.ts",
46
47
  "src/codegen/docs.ts",
48
+ "src/codegen/docs-cli.ts",
49
+ "src/package-cli.ts",
47
50
  "src/spec/fetch.ts",
48
51
  "src/spec/parse.ts",
49
52
  "src/lint/rules/sample.ts",
@@ -245,6 +248,16 @@ describe("scaffold content validation", () => {
245
248
  expect(pkg.scripts.build).toContain("tsconfig.build.json");
246
249
  });
247
250
 
251
+ // #2090, the scaffolded package.json failed tier 1 as generated: a bare
252
+ // string exports["."], a build script that never deletes emitted .js, and
253
+ // a prepack that never bundled, so dist/manifest.json never existed.
254
+ test("package.json exports[\".\"].default is ./src/index.ts, build deletes emitted JS, prepack bundles (#2090)", () => {
255
+ const pkg = JSON.parse(readFileSync(join(targetDir, "package.json"), "utf-8"));
256
+ expect(pkg.exports["."].default).toBe("./src/index.ts");
257
+ expect(pkg.scripts.build).toContain("-delete");
258
+ expect(pkg.scripts.prepack).toContain("bundle");
259
+ });
260
+
248
261
  test("tsconfig.build.json uses bundler resolution + the development condition (#749)", () => {
249
262
  const cfg = JSON.parse(readFileSync(join(targetDir, "tsconfig.build.json"), "utf-8"));
250
263
  expect(cfg.compilerOptions.moduleResolution).toBe("bundler");
@@ -308,6 +321,88 @@ describe("scaffold content validation", () => {
308
321
  });
309
322
  });
310
323
 
324
+ // #2090, a fresh scaffold used to fail 5 tier-1 checks before the author
325
+ // wrote anything. The docs-cli.ts gap (section 1) and the package.json/bundle
326
+ // gap (section 2) together fixed the packaging-shape check and let
327
+ // `npm run bundle` actually produce dist/manifest.json with a chantVersion.
328
+ describe("a fresh scaffold's tier-1 completeness (#2090)", () => {
329
+ let root: string;
330
+ let dir: string;
331
+
332
+ beforeEach(async () => {
333
+ root = join(tmpdir(), `chant-scaffold-tier1-${Date.now()}-${Math.random().toString(36).slice(2)}`);
334
+ mkdirSync(root, { recursive: true });
335
+ // The scaffold's tsconfig.json extends "../../tsconfig.json" (mirroring
336
+ // lexicons/<name>/tsconfig.json's real "../../tsconfig.json" -> repo
337
+ // root), so loading it needs a real file two levels up.
338
+ writeFileSync(join(root, "tsconfig.json"), "{}\n");
339
+
340
+ // A self-contained node_modules so the scaffold's own runtime imports of
341
+ // "@intentius/chant/*" resolve exactly as they would in the real
342
+ // monorepo, without touching the real repo's node_modules or lexicons/.
343
+ mkdirSync(join(root, "node_modules/@intentius"), { recursive: true });
344
+ symlinkSync(
345
+ join(__dirname, "..", "..", ".."), // commands -> cli -> src -> packages/core
346
+ join(root, "node_modules/@intentius/chant"),
347
+ "dir",
348
+ );
349
+
350
+ dir = join(root, "lexicons", "acme");
351
+ await initLexiconCommand({ name: "acme", path: dir });
352
+
353
+ // Bypass the generate() TODO throw. A real spec fetcher/parser is the
354
+ // author's job, not this test's. writeGeneratedFiles resolves its own
355
+ // target so a no-op stub is fine.
356
+ writeFileSync(
357
+ join(dir, "src/codegen/generate.ts"),
358
+ [
359
+ "export async function generate() {",
360
+ " return { resources: 0, properties: 0, enums: 0, lexiconJSON: '{}', typesDTS: '', indexTS: '' };",
361
+ "}",
362
+ "export function writeGeneratedFiles() {}",
363
+ "",
364
+ ].join("\n"),
365
+ );
366
+
367
+ // Run the fixed bundle pipeline for real, proving section 2's package.json
368
+ // + package-cli.ts changes actually produce dist/manifest.json, not just
369
+ // that the scripts look right.
370
+ const packageMod = (await import(pathToFileURL(join(dir, "src/codegen/package.ts")).href)) as {
371
+ packageLexicon: (opts?: { verbose?: boolean }) => Promise<{ spec: unknown }>;
372
+ };
373
+ const { spec } = await packageMod.packageLexicon({ verbose: false });
374
+
375
+ const bundleMod = (await import(
376
+ pathToFileURL(join(root, "node_modules/@intentius/chant/src/codegen/package.ts")).href
377
+ )) as { writeBundleSpec: (spec: unknown, distDir: string) => void };
378
+ bundleMod.writeBundleSpec(spec, join(dir, "dist"));
379
+ });
380
+
381
+ afterEach(() => {
382
+ rmSync(root, { recursive: true, force: true });
383
+ });
384
+
385
+ test("the fixed bundle pipeline actually produces dist/manifest.json with a chantVersion", () => {
386
+ expect(existsSync(join(dir, "dist/manifest.json"))).toBe(true);
387
+ const manifest = JSON.parse(readFileSync(join(dir, "dist/manifest.json"), "utf-8"));
388
+ expect(typeof manifest.chantVersion).toBe("string");
389
+ expect(manifest.chantVersion.length).toBeGreaterThan(0);
390
+ });
391
+
392
+ // Only real author work should remain. "Every shipped example builds..."
393
+ // also fails here, but for a reason outside this issue's scope: the
394
+ // scaffold's getting-started example has every line commented out (nothing
395
+ // to build yet), which is true independent of sections 1 and 2 above.
396
+ test("fails only on real author work, not on anything sections 1-2 fix", async () => {
397
+ const result = await checkLexicon(dir);
398
+ const tier1Failures = result.items.filter((i) => i.tier === 1 && !i.pass).map((i) => i.name);
399
+ expect(tier1Failures).toEqual([
400
+ "postSynthChecks() returns at least 1 check",
401
+ "Every shipped example builds and passes its own post-synth checks",
402
+ ]);
403
+ });
404
+ });
405
+
311
406
  // ── Fixture snapshot tests ──────────────────────────────────────────
312
407
 
313
408
  describe("init-lexicon fixture snapshot", () => {
@@ -4,11 +4,11 @@ import { formatSuccess, formatWarning } from "../format";
4
4
 
5
5
  // Template generators
6
6
  import { generatePluginTs, generateIndexTs } from "./init-lexicon/templates/plugin";
7
- import { generateCodegenGenerateTs, generateCodegenGenerateCliTs, generateCodegenNamingTs, generateCodegenPackageTs, generateCodegenDocsTs } from "./init-lexicon/templates/codegen";
7
+ import { generateCodegenGenerateTs, generateCodegenGenerateCliTs, generateCodegenNamingTs, generateCodegenPackageTs, generateCodegenDocsTs, generateCodegenDocsCliTs } from "./init-lexicon/templates/codegen";
8
8
  import { generateSpecFetchTs, generateSpecParseTs } from "./init-lexicon/templates/spec";
9
9
  import { generateSampleRuleTs, generateLintRulesIndexTs } from "./init-lexicon/templates/lint";
10
10
  import { generateLspCompletionsTs, generateLspHoverTs } from "./init-lexicon/templates/lsp";
11
- import { generatePackageJson, generateTsConfig, generateTsConfigBuild, generateJustfile, generateGitignore, generateReadme, generateSerializerTs, generateValidateTs, generateValidateCliTs } from "./init-lexicon/templates/project";
11
+ import { generatePackageJson, generateTsConfig, generateTsConfigBuild, generateJustfile, generateGitignore, generateReadme, generateSerializerTs, generateValidateTs, generateValidateCliTs, generatePackageCliTs } from "./init-lexicon/templates/project";
12
12
  import { generatePluginTestTs, generateSerializerTestTs, generateCompletionsTestTs, generateHoverTestTs } from "./init-lexicon/templates/tests";
13
13
  import { generateDocsPackageJson, generateDocsTsConfig, generateDocsAstroConfig, generateDocsContentConfig, generateDocsIndexMdx, generateDocsGettingStartedMdx } from "./init-lexicon/templates/docs";
14
14
  import { generateExamplePackageJson, generateExampleInfraTs } from "./init-lexicon/templates/examples";
@@ -137,6 +137,7 @@ export async function initLexiconCommand(options: InitLexiconOptions): Promise<I
137
137
  "src/codegen/naming.ts": generateCodegenNamingTs(),
138
138
  "src/codegen/package.ts": generateCodegenPackageTs(name),
139
139
  "src/codegen/docs.ts": generateCodegenDocsTs(name),
140
+ "src/codegen/docs-cli.ts": generateCodegenDocsCliTs(),
140
141
  "src/spec/fetch.ts": generateSpecFetchTs(),
141
142
  "src/spec/parse.ts": generateSpecParseTs(),
142
143
  "src/lint/rules/sample.ts": generateSampleRuleTs(names),
@@ -149,6 +150,7 @@ export async function initLexiconCommand(options: InitLexiconOptions): Promise<I
149
150
  "src/serializer.test.ts": generateSerializerTestTs(name, names),
150
151
  "src/validate.ts": generateValidateTs(name),
151
152
  "src/validate-cli.ts": generateValidateCliTs(),
153
+ "src/package-cli.ts": generatePackageCliTs(),
152
154
  "package.json": generatePackageJson(name, names),
153
155
  "tsconfig.json": generateTsConfig(),
154
156
  "tsconfig.build.json": generateTsConfigBuild(),
@@ -348,5 +348,39 @@ describe("initCommand", () => {
348
348
  expect(pipeline).toContain("NodePipeline");
349
349
  });
350
350
  });
351
- });
352
351
 
352
+ // chant #2129 — core writes `chant.config.ts` before a plugin's root files
353
+ // and `writeIfNotExists` keeps the first one, so a template that ships its
354
+ // own config used to be discarded in silence. The template's wins now: it
355
+ // is the only one that knows the config namespace the scaffold needs.
356
+ test("a template's own chant.config.ts wins over the generic one", async () => {
357
+ await withTestDir(async (testDir) => {
358
+ const result = await initCommand({
359
+ path: testDir,
360
+ lexicon: "fountain",
361
+ template: "steward",
362
+ skipMcp: true,
363
+ skipInstall: true,
364
+ });
365
+
366
+ expect(result.success).toBe(true);
367
+ expect(result.createdFiles).toContain("chant.config.ts");
368
+ // Written once, so no "already exists, skipping" warning about it.
369
+ expect(result.warnings.filter((w) => w.includes("chant.config.ts"))).toEqual([]);
370
+
371
+ const config = readFileSync(join(testDir, "chant.config.ts"), "utf-8");
372
+ expect(config).toContain("fountain:");
373
+ expect(config).toContain('token: { env: "FOUNTAIN_TOKEN" }');
374
+ expect(result.createdFiles).toContain("src/prod-watch.op.ts");
375
+ });
376
+ });
377
+
378
+ test("a template without a config still gets the generic one", async () => {
379
+ await withTestDir(async (testDir) => {
380
+ await initCommand({ path: testDir, lexicon: "fountain", skipMcp: true, skipInstall: true });
381
+ const config = readFileSync(join(testDir, "chant.config.ts"), "utf-8");
382
+ expect(config).toContain('lexicons: ["fountain"]');
383
+ expect(config).not.toContain("profiles");
384
+ });
385
+ });
386
+ });
@@ -343,10 +343,17 @@ export async function initCommand(options: InitOptions): Promise<InitResult> {
343
343
  warnings,
344
344
  );
345
345
 
346
- // Generate chant.config.ts
346
+ // Generate chant.config.ts. A template that ships its own wins: core's
347
+ // version knows only the lexicon name, while a template that declares a
348
+ // config namespace (fountain's steward scaffold and its `fountain.profiles`
349
+ // block, chant #2129) is scaffolding a project that needs it to run at all.
350
+ // The root-file loop below runs *after* this write, and `writeIfNotExists`
351
+ // keeps the first file, so a template's config would otherwise be discarded
352
+ // in silence — see lexicons/cedar/src/init-templates.ts, which documents
353
+ // having had to work around exactly that.
347
354
  writeIfNotExists(
348
355
  join(targetDir, "chant.config.ts"),
349
- generateChantConfig(options.lexicon),
356
+ templateSet?.root?.["chant.config.ts"] ?? generateChantConfig(options.lexicon),
350
357
  "chant.config.ts",
351
358
  createdFiles,
352
359
  warnings,
@@ -372,9 +379,13 @@ export async function initCommand(options: InitOptions): Promise<InitResult> {
372
379
  warnings,
373
380
  );
374
381
  }
375
- // Write root scaffold files (e.g. index.js, test.js, Dockerfile)
382
+ // Write root scaffold files (e.g. index.js, test.js, Dockerfile).
383
+ // `chant.config.ts` is skipped: it was already written above, from this
384
+ // same template set, and re-offering it here would only produce an
385
+ // "already exists, skipping" warning about a file the template supplied.
376
386
  if (templateSet.root) {
377
387
  for (const [filename, content] of Object.entries(templateSet.root)) {
388
+ if (filename === "chant.config.ts") continue;
378
389
  writeIfNotExists(
379
390
  join(targetDir, filename),
380
391
  content,
@@ -69,6 +69,54 @@ export const b = new Bucket({ encryption: { algo: "AES256" } });
69
69
  expect(result.diagnostics.some((d) => d.ruleId === "COR001")).toBe(true);
70
70
  });
71
71
 
72
+ // #2122 (epic #2114 sub-issue 6) — OPS013 is a core-owned Op-model
73
+ // post-synth check, run over every `*.op.ts` file `chant lint` finds under
74
+ // the target path with no lexicon or build needed. This is the acceptance
75
+ // criterion: it fires on a fixture with a dangling `stepOutput` reference,
76
+ // on a project with no lexicons configured (no `plugins` in `options`
77
+ // below, the same as every other test in this file).
78
+ test("OPS013 fires on a dangling stepOutput reference with no lexicons configured", async () => {
79
+ await writeFile(
80
+ join(testDir, "reconcile.op.ts"),
81
+ `
82
+ export default {
83
+ [Symbol.for("chant.declarable")]: true,
84
+ entityType: "Chant::Op",
85
+ lexicon: "chant",
86
+ kind: "resource",
87
+ props: {
88
+ name: "reconcile",
89
+ overview: "test",
90
+ phases: [
91
+ { name: "Phase", steps: [
92
+ {
93
+ kind: "activity",
94
+ fn: "httpCheck",
95
+ args: {
96
+ url: "http://x",
97
+ contains: { [Symbol.for("chant.op.stepOutputRef")]: true, kind: "step-output-ref", step: "nope", path: "x" },
98
+ },
99
+ },
100
+ ] },
101
+ ],
102
+ },
103
+ };
104
+ `,
105
+ );
106
+
107
+ const options: LintOptions = {
108
+ path: testDir,
109
+ format: "stylish",
110
+ };
111
+
112
+ const result = await lintCommand(options);
113
+
114
+ expect(result.success).toBe(false);
115
+ expect(
116
+ result.diagnostics.some((d) => d.ruleId === "OPS013" && d.message.includes('unknown step id "nope"')),
117
+ ).toBe(true);
118
+ });
119
+
72
120
  test("formats output as JSON", async () => {
73
121
  await writeFile(
74
122
  join(testDir, "nested.ts"),
@@ -13,6 +13,9 @@ import { loadComponentChecks } from "../../lint/rules/comp/index";
13
13
  import { runComponentChecks, type ComponentCheckDiagnostic } from "../../lint/component-checks";
14
14
  import { buildCapabilityRegistry } from "../../components/capability-plugin-loader";
15
15
  import type { RollbackPolicy } from "../../components/capability";
16
+ import { coreOpChecks } from "../../lint/rules/op";
17
+ import { loadActivityContracts } from "../../op/activity-contract-registry";
18
+ import { runPostSynthChecks } from "../../lint/post-synth";
16
19
  import { rule } from "../../lint/declarative";
17
20
  import { watchDirectory, formatTimestamp, formatChangedFiles } from "../watch";
18
21
  import { formatError, formatInfo } from "../format";
@@ -420,6 +423,113 @@ async function runComponentCheckDiagnostics(
420
423
  return { diagnostics, suppressed };
421
424
  }
422
425
 
426
+ /**
427
+ * Run the OPS* Op-model post-synth checks (#2122, epic #2114 sub-issue 6 —
428
+ * OPS012/OPS013/OPS014, ported from a hosting lexicon's own
429
+ * TMP012/TMP013/TMP014) over every `*.op.ts` file under the lint target and
430
+ * merge them into the same diagnostics/suppressed lists `chant lint` already
431
+ * reports through, the same treatment {@link runComponentCheckDiagnostics}
432
+ * above gives COMP*.
433
+ *
434
+ * Deliberately scoped DOWNWARD from `infraPath` — the same scan
435
+ * `getTypeScriptFiles` already ran to build `files` — rather than
436
+ * `../../op/discover.ts`'s `discoverOps`, which walks UP to the nearest
437
+ * project root (or the git root, absent a config file) precisely because a
438
+ * real project's `ops/` convention sits outside `sourceDir`. That upward
439
+ * walk is right for `chant run`/`chant build`, which always operate on one
440
+ * whole project; it is wrong here, because `chant lint <path>` (and every
441
+ * fixture-scoped test that calls this file's `lintCommand`) may point at a
442
+ * directory with no `chant.config.*` above it short of this repo's own git
443
+ * root — which would make this check import every `*.op.ts` file in the
444
+ * entire monorepo on every such call. Scanning only under `infraPath`, like
445
+ * every other check in this function, keeps this check's cost proportional
446
+ * to the target the caller actually asked to lint.
447
+ *
448
+ * Each `*.op.ts` file's default export is imported directly and used as-is
449
+ * (it is already the `Declarable` `OpResource` instance `Op()` built) — no
450
+ * serializer and no lexicon plugin needed, since OPS012/OPS013/OPS014 only
451
+ * ever read `ctx.entities`, never `ctx.outputs`. That's what lets this fire
452
+ * even on a project with no lexicons configured at all.
453
+ *
454
+ * The project's configured lexicon NAMES are read, though (chant #2101), to
455
+ * resolve the activity contracts each one declares at
456
+ * `@intentius/chant-lexicon-<name>/op/activity-contracts` — one dynamic
457
+ * import per lexicon, no plugin load. Without them a step calling a
458
+ * lexicon's activity is flagged for the absence of a contract that lexicon
459
+ * does declare, which is the whole point of OPS013 firing outside a build.
460
+ *
461
+ * Reported at `1:1` in the file the Op was declared in, the same whole-file
462
+ * convention COMP* diagnostics use — a post-synth finding carries no real
463
+ * line/column (../../lint/post-synth.ts's `PostSynthDiagnostic` doc) and
464
+ * there's no per-file disable-directive suppression for the same reason
465
+ * (that doc again), so this reads only `lint.rules` severity overrides, not
466
+ * `chant-disable` comments.
467
+ */
468
+ async function runOpCheckDiagnostics(
469
+ infraPath: string,
470
+ files: string[],
471
+ ): Promise<{ diagnostics: LintDiagnostic[]; suppressed: Array<LintDiagnostic & { reason?: string }> }> {
472
+ const config = loadConfig(findProjectRoot(infraPath));
473
+ const opFiles = files.filter((f) => f.endsWith(".op.ts"));
474
+ if (opFiles.length === 0) return { diagnostics: [], suppressed: [] };
475
+
476
+ const entities = new Map<string, unknown>();
477
+ const fileByOpName = new Map<string, string>();
478
+ for (const filePath of opFiles) {
479
+ try {
480
+ const mod: unknown = await import(filePath);
481
+ const entity = (mod as { default?: unknown }).default;
482
+ if (!entity || typeof entity !== "object") continue;
483
+ const opConfig = (entity as { props?: unknown }).props as { name?: unknown; phases?: unknown } | undefined;
484
+ if (!opConfig || typeof opConfig.name !== "string" || !Array.isArray(opConfig.phases)) continue;
485
+ entities.set(opConfig.name, entity);
486
+ fileByOpName.set(opConfig.name, filePath);
487
+ } catch {
488
+ // A file that fails to import is somebody else's problem — a syntax
489
+ // error surfaces through the AST rule pass over the same file instead
490
+ // of crashing this one.
491
+ continue;
492
+ }
493
+ }
494
+
495
+ if (entities.size === 0) return { diagnostics: [], suppressed: [] };
496
+
497
+ const lexiconNames = await resolveProjectLexicons(infraPath).catch(() => [] as string[]);
498
+ const activityContracts = await loadActivityContracts(lexiconNames);
499
+
500
+ const raw = runPostSynthChecks(
501
+ coreOpChecks(),
502
+ {
503
+ outputs: new Map(),
504
+ entities: entities as Map<string, never>,
505
+ warnings: [],
506
+ errors: [],
507
+ sourceFileCount: opFiles.length,
508
+ },
509
+ undefined,
510
+ { activityContracts },
511
+ );
512
+
513
+ const diagnostics: LintDiagnostic[] = [];
514
+ const suppressed: Array<LintDiagnostic & { reason?: string }> = [];
515
+
516
+ for (const d of raw) {
517
+ const resolved = resolveConfiguredSeverity(config.rules, d.checkId, d.severity);
518
+ if (resolved.severity === "off") continue;
519
+
520
+ diagnostics.push({
521
+ file: (d.entity && fileByOpName.get(d.entity)) ?? infraPath,
522
+ line: 1,
523
+ column: 1,
524
+ ruleId: d.checkId,
525
+ severity: resolved.severity,
526
+ message: d.message,
527
+ });
528
+ }
529
+
530
+ return { diagnostics, suppressed };
531
+ }
532
+
423
533
  /**
424
534
  * Apply fixes to a file
425
535
  */
@@ -523,6 +633,13 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
523
633
  diagnostics.push(...componentResult.diagnostics);
524
634
  suppressed.push(...componentResult.suppressed);
525
635
 
636
+ // Run the OPS* Op-model post-synth checks (#2122) over every `*.op.ts`
637
+ // file under the lint target — see runOpCheckDiagnostics's doc for why
638
+ // this needs no lexicon or build to fire.
639
+ const opResult = await runOpCheckDiagnostics(infraPath, files);
640
+ diagnostics.push(...opResult.diagnostics);
641
+ suppressed.push(...opResult.suppressed);
642
+
526
643
  // Apply fixes if requested
527
644
  if (options.fix) {
528
645
  // Group fixes by file
@@ -570,6 +687,12 @@ export async function lintCommand(options: LintOptions): Promise<LintResult> {
570
687
  const postComponentResult = await runComponentCheckDiagnostics(infraPath, options.sandbox, options.buildParams);
571
688
  diagnostics.push(...postComponentResult.diagnostics);
572
689
  suppressed.push(...postComponentResult.suppressed);
690
+
691
+ // OPS* checks have no `.fix` either; re-run for the same consistency
692
+ // reason as the COMP* re-run just above.
693
+ const postOpResult = await runOpCheckDiagnostics(infraPath, files);
694
+ diagnostics.push(...postOpResult.diagnostics);
695
+ suppressed.push(...postOpResult.suppressed);
573
696
  }
574
697
 
575
698
  // Count errors and warnings
@@ -72,6 +72,53 @@ jobs:
72
72
  run: npm run --prefix lexicons/k8s prepack
73
73
  `;
74
74
 
75
+ // Mirrors the real chant.yml's check + test jobs: a comment (the cedar note)
76
+ // sitting mid-list splits what would otherwise be one contiguous run of
77
+ // prepack lines into two groups of 2+, so the old grouping wrote the new
78
+ // lexicon's line twice per job (#2098).
79
+ const ciContentWithMidListComment = `name: chant
80
+ on: [push]
81
+ jobs:
82
+ check:
83
+ steps:
84
+ - name: Generate lexicon artifacts
85
+ run: |
86
+ npm run --prefix lexicons/aws prepack
87
+ npm run --prefix lexicons/gitlab prepack
88
+ # cedar generates from the project's own .cedarschema, falling
89
+ # back to the schema bundled at src/spec/default-schema.cedarschema
90
+ # so a clean checkout still produces a surface to gate (#1650).
91
+ npm run --prefix lexicons/cedar prepack
92
+ npm run --prefix lexicons/k8s prepack
93
+ - name: Run tests
94
+ run: npx vitest run
95
+
96
+ test:
97
+ steps:
98
+ - name: Generate lexicon artifacts
99
+ run: |
100
+ npm run --prefix lexicons/aws prepack
101
+ npm run --prefix lexicons/gitlab prepack
102
+ # cedar generates from the project's own .cedarschema, falling
103
+ # back to the schema bundled at src/spec/default-schema.cedarschema
104
+ # so a clean checkout still produces a surface to gate (#1650).
105
+ npm run --prefix lexicons/cedar prepack
106
+ npm run --prefix lexicons/k8s prepack
107
+ - name: Run tests
108
+ run: npx vitest run
109
+
110
+ validate:
111
+ steps:
112
+ - name: Generate and validate AWS lexicon
113
+ run: npm run --prefix lexicons/aws prepack
114
+
115
+ - name: Generate and validate GitLab lexicon
116
+ run: npm run --prefix lexicons/gitlab prepack
117
+
118
+ - name: Generate and validate K8s lexicon
119
+ run: npm run --prefix lexicons/k8s prepack
120
+ `;
121
+
75
122
  const publishContent = `name: publish
76
123
  on:
77
124
  push:
@@ -217,6 +264,34 @@ describe("onboardCommand", () => {
217
264
  const docker = readFileSync(join(root, "test/Dockerfile.smoke"), "utf-8");
218
265
  expect(docker.match(/terraform/g)?.length).toBe(1);
219
266
  });
267
+
268
+ test("a comment mid-list in check/test run blocks does not split the group: one insertion per block (#2098)", () => {
269
+ writeFileSync(join(root, ".github/workflows/chant.yml"), ciContentWithMidListComment);
270
+
271
+ const result = onboardCommand({ name: "terraform", root });
272
+ expect(result.patched).toContain("chant.yml (prepack + validate)");
273
+
274
+ const ci = readFileSync(join(root, ".github/workflows/chant.yml"), "utf-8");
275
+ // check + test + validate: exactly one new line per job, not two per job
276
+ // from the comment splitting the run: | block into two groups.
277
+ expect(ci.match(/lexicons\/terraform prepack/g)?.length).toBe(3);
278
+
279
+ const [checkBlock, rest] = ci.split(" test:");
280
+ const [testBlock, validateBlock] = rest.split(" validate:");
281
+
282
+ expect(checkBlock.match(/lexicons\/terraform prepack/g)?.length).toBe(1);
283
+ expect(testBlock.match(/lexicons\/terraform prepack/g)?.length).toBe(1);
284
+ expect(validateBlock.match(/lexicons\/terraform prepack/g)?.length).toBe(1);
285
+
286
+ // The new line lands after the block's last prepack line (k8s, past the
287
+ // comment), not right after the comment's first half of the group.
288
+ expect(checkBlock).toContain(
289
+ " npm run --prefix lexicons/k8s prepack\n npm run --prefix lexicons/terraform prepack\n",
290
+ );
291
+ expect(testBlock).toContain(
292
+ " npm run --prefix lexicons/k8s prepack\n npm run --prefix lexicons/terraform prepack\n",
293
+ );
294
+ });
220
295
  });
221
296
 
222
297
  describe("root tsconfig.json paths (#1614)", () => {
@@ -5,6 +5,7 @@ import { formatSuccess, formatError, formatWarning } from "../format";
5
5
 
6
6
  export interface OnboardOptions {
7
7
  name: string;
8
+ /** Run `chant dev check-lexicon` and print its full output (see `printOnboardResult`). */
8
9
  verbose?: boolean;
9
10
  /** Monorepo root to patch. Defaults to the root this module lives in. */
10
11
  root?: string;
@@ -14,6 +15,7 @@ export interface OnboardResult {
14
15
  success: boolean;
15
16
  patched: string[];
16
17
  skipped: string[];
18
+ verbose?: boolean;
17
19
  error?: string;
18
20
  }
19
21
 
@@ -41,6 +43,13 @@ function isPrepackLine(line: string): boolean {
41
43
  return PREPACK_LINE.test(line);
42
44
  }
43
45
 
46
+ /** A YAML comment line, e.g. the cedar note sitting mid-list in chant.yml. */
47
+ const COMMENT_LINE = /^\s*#/;
48
+
49
+ function isCommentLine(line: string): boolean {
50
+ return COMMENT_LINE.test(line);
51
+ }
52
+
44
53
  function hasPrepackLine(lines: string[], name: string): boolean {
45
54
  return lines.some((l) => isPrepackLine(l) && l.includes(`lexicons/${name} prepack`));
46
55
  }
@@ -137,27 +146,46 @@ export function patchRootTsconfigPaths(root: string, name: string): PatchResult
137
146
 
138
147
  /**
139
148
  * Insert a new prepack line after the last prepack line in each contiguous group
140
- * of 2+ lines. Single standalone lines (like YAML `run:` values) are ignored.
141
- * Used for multi-line `run: |` blocks in workflows.
149
+ * of 2+ prepack lines. Single standalone lines (like YAML `run:` values) are
150
+ * ignored. Used for multi-line `run: |` blocks in workflows.
151
+ *
152
+ * A comment line between two prepack lines (the cedar note in chant.yml's
153
+ * check and test jobs) does not end the group: it is skipped when scanning,
154
+ * so the block still gets exactly one insertion, anchored after its last
155
+ * real prepack line rather than after the comment (#2098).
142
156
  */
143
157
  function insertPrepackInContiguousGroups(lines: string[], name: string): boolean {
144
158
  if (hasPrepackLine(lines, name)) return false;
145
159
 
146
- // Identify contiguous groups of prepack lines
147
- const groups: { start: number; end: number }[] = [];
160
+ // Identify contiguous groups of prepack lines, treating comment lines
161
+ // inside a group as pass-through rather than a boundary.
162
+ const groups: { lastPrepackIdx: number; count: number }[] = [];
148
163
  let groupStart = -1;
149
- for (let i = 0; i <= lines.length; i++) {
150
- const isPrepack = i < lines.length && isPrepackLine(lines[i]);
151
- if (isPrepack && groupStart === -1) {
152
- groupStart = i;
153
- } else if (!isPrepack && groupStart !== -1) {
154
- groups.push({ start: groupStart, end: i - 1 });
155
- groupStart = -1;
164
+ let lastPrepackIdx = -1;
165
+ let count = 0;
166
+
167
+ const closeGroup = () => {
168
+ if (groupStart !== -1) groups.push({ lastPrepackIdx, count });
169
+ groupStart = -1;
170
+ count = 0;
171
+ };
172
+
173
+ for (let i = 0; i < lines.length; i++) {
174
+ if (isPrepackLine(lines[i])) {
175
+ if (groupStart === -1) groupStart = i;
176
+ lastPrepackIdx = i;
177
+ count++;
178
+ } else if (isCommentLine(lines[i])) {
179
+ // Skip: does not extend a group on its own, and does not close one.
180
+ continue;
181
+ } else {
182
+ closeGroup();
156
183
  }
157
184
  }
185
+ closeGroup();
158
186
 
159
- // Only insert into groups of 2+ lines (multi-line blocks, not standalone steps)
160
- const insertAfter = groups.filter((g) => g.end > g.start).map((g) => g.end);
187
+ // Only insert into groups of 2+ prepack lines (multi-line blocks, not standalone steps)
188
+ const insertAfter = groups.filter((g) => g.count > 1).map((g) => g.lastPrepackIdx);
161
189
 
162
190
  if (insertAfter.length === 0) return false;
163
191
 
@@ -332,7 +360,7 @@ export function onboardCommand(options: OnboardOptions): OnboardResult {
332
360
  patchDockerfile(join(root, "test/Dockerfile.smoke-npm"), options.name),
333
361
  );
334
362
 
335
- return { success: true, patched, skipped };
363
+ return { success: true, patched, skipped, verbose: options.verbose };
336
364
  }
337
365
 
338
366
  /**
@@ -365,20 +393,23 @@ export async function printOnboardResult(result: OnboardResult, name: string): P
365
393
  console.log(` (must depend on @intentius/chant-lexicon-${name} for workspace resolution)`);
366
394
  console.log(` 2. Add smoke tests to test/integration.sh`);
367
395
  console.log(` 3. Run: npm install (to update workspace links)`);
368
- console.log(` 4. First npm publish: tag with v<version> and push`);
396
+ console.log(` 4. First release: just release-lexicon ${name} patch`);
369
397
  console.log(` 5. Run: chant dev check-lexicon lexicons/${name} (to see completeness status)`);
370
398
  console.log(formatWarning({
371
399
  message: "First-time scoped packages may publish as private despite --access public",
372
400
  }));
373
401
  console.log(` Check https://www.npmjs.com/org/intentius and toggle visibility if needed`);
374
402
 
375
- // Run check-lexicon if the lexicon directory exists
376
- const lexiconDir = join(findRepoRoot(), "lexicons", name);
377
- if (existsSync(lexiconDir)) {
378
- console.log("");
379
- console.log("Lexicon completeness:");
380
- const { checkLexicon, printCheckResult } = await import("./check-lexicon");
381
- const checkResult = await checkLexicon(lexiconDir);
382
- printCheckResult(checkResult, false);
403
+ // Under --verbose, run check-lexicon now instead of leaving step 5 to the
404
+ // author, printing the full tier 1/2/3 detail rather than just the summary above.
405
+ if (result.verbose) {
406
+ const lexiconDir = join(findRepoRoot(), "lexicons", name);
407
+ if (existsSync(lexiconDir)) {
408
+ console.log("");
409
+ console.log("Lexicon completeness:");
410
+ const { checkLexicon, printCheckResult } = await import("./check-lexicon");
411
+ const checkResult = await checkLexicon(lexiconDir);
412
+ printCheckResult(checkResult, false);
413
+ }
383
414
  }
384
415
  }