@intentius/chant 0.57.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 (504) 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/init-lexicon/templates/codegen.d.ts +1 -0
  37. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
  38. package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
  39. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
  40. package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
  41. package/dist/cli/commands/init.d.ts.map +1 -1
  42. package/dist/cli/commands/lint.d.ts.map +1 -1
  43. package/dist/cli/commands/onboard.d.ts +2 -0
  44. package/dist/cli/commands/onboard.d.ts.map +1 -1
  45. package/dist/cli/handlers/build.d.ts.map +1 -1
  46. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  47. package/dist/cli/handlers/operator.d.ts +82 -16
  48. package/dist/cli/handlers/operator.d.ts.map +1 -1
  49. package/dist/cli/handlers/run.d.ts +49 -42
  50. package/dist/cli/handlers/run.d.ts.map +1 -1
  51. package/dist/cli/main.d.ts +28 -1
  52. package/dist/cli/main.d.ts.map +1 -1
  53. package/dist/cli/mcp/op-tools.d.ts +16 -1
  54. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  55. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  56. package/dist/cli/mcp/resources/context.d.ts.map +1 -1
  57. package/dist/cli/registry.d.ts +26 -9
  58. package/dist/cli/registry.d.ts.map +1 -1
  59. package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
  60. package/dist/components/auto-release.d.ts +10 -20
  61. package/dist/components/auto-release.d.ts.map +1 -1
  62. package/dist/components/capability.d.ts +4 -4
  63. package/dist/components/cli-support.d.ts +20 -21
  64. package/dist/components/cli-support.d.ts.map +1 -1
  65. package/dist/components/component.d.ts +3 -3
  66. package/dist/components/component.d.ts.map +1 -1
  67. package/dist/components/driver-output.d.ts.map +1 -1
  68. package/dist/components/driver.d.ts +66 -36
  69. package/dist/components/driver.d.ts.map +1 -1
  70. package/dist/components/index.d.ts +1 -2
  71. package/dist/components/index.d.ts.map +1 -1
  72. package/dist/components/manifest-persistence.d.ts +1 -9
  73. package/dist/components/manifest-persistence.d.ts.map +1 -1
  74. package/dist/components/run-progress.d.ts +6 -6
  75. package/dist/components/run-progress.d.ts.map +1 -1
  76. package/dist/components/verbs/run-agent.d.ts +9 -15
  77. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  78. package/dist/components/verbs/verify.d.ts +2 -2
  79. package/dist/deep-observation.d.ts +17 -0
  80. package/dist/deep-observation.d.ts.map +1 -1
  81. package/dist/discovery/files.d.ts +4 -4
  82. package/dist/discovery/fold-import.d.ts.map +1 -1
  83. package/dist/discovery/param-deps.d.ts +33 -0
  84. package/dist/discovery/param-deps.d.ts.map +1 -1
  85. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  86. package/dist/discovery/sandbox/config-wire.d.ts +2 -2
  87. package/dist/fold/foldable-helpers.d.ts +5 -1
  88. package/dist/fold/foldable-helpers.d.ts.map +1 -1
  89. package/dist/fold-provenance.d.ts +236 -0
  90. package/dist/fold-provenance.d.ts.map +1 -0
  91. package/dist/graph-ops.d.ts +1 -1
  92. package/dist/held-elsewhere.d.ts +85 -0
  93. package/dist/held-elsewhere.d.ts.map +1 -0
  94. package/dist/index.d.ts +3 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/kubectl-context.d.ts +3 -3
  97. package/dist/lexicon-config.d.ts +4 -4
  98. package/dist/lexicon-plugin-helpers.d.ts +1 -1
  99. package/dist/lexicon.d.ts +104 -14
  100. package/dist/lexicon.d.ts.map +1 -1
  101. package/dist/lifecycle/change-set.d.ts +13 -0
  102. package/dist/lifecycle/change-set.d.ts.map +1 -1
  103. package/dist/lifecycle/deep-diff.d.ts +133 -6
  104. package/dist/lifecycle/deep-diff.d.ts.map +1 -1
  105. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  106. package/dist/lifecycle/gate-ledger.d.ts +71 -3
  107. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  108. package/dist/lifecycle/index.d.ts +1 -0
  109. package/dist/lifecycle/index.d.ts.map +1 -1
  110. package/dist/lifecycle/release-ledger.d.ts +2 -2
  111. package/dist/lifecycle/run-ledger.d.ts +53 -0
  112. package/dist/lifecycle/run-ledger.d.ts.map +1 -0
  113. package/dist/lifecycle/symptoms.d.ts +3 -3
  114. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  115. package/dist/lint/config.d.ts +81 -2
  116. package/dist/lint/config.d.ts.map +1 -1
  117. package/dist/lint/post-synth.d.ts +55 -2
  118. package/dist/lint/post-synth.d.ts.map +1 -1
  119. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
  120. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
  121. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
  122. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
  123. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
  124. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
  125. package/dist/lint/rules/comp/index.d.ts +1 -1
  126. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  127. package/dist/lint/rules/op/index.d.ts +16 -0
  128. package/dist/lint/rules/op/index.d.ts.map +1 -0
  129. package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
  130. package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
  131. package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
  132. package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
  133. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
  134. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
  135. package/dist/lint/rules/op/support.d.ts +12 -0
  136. package/dist/lint/rules/op/support.d.ts.map +1 -0
  137. package/dist/lint/suppressions.d.ts +108 -0
  138. package/dist/lint/suppressions.d.ts.map +1 -0
  139. package/dist/live-endpoint.d.ts +1 -1
  140. package/dist/op/activities/activity-contracts.d.ts +54 -0
  141. package/dist/op/activities/activity-contracts.d.ts.map +1 -0
  142. package/dist/op/activities/apply.d.ts +262 -0
  143. package/dist/op/activities/apply.d.ts.map +1 -0
  144. package/dist/op/activities/build.d.ts +13 -0
  145. package/dist/op/activities/build.d.ts.map +1 -0
  146. package/dist/op/activities/converge.d.ts +110 -0
  147. package/dist/op/activities/converge.d.ts.map +1 -0
  148. package/dist/op/activities/env-teardown.d.ts +76 -0
  149. package/dist/op/activities/env-teardown.d.ts.map +1 -0
  150. package/dist/op/activities/guard-validate.d.ts +64 -0
  151. package/dist/op/activities/guard-validate.d.ts.map +1 -0
  152. package/dist/op/activities/http-check.d.ts +34 -0
  153. package/dist/op/activities/http-check.d.ts.map +1 -0
  154. package/dist/op/activities/index.d.ts +31 -0
  155. package/dist/op/activities/index.d.ts.map +1 -0
  156. package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
  157. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
  158. package/dist/op/activities/lifecycle.d.ts +42 -0
  159. package/dist/op/activities/lifecycle.d.ts.map +1 -0
  160. package/dist/op/activities/pipeline-audit.d.ts +84 -0
  161. package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
  162. package/dist/op/activities/policy.d.ts +17 -0
  163. package/dist/op/activities/policy.d.ts.map +1 -0
  164. package/dist/op/activities/reconcile.d.ts +89 -0
  165. package/dist/op/activities/reconcile.d.ts.map +1 -0
  166. package/dist/op/activities/shell.d.ts +13 -0
  167. package/dist/op/activities/shell.d.ts.map +1 -0
  168. package/dist/op/activities/teardown.d.ts +10 -0
  169. package/dist/op/activities/teardown.d.ts.map +1 -0
  170. package/dist/op/activities/util.d.ts +7 -0
  171. package/dist/op/activities/util.d.ts.map +1 -0
  172. package/dist/op/activities/wait.d.ts +28 -0
  173. package/dist/op/activities/wait.d.ts.map +1 -0
  174. package/dist/op/activities/workflow-audit.d.ts +92 -0
  175. package/dist/op/activities/workflow-audit.d.ts.map +1 -0
  176. package/dist/op/activity-contract-registry.d.ts +76 -0
  177. package/dist/op/activity-contract-registry.d.ts.map +1 -0
  178. package/dist/op/activity-contract.d.ts +25 -18
  179. package/dist/op/activity-contract.d.ts.map +1 -1
  180. package/dist/op/activity-failure.d.ts +28 -0
  181. package/dist/op/activity-failure.d.ts.map +1 -0
  182. package/dist/op/activity-profiles.d.ts +118 -0
  183. package/dist/op/activity-profiles.d.ts.map +1 -0
  184. package/dist/op/activity-registry.d.ts +22 -38
  185. package/dist/op/activity-registry.d.ts.map +1 -1
  186. package/dist/op/activity-runtime.d.ts +3 -14
  187. package/dist/op/activity-runtime.d.ts.map +1 -1
  188. package/dist/op/builders.d.ts +84 -29
  189. package/dist/op/builders.d.ts.map +1 -1
  190. package/dist/op/composites/apply-op.d.ts +113 -0
  191. package/dist/op/composites/apply-op.d.ts.map +1 -0
  192. package/dist/op/composites/converge-op.d.ts +120 -0
  193. package/dist/op/composites/converge-op.d.ts.map +1 -0
  194. package/dist/op/composites/index.d.ts +26 -0
  195. package/dist/op/composites/index.d.ts.map +1 -0
  196. package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
  197. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
  198. package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
  199. package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
  200. package/dist/op/composites/reconcile-op.d.ts +57 -0
  201. package/dist/op/composites/reconcile-op.d.ts.map +1 -0
  202. package/dist/op/composites/watch-op.d.ts +60 -0
  203. package/dist/op/composites/watch-op.d.ts.map +1 -0
  204. package/dist/op/composites/workflow-audit-op.d.ts +57 -0
  205. package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
  206. package/dist/op/converge-rule.d.ts +12 -10
  207. package/dist/op/converge-rule.d.ts.map +1 -1
  208. package/dist/op/cron.d.ts +51 -0
  209. package/dist/op/cron.d.ts.map +1 -0
  210. package/dist/op/discover.d.ts +9 -0
  211. package/dist/op/discover.d.ts.map +1 -1
  212. package/dist/op/duration.d.ts +11 -0
  213. package/dist/op/duration.d.ts.map +1 -0
  214. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  215. package/dist/op/gate.d.ts +90 -0
  216. package/dist/op/gate.d.ts.map +1 -0
  217. package/dist/op/generate-pipeline.d.ts +9 -0
  218. package/dist/op/generate-pipeline.d.ts.map +1 -1
  219. package/dist/op/index.d.ts +23 -7
  220. package/dist/op/index.d.ts.map +1 -1
  221. package/dist/op/local-executor.d.ts +114 -28
  222. package/dist/op/local-executor.d.ts.map +1 -1
  223. package/dist/op/local-output.d.ts +11 -1
  224. package/dist/op/local-output.d.ts.map +1 -1
  225. package/dist/op/op-ir.d.ts +184 -0
  226. package/dist/op/op-ir.d.ts.map +1 -0
  227. package/dist/op/op-verb-class.d.ts +10 -2
  228. package/dist/op/op-verb-class.d.ts.map +1 -1
  229. package/dist/op/operator.d.ts +30 -5
  230. package/dist/op/operator.d.ts.map +1 -1
  231. package/dist/op/receipt-store.d.ts +1 -1
  232. package/dist/op/receipt-store.d.ts.map +1 -1
  233. package/dist/op/resource.d.ts +15 -1
  234. package/dist/op/resource.d.ts.map +1 -1
  235. package/dist/op/runtime.d.ts +200 -0
  236. package/dist/op/runtime.d.ts.map +1 -0
  237. package/dist/op/runtimes/local.d.ts +29 -0
  238. package/dist/op/runtimes/local.d.ts.map +1 -0
  239. package/dist/op/step-output-ref.d.ts +15 -13
  240. package/dist/op/step-output-ref.d.ts.map +1 -1
  241. package/dist/op/types.d.ts +79 -27
  242. package/dist/op/types.d.ts.map +1 -1
  243. package/dist/ownership.d.ts +1 -1
  244. package/dist/provenance.d.ts +21 -0
  245. package/dist/provenance.d.ts.map +1 -1
  246. package/dist/serializer-walker.d.ts.map +1 -1
  247. package/package.json +6 -1
  248. package/src/audit/catalog.test.ts +79 -3
  249. package/src/audit/catalog.ts +111 -13
  250. package/src/audit/core.test.ts +26 -0
  251. package/src/audit/core.ts +61 -17
  252. package/src/audit/discover.test.ts +39 -0
  253. package/src/audit/discover.ts +91 -15
  254. package/src/audit/lineage.ts +100 -0
  255. package/src/audit/prior-art.ts +153 -0
  256. package/src/audit/proof.test.ts +67 -0
  257. package/src/audit/proof.ts +70 -0
  258. package/src/audit/report-html.ts +9 -4
  259. package/src/audit/report-model.ts +16 -2
  260. package/src/audit/report.test.ts +33 -0
  261. package/src/audit/report.ts +5 -3
  262. package/src/audit/rules-doc.test.ts +34 -2
  263. package/src/audit/rules-doc.ts +82 -9
  264. package/src/audit/secrets.ts +15 -3
  265. package/src/audit/terraform-state.test.ts +144 -0
  266. package/src/audit/terraform-state.ts +131 -0
  267. package/src/build.ts +31 -1
  268. package/src/claimed-fields.test.ts +145 -0
  269. package/src/claimed-fields.ts +208 -0
  270. package/src/cli/build-params-cli.ts +2 -2
  271. package/src/cli/command-group.ts +14 -0
  272. package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
  273. package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
  274. package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
  275. package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
  276. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
  277. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
  278. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
  279. package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
  280. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
  281. package/src/cli/commands/audit.test.ts +189 -11
  282. package/src/cli/commands/audit.ts +73 -27
  283. package/src/cli/commands/build.test.ts +292 -9
  284. package/src/cli/commands/build.ts +156 -24
  285. package/src/cli/commands/check-lexicon-docs.ts +1 -1
  286. package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
  287. package/src/cli/commands/check-lexicon-examples.ts +42 -10
  288. package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
  289. package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
  290. package/src/cli/commands/init-lexicon.test.ts +97 -2
  291. package/src/cli/commands/init-lexicon.ts +4 -2
  292. package/src/cli/commands/init.test.ts +35 -1
  293. package/src/cli/commands/init.ts +14 -3
  294. package/src/cli/commands/lint.test.ts +48 -0
  295. package/src/cli/commands/lint.ts +123 -0
  296. package/src/cli/commands/onboard.test.ts +75 -0
  297. package/src/cli/commands/onboard.ts +54 -23
  298. package/src/cli/handlers/build.test.ts +81 -1
  299. package/src/cli/handlers/build.ts +15 -1
  300. package/src/cli/handlers/graph.test.ts +3 -3
  301. package/src/cli/handlers/lifecycle.test.ts +195 -12
  302. package/src/cli/handlers/lifecycle.ts +123 -6
  303. package/src/cli/handlers/misc.ts +1 -1
  304. package/src/cli/handlers/operator.test.ts +183 -11
  305. package/src/cli/handlers/operator.ts +260 -55
  306. package/src/cli/handlers/run.test.ts +431 -1287
  307. package/src/cli/handlers/run.ts +365 -915
  308. package/src/cli/main.test.ts +23 -15
  309. package/src/cli/main.ts +88 -33
  310. package/src/cli/mcp/op-tools.ts +147 -88
  311. package/src/cli/mcp/resource-handlers.ts +10 -37
  312. package/src/cli/mcp/resources/context.ts +11 -12
  313. package/src/cli/mcp/server.test.ts +25 -27
  314. package/src/cli/mcp/server.ts +2 -2
  315. package/src/cli/registry.ts +26 -9
  316. package/src/codegen/docs.ts +1 -1
  317. package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
  318. package/src/codegen/generate-post-synth-barrel.ts +1 -1
  319. package/src/components/README.md +3 -2
  320. package/src/components/auto-release.test.ts +4 -20
  321. package/src/components/auto-release.ts +17 -42
  322. package/src/components/capability.ts +4 -4
  323. package/src/components/cli-support.test.ts +10 -5
  324. package/src/components/cli-support.ts +52 -44
  325. package/src/components/component.schema.json +2 -2
  326. package/src/components/component.ts +3 -3
  327. package/src/components/driver-output.ts +14 -2
  328. package/src/components/driver.test.ts +92 -22
  329. package/src/components/driver.ts +193 -83
  330. package/src/components/index.ts +1 -6
  331. package/src/components/manifest-persistence.test.ts +2 -20
  332. package/src/components/manifest-persistence.ts +4 -24
  333. package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
  334. package/src/components/run-progress.ts +6 -6
  335. package/src/components/verbs/run-agent.ts +11 -17
  336. package/src/components/verbs/verify.ts +2 -2
  337. package/src/deep-observation.test.ts +75 -0
  338. package/src/deep-observation.ts +48 -0
  339. package/src/discovery/collect.test.ts +3 -3
  340. package/src/discovery/files.ts +4 -4
  341. package/src/discovery/fold-import.ts +105 -2
  342. package/src/discovery/param-deps.test.ts +112 -1
  343. package/src/discovery/param-deps.ts +193 -0
  344. package/src/discovery/sandbox/bundle.ts +15 -1
  345. package/src/discovery/sandbox/config-wire.test.ts +2 -2
  346. package/src/discovery/sandbox/config-wire.ts +2 -2
  347. package/src/fold/fold.test.ts +56 -0
  348. package/src/fold/foldable-helpers.ts +81 -1
  349. package/src/fold-provenance-exclusion.test.ts +186 -0
  350. package/src/fold-provenance.test.ts +495 -0
  351. package/src/fold-provenance.ts +441 -0
  352. package/src/graph-ops.test.ts +2 -2
  353. package/src/graph-ops.ts +1 -1
  354. package/src/held-elsewhere.test.ts +102 -0
  355. package/src/held-elsewhere.ts +114 -0
  356. package/src/index.ts +3 -0
  357. package/src/kubectl-context.ts +3 -3
  358. package/src/lexicon-config.test.ts +5 -5
  359. package/src/lexicon-config.ts +4 -4
  360. package/src/lexicon-plugin-helpers.ts +1 -1
  361. package/src/lexicon.ts +120 -14
  362. package/src/lifecycle/change-set.test.ts +49 -0
  363. package/src/lifecycle/change-set.ts +67 -0
  364. package/src/lifecycle/converge-ledger.ts +1 -1
  365. package/src/lifecycle/deep-diff.test.ts +267 -14
  366. package/src/lifecycle/deep-diff.ts +217 -14
  367. package/src/lifecycle/deep-observe.test.ts +3 -1
  368. package/src/lifecycle/deep-observe.ts +16 -6
  369. package/src/lifecycle/gate-ledger.test.ts +74 -2
  370. package/src/lifecycle/gate-ledger.ts +143 -36
  371. package/src/lifecycle/index.ts +1 -0
  372. package/src/lifecycle/release-ledger.ts +2 -2
  373. package/src/lifecycle/run-ledger.test.ts +268 -0
  374. package/src/lifecycle/run-ledger.ts +201 -0
  375. package/src/lifecycle/symptoms.ts +3 -3
  376. package/src/lint/config.test.ts +82 -1
  377. package/src/lint/config.ts +112 -3
  378. package/src/lint/policy.test.ts +1 -1
  379. package/src/lint/post-synth.test.ts +31 -0
  380. package/src/lint/post-synth.ts +54 -1
  381. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
  382. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
  383. package/src/lint/rules/comp/comp.test.ts +1 -1
  384. package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
  385. package/src/lint/rules/comp/index.ts +3 -3
  386. package/src/lint/rules/op/index.ts +23 -0
  387. package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
  388. package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
  389. package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
  390. package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
  391. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
  392. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
  393. package/src/lint/rules/op/support.ts +11 -0
  394. package/src/lint/suppressions.test.ts +163 -0
  395. package/src/lint/suppressions.ts +204 -0
  396. package/src/live-endpoint.ts +1 -1
  397. package/src/op/activities/activity-contracts.ts +66 -0
  398. package/src/op/activities/apply.test.ts +567 -0
  399. package/src/op/activities/apply.ts +662 -0
  400. package/src/op/activities/build.ts +26 -0
  401. package/src/op/activities/converge.test.ts +330 -0
  402. package/src/op/activities/converge.ts +449 -0
  403. package/src/op/activities/env-teardown.test.ts +187 -0
  404. package/src/op/activities/env-teardown.ts +171 -0
  405. package/src/op/activities/guard-validate.test.ts +139 -0
  406. package/src/op/activities/guard-validate.ts +223 -0
  407. package/src/op/activities/http-check.test.ts +48 -0
  408. package/src/op/activities/http-check.ts +55 -0
  409. package/src/op/activities/index.ts +119 -0
  410. package/src/op/activities/lexicon-upgrade.test.ts +492 -0
  411. package/src/op/activities/lexicon-upgrade.ts +673 -0
  412. package/src/op/activities/lifecycle.ts +85 -0
  413. package/src/op/activities/pipeline-audit.test.ts +67 -0
  414. package/src/op/activities/pipeline-audit.ts +201 -0
  415. package/src/op/activities/policy.test.ts +19 -0
  416. package/src/op/activities/policy.ts +37 -0
  417. package/src/op/activities/reconcile.test.ts +81 -0
  418. package/src/op/activities/reconcile.ts +187 -0
  419. package/src/op/activities/shell.ts +26 -0
  420. package/src/op/activities/teardown.ts +22 -0
  421. package/src/op/activities/util.ts +6 -0
  422. package/src/op/activities/wait.ts +69 -0
  423. package/src/op/activities/workflow-audit.test.ts +90 -0
  424. package/src/op/activities/workflow-audit.ts +203 -0
  425. package/src/op/activity-contract-registry.test.ts +98 -0
  426. package/src/op/activity-contract-registry.ts +114 -0
  427. package/src/op/activity-contract.test.ts +1 -1
  428. package/src/op/activity-contract.ts +37 -33
  429. package/src/op/activity-failure.ts +34 -0
  430. package/src/op/activity-profiles.test.ts +56 -0
  431. package/src/op/activity-profiles.ts +116 -0
  432. package/src/op/activity-registry.test.ts +37 -28
  433. package/src/op/activity-registry.ts +27 -56
  434. package/src/op/activity-runtime.ts +3 -47
  435. package/src/op/builders-exports.test.ts +0 -49
  436. package/src/op/builders-typed.test.ts +164 -0
  437. package/src/op/builders.ts +123 -39
  438. package/src/op/composites/apply-op.ts +208 -0
  439. package/src/op/composites/composites.test.ts +366 -0
  440. package/src/op/composites/converge-op.test.ts +168 -0
  441. package/src/op/composites/converge-op.ts +214 -0
  442. package/src/op/composites/index.ts +26 -0
  443. package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
  444. package/src/op/composites/lexicon-upgrade-op.ts +134 -0
  445. package/src/op/composites/pipeline-audit-op.test.ts +25 -0
  446. package/src/op/composites/pipeline-audit-op.ts +78 -0
  447. package/src/op/composites/reconcile-op.test.ts +51 -0
  448. package/src/op/composites/reconcile-op.ts +107 -0
  449. package/src/op/composites/watch-op.ts +108 -0
  450. package/src/op/composites/workflow-audit-op.test.ts +25 -0
  451. package/src/op/composites/workflow-audit-op.ts +88 -0
  452. package/src/op/converge-rule.ts +12 -10
  453. package/src/op/cron.test.ts +128 -0
  454. package/src/op/cron.ts +149 -0
  455. package/src/op/discover-root.test.ts +105 -1
  456. package/src/op/discover.test.ts +6 -2
  457. package/src/op/discover.ts +84 -16
  458. package/src/op/duration.ts +21 -0
  459. package/src/op/effect-step.test.ts +26 -11
  460. package/src/op/emulator-lifecycle.ts +1 -2
  461. package/src/op/gate.ts +155 -0
  462. package/src/op/generate-pipeline.test.ts +65 -3
  463. package/src/op/generate-pipeline.ts +19 -2
  464. package/src/op/index.ts +39 -6
  465. package/src/op/local-executor.test.ts +163 -34
  466. package/src/op/local-executor.ts +370 -102
  467. package/src/op/local-output.test.ts +95 -11
  468. package/src/op/local-output.ts +33 -4
  469. package/src/op/op-ir.test.ts +281 -0
  470. package/src/op/op-ir.ts +417 -0
  471. package/src/op/op-verb-class.ts +19 -5
  472. package/src/op/op.test.ts +26 -5
  473. package/src/op/operator.test.ts +175 -6
  474. package/src/op/operator.ts +63 -16
  475. package/src/op/receipt-store.ts +1 -1
  476. package/src/op/resource.ts +20 -2
  477. package/src/op/runtime.ts +203 -0
  478. package/src/op/runtimes/local.test.ts +181 -0
  479. package/src/op/runtimes/local.ts +212 -0
  480. package/src/op/step-output-ref.ts +15 -13
  481. package/src/op/types.ts +84 -24
  482. package/src/ownership.ts +1 -1
  483. package/src/provenance.test.ts +6 -0
  484. package/src/provenance.ts +21 -1
  485. package/src/serializer-walker.test.ts +42 -0
  486. package/src/serializer-walker.ts +21 -2
  487. package/dist/cli/handlers/op-progress.d.ts +0 -90
  488. package/dist/cli/handlers/op-progress.d.ts.map +0 -1
  489. package/dist/cli/handlers/run-client.d.ts +0 -127
  490. package/dist/cli/handlers/run-client.d.ts.map +0 -1
  491. package/dist/cli/handlers/run-report.d.ts +0 -5
  492. package/dist/cli/handlers/run-report.d.ts.map +0 -1
  493. package/dist/components/temporal-codegen-loader.d.ts +0 -27
  494. package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
  495. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
  496. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
  497. package/src/cli/handlers/op-progress.test.ts +0 -268
  498. package/src/cli/handlers/op-progress.ts +0 -248
  499. package/src/cli/handlers/run-client.test.ts +0 -82
  500. package/src/cli/handlers/run-client.ts +0 -219
  501. package/src/cli/handlers/run-report.test.ts +0 -62
  502. package/src/cli/handlers/run-report.ts +0 -122
  503. package/src/components/temporal-codegen-loader.ts +0 -41
  504. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
@@ -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
  }
@@ -6,7 +6,7 @@
6
6
  * `buildParams`, so a `*.component.ts` file reading `params.<name>` always
7
7
  * saw `{}` under `chant build --components --generate`, exactly like `chant
8
8
  * run --components` (see ../handlers/run.test.ts's "build-time parameters"
9
- * describe block for the equivalent local/`--temporal` coverage).
9
+ * describe block for the equivalent local-run coverage).
10
10
  *
11
11
  * Mocks `generateComponentsPipeline` and `loadChantConfigUpward` (chant
12
12
  * #1117 — `runGenerateComponents` walks up to the project root now, same as
@@ -149,3 +149,83 @@ describe("runBuild --components --generate (chant #1108 build-time parameters)",
149
149
  expect(generateComponentsPipelineMock).not.toHaveBeenCalled();
150
150
  });
151
151
  });
152
+
153
+ /**
154
+ * chant #2060. `chant build --components --generate --format json` forwarded
155
+ * only `{ stages, jobs, yaml }`, dropping `result.env` even though the
156
+ * generator (#2046, PR #2050) resolves and returns it. A consumer reading the
157
+ * structured output (behold does) had no environment identity except by
158
+ * parsing the YAML back, which #2046 was meant to retire.
159
+ */
160
+ describe("runBuild --components --generate --format json (chant #2060 env passthrough)", () => {
161
+ beforeEach(() => {
162
+ generateComponentsPipelineMock.mockReset();
163
+ loadChantConfigUpwardMock.mockReset().mockResolvedValue({ config: {} });
164
+ });
165
+
166
+ test("--format json includes result.env alongside stages, jobs and yaml", async () => {
167
+ generateComponentsPipelineMock.mockResolvedValue({
168
+ success: true,
169
+ yaml: "name: chant-components-prod\nenv:\n CHANT_ENV: prod\n",
170
+ stages: ["deploy"],
171
+ jobs: [{ jobName: "deploy-web", component: "web", stage: "deploy", needs: [] }],
172
+ env: "prod",
173
+ });
174
+ const stdout: string[] = [];
175
+ vi.spyOn(console, "log").mockImplementation((s: string) => { stdout.push(s); });
176
+
177
+ const exit = await runBuild({
178
+ args: makeArgs({ format: "json", env: "prod" }),
179
+ plugins: [],
180
+ serializers: [],
181
+ });
182
+
183
+ expect(exit).toBe(0);
184
+ expect(stdout).toHaveLength(1);
185
+ const printed = JSON.parse(stdout[0]);
186
+ expect(printed).toEqual({
187
+ stages: ["deploy"],
188
+ jobs: [{ jobName: "deploy-web", component: "web", stage: "deploy", needs: [] }],
189
+ yaml: "name: chant-components-prod\nenv:\n CHANT_ENV: prod\n",
190
+ env: "prod",
191
+ });
192
+ vi.restoreAllMocks();
193
+ });
194
+
195
+ test("--format json omits env when the generator's result carries none", async () => {
196
+ generateComponentsPipelineMock.mockResolvedValue({
197
+ success: true,
198
+ yaml: "stages: []",
199
+ stages: [],
200
+ jobs: [],
201
+ });
202
+ const stdout: string[] = [];
203
+ vi.spyOn(console, "log").mockImplementation((s: string) => { stdout.push(s); });
204
+
205
+ const exit = await runBuild({ args: makeArgs({ format: "json" }), plugins: [], serializers: [] });
206
+
207
+ expect(exit).toBe(0);
208
+ const printed = JSON.parse(stdout[0]);
209
+ expect(printed).toEqual({ stages: [], jobs: [], yaml: "stages: []" });
210
+ expect(printed).not.toHaveProperty("env");
211
+ vi.restoreAllMocks();
212
+ });
213
+
214
+ test("the default text format is unchanged: env is not forwarded and only the raw yaml is printed", async () => {
215
+ generateComponentsPipelineMock.mockResolvedValue({
216
+ success: true,
217
+ yaml: "name: chant-components-prod\nenv:\n CHANT_ENV: prod\n",
218
+ stages: ["deploy"],
219
+ jobs: [{ jobName: "deploy-web", component: "web", stage: "deploy", needs: [] }],
220
+ env: "prod",
221
+ });
222
+ const stdout: string[] = [];
223
+ vi.spyOn(console, "log").mockImplementation((s: string) => { stdout.push(s); });
224
+
225
+ const exit = await runBuild({ args: makeArgs({ env: "prod" }), plugins: [], serializers: [] });
226
+
227
+ expect(exit).toBe(0);
228
+ expect(stdout).toEqual(["name: chant-components-prod\nenv:\n CHANT_ENV: prod\n"]);
229
+ vi.restoreAllMocks();
230
+ });
231
+ });
@@ -63,7 +63,21 @@ async function runGenerateComponents(ctx: CommandContext): Promise<number> {
63
63
 
64
64
  const yaml = result.yaml ?? "";
65
65
  if (args.format === "json") {
66
- console.log(JSON.stringify({ stages: result.stages, jobs: result.jobs, yaml }, null, 2));
66
+ console.log(
67
+ JSON.stringify(
68
+ {
69
+ stages: result.stages,
70
+ jobs: result.jobs,
71
+ yaml,
72
+ // The environment the generated pipeline deploys (#2046), the
73
+ // generator's own resolution, forwarded rather than left for a
74
+ // consumer to re-derive by parsing the YAML back (#2060).
75
+ ...(result.env ? { env: result.env } : {}),
76
+ },
77
+ null,
78
+ 2,
79
+ ),
80
+ );
67
81
  } else if (args.output) {
68
82
  const outputPath = resolve(args.output);
69
83
  mkdirSync(dirname(outputPath), { recursive: true });