@intentius/chant 0.57.0 → 0.59.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 (558) 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 +36 -1
  4. package/dist/audit/core.d.ts.map +1 -1
  5. package/dist/audit/discover.d.ts +26 -9
  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/carve-bridge.d.ts.map +1 -1
  34. package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
  35. package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
  36. package/dist/cli/commands/check-lexicon-examples.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 +13 -0
  44. package/dist/cli/commands/lint.d.ts.map +1 -1
  45. package/dist/cli/commands/onboard.d.ts +2 -0
  46. package/dist/cli/commands/onboard.d.ts.map +1 -1
  47. package/dist/cli/handlers/build.d.ts.map +1 -1
  48. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  49. package/dist/cli/handlers/operator.d.ts +82 -16
  50. package/dist/cli/handlers/operator.d.ts.map +1 -1
  51. package/dist/cli/handlers/run.d.ts +49 -42
  52. package/dist/cli/handlers/run.d.ts.map +1 -1
  53. package/dist/cli/main.d.ts +12 -1
  54. package/dist/cli/main.d.ts.map +1 -1
  55. package/dist/cli/mcp/op-tools.d.ts +16 -1
  56. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  57. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
  58. package/dist/cli/mcp/resources/context.d.ts.map +1 -1
  59. package/dist/cli/plugins.d.ts +22 -0
  60. package/dist/cli/plugins.d.ts.map +1 -1
  61. package/dist/cli/registry.d.ts +40 -9
  62. package/dist/cli/registry.d.ts.map +1 -1
  63. package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
  64. package/dist/components/auto-release.d.ts +10 -20
  65. package/dist/components/auto-release.d.ts.map +1 -1
  66. package/dist/components/capability.d.ts +4 -4
  67. package/dist/components/cli-support.d.ts +24 -22
  68. package/dist/components/cli-support.d.ts.map +1 -1
  69. package/dist/components/component.d.ts +21 -6
  70. package/dist/components/component.d.ts.map +1 -1
  71. package/dist/components/driver-output.d.ts.map +1 -1
  72. package/dist/components/driver.d.ts +73 -37
  73. package/dist/components/driver.d.ts.map +1 -1
  74. package/dist/components/index.d.ts +1 -2
  75. package/dist/components/index.d.ts.map +1 -1
  76. package/dist/components/manifest-persistence.d.ts +1 -9
  77. package/dist/components/manifest-persistence.d.ts.map +1 -1
  78. package/dist/components/run-progress.d.ts +6 -6
  79. package/dist/components/run-progress.d.ts.map +1 -1
  80. package/dist/components/verbs/run-agent.d.ts +10 -22
  81. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  82. package/dist/components/verbs/verify.d.ts +2 -2
  83. package/dist/deep-observation.d.ts +17 -0
  84. package/dist/deep-observation.d.ts.map +1 -1
  85. package/dist/detectLexicon.d.ts +13 -0
  86. package/dist/detectLexicon.d.ts.map +1 -1
  87. package/dist/discovery/files.d.ts +4 -4
  88. package/dist/discovery/fold-import.d.ts.map +1 -1
  89. package/dist/discovery/param-deps.d.ts +33 -0
  90. package/dist/discovery/param-deps.d.ts.map +1 -1
  91. package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
  92. package/dist/discovery/sandbox/config-wire.d.ts +2 -2
  93. package/dist/fold/foldable-helpers.d.ts +5 -1
  94. package/dist/fold/foldable-helpers.d.ts.map +1 -1
  95. package/dist/fold-provenance.d.ts +236 -0
  96. package/dist/fold-provenance.d.ts.map +1 -0
  97. package/dist/graph-ops.d.ts +1 -1
  98. package/dist/held-elsewhere.d.ts +85 -0
  99. package/dist/held-elsewhere.d.ts.map +1 -0
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/kubectl-context.d.ts +3 -3
  103. package/dist/lexicon-config.d.ts +4 -4
  104. package/dist/lexicon-plugin-helpers.d.ts +1 -1
  105. package/dist/lexicon.d.ts +273 -16
  106. package/dist/lexicon.d.ts.map +1 -1
  107. package/dist/lifecycle/change-set.d.ts +13 -0
  108. package/dist/lifecycle/change-set.d.ts.map +1 -1
  109. package/dist/lifecycle/deep-diff.d.ts +133 -6
  110. package/dist/lifecycle/deep-diff.d.ts.map +1 -1
  111. package/dist/lifecycle/deep-observe.d.ts.map +1 -1
  112. package/dist/lifecycle/gate-ledger.d.ts +79 -3
  113. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  114. package/dist/lifecycle/index.d.ts +1 -0
  115. package/dist/lifecycle/index.d.ts.map +1 -1
  116. package/dist/lifecycle/release-ledger.d.ts +2 -2
  117. package/dist/lifecycle/run-ledger.d.ts +53 -0
  118. package/dist/lifecycle/run-ledger.d.ts.map +1 -0
  119. package/dist/lifecycle/symptoms.d.ts +3 -3
  120. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  121. package/dist/lint/config.d.ts +81 -2
  122. package/dist/lint/config.d.ts.map +1 -1
  123. package/dist/lint/post-synth.d.ts +55 -2
  124. package/dist/lint/post-synth.d.ts.map +1 -1
  125. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
  126. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
  127. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
  128. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
  129. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
  130. package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
  131. package/dist/lint/rules/comp/index.d.ts +1 -1
  132. package/dist/lint/rules/comp/index.d.ts.map +1 -1
  133. package/dist/lint/rules/op/index.d.ts +16 -0
  134. package/dist/lint/rules/op/index.d.ts.map +1 -0
  135. package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
  136. package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
  137. package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
  138. package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
  139. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
  140. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
  141. package/dist/lint/rules/op/support.d.ts +12 -0
  142. package/dist/lint/rules/op/support.d.ts.map +1 -0
  143. package/dist/lint/suppressions.d.ts +108 -0
  144. package/dist/lint/suppressions.d.ts.map +1 -0
  145. package/dist/live-endpoint.d.ts +1 -1
  146. package/dist/op/activities/activity-contracts.d.ts +54 -0
  147. package/dist/op/activities/activity-contracts.d.ts.map +1 -0
  148. package/dist/op/activities/apply.d.ts +262 -0
  149. package/dist/op/activities/apply.d.ts.map +1 -0
  150. package/dist/op/activities/build.d.ts +13 -0
  151. package/dist/op/activities/build.d.ts.map +1 -0
  152. package/dist/op/activities/converge.d.ts +110 -0
  153. package/dist/op/activities/converge.d.ts.map +1 -0
  154. package/dist/op/activities/env-teardown.d.ts +76 -0
  155. package/dist/op/activities/env-teardown.d.ts.map +1 -0
  156. package/dist/op/activities/guard-validate.d.ts +64 -0
  157. package/dist/op/activities/guard-validate.d.ts.map +1 -0
  158. package/dist/op/activities/http-check.d.ts +34 -0
  159. package/dist/op/activities/http-check.d.ts.map +1 -0
  160. package/dist/op/activities/index.d.ts +31 -0
  161. package/dist/op/activities/index.d.ts.map +1 -0
  162. package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
  163. package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
  164. package/dist/op/activities/lifecycle.d.ts +42 -0
  165. package/dist/op/activities/lifecycle.d.ts.map +1 -0
  166. package/dist/op/activities/pipeline-audit.d.ts +84 -0
  167. package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
  168. package/dist/op/activities/policy.d.ts +17 -0
  169. package/dist/op/activities/policy.d.ts.map +1 -0
  170. package/dist/op/activities/reconcile.d.ts +149 -0
  171. package/dist/op/activities/reconcile.d.ts.map +1 -0
  172. package/dist/op/activities/shell.d.ts +13 -0
  173. package/dist/op/activities/shell.d.ts.map +1 -0
  174. package/dist/op/activities/teardown.d.ts +10 -0
  175. package/dist/op/activities/teardown.d.ts.map +1 -0
  176. package/dist/op/activities/util.d.ts +7 -0
  177. package/dist/op/activities/util.d.ts.map +1 -0
  178. package/dist/op/activities/wait.d.ts +28 -0
  179. package/dist/op/activities/wait.d.ts.map +1 -0
  180. package/dist/op/activities/workflow-audit.d.ts +92 -0
  181. package/dist/op/activities/workflow-audit.d.ts.map +1 -0
  182. package/dist/op/activity-contract-registry.d.ts +76 -0
  183. package/dist/op/activity-contract-registry.d.ts.map +1 -0
  184. package/dist/op/activity-contract.d.ts +25 -18
  185. package/dist/op/activity-contract.d.ts.map +1 -1
  186. package/dist/op/activity-failure.d.ts +28 -0
  187. package/dist/op/activity-failure.d.ts.map +1 -0
  188. package/dist/op/activity-profiles.d.ts +118 -0
  189. package/dist/op/activity-profiles.d.ts.map +1 -0
  190. package/dist/op/activity-registry.d.ts +22 -38
  191. package/dist/op/activity-registry.d.ts.map +1 -1
  192. package/dist/op/activity-runtime.d.ts +3 -14
  193. package/dist/op/activity-runtime.d.ts.map +1 -1
  194. package/dist/op/builders.d.ts +85 -30
  195. package/dist/op/builders.d.ts.map +1 -1
  196. package/dist/op/change-signal.d.ts +91 -0
  197. package/dist/op/change-signal.d.ts.map +1 -0
  198. package/dist/op/composites/apply-op.d.ts +118 -0
  199. package/dist/op/composites/apply-op.d.ts.map +1 -0
  200. package/dist/op/composites/converge-op.d.ts +120 -0
  201. package/dist/op/composites/converge-op.d.ts.map +1 -0
  202. package/dist/op/composites/index.d.ts +26 -0
  203. package/dist/op/composites/index.d.ts.map +1 -0
  204. package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
  205. package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
  206. package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
  207. package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
  208. package/dist/op/composites/reconcile-op.d.ts +57 -0
  209. package/dist/op/composites/reconcile-op.d.ts.map +1 -0
  210. package/dist/op/composites/watch-op.d.ts +60 -0
  211. package/dist/op/composites/watch-op.d.ts.map +1 -0
  212. package/dist/op/composites/workflow-audit-op.d.ts +57 -0
  213. package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
  214. package/dist/op/converge-rule.d.ts +12 -10
  215. package/dist/op/converge-rule.d.ts.map +1 -1
  216. package/dist/op/cron.d.ts +51 -0
  217. package/dist/op/cron.d.ts.map +1 -0
  218. package/dist/op/discover.d.ts +9 -0
  219. package/dist/op/discover.d.ts.map +1 -1
  220. package/dist/op/duration.d.ts +11 -0
  221. package/dist/op/duration.d.ts.map +1 -0
  222. package/dist/op/emulator-lifecycle.d.ts.map +1 -1
  223. package/dist/op/gate-name.d.ts +40 -0
  224. package/dist/op/gate-name.d.ts.map +1 -0
  225. package/dist/op/gate-summary.d.ts +43 -0
  226. package/dist/op/gate-summary.d.ts.map +1 -0
  227. package/dist/op/gate.d.ts +90 -0
  228. package/dist/op/gate.d.ts.map +1 -0
  229. package/dist/op/generate-pipeline.d.ts +9 -0
  230. package/dist/op/generate-pipeline.d.ts.map +1 -1
  231. package/dist/op/index.d.ts +29 -9
  232. package/dist/op/index.d.ts.map +1 -1
  233. package/dist/op/local-executor.d.ts +114 -28
  234. package/dist/op/local-executor.d.ts.map +1 -1
  235. package/dist/op/local-output.d.ts +11 -1
  236. package/dist/op/local-output.d.ts.map +1 -1
  237. package/dist/op/op-ir.d.ts +185 -0
  238. package/dist/op/op-ir.d.ts.map +1 -0
  239. package/dist/op/op-verb-class.d.ts +10 -2
  240. package/dist/op/op-verb-class.d.ts.map +1 -1
  241. package/dist/op/operator.d.ts +93 -5
  242. package/dist/op/operator.d.ts.map +1 -1
  243. package/dist/op/receipt-store.d.ts +1 -1
  244. package/dist/op/receipt-store.d.ts.map +1 -1
  245. package/dist/op/resource.d.ts +15 -1
  246. package/dist/op/resource.d.ts.map +1 -1
  247. package/dist/op/runtime.d.ts +200 -0
  248. package/dist/op/runtime.d.ts.map +1 -0
  249. package/dist/op/runtimes/local.d.ts +29 -0
  250. package/dist/op/runtimes/local.d.ts.map +1 -0
  251. package/dist/op/step-output-ref.d.ts +15 -13
  252. package/dist/op/step-output-ref.d.ts.map +1 -1
  253. package/dist/op/types.d.ts +96 -29
  254. package/dist/op/types.d.ts.map +1 -1
  255. package/dist/ownership.d.ts +1 -1
  256. package/dist/provenance.d.ts +21 -0
  257. package/dist/provenance.d.ts.map +1 -1
  258. package/dist/serializer-walker.d.ts.map +1 -1
  259. package/dist/terraform/bridge.d.ts +26 -7
  260. package/dist/terraform/bridge.d.ts.map +1 -1
  261. package/dist/terraform/carve-provider.d.ts +28 -2
  262. package/dist/terraform/carve-provider.d.ts.map +1 -1
  263. package/dist/terraform/data-source-shape.d.ts +77 -0
  264. package/dist/terraform/data-source-shape.d.ts.map +1 -0
  265. package/dist/terraform/graph.d.ts.map +1 -1
  266. package/dist/terraform/providers/kubernetes.d.ts +5 -0
  267. package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
  268. package/dist/terraform/tier-map.d.ts +16 -4
  269. package/dist/terraform/tier-map.d.ts.map +1 -1
  270. package/dist/terraform/types.d.ts +8 -0
  271. package/dist/terraform/types.d.ts.map +1 -1
  272. package/package.json +6 -1
  273. package/src/audit/catalog.test.ts +79 -3
  274. package/src/audit/catalog.ts +111 -13
  275. package/src/audit/core.test.ts +26 -0
  276. package/src/audit/core.ts +84 -18
  277. package/src/audit/discover.test.ts +39 -0
  278. package/src/audit/discover.ts +202 -18
  279. package/src/audit/lineage.ts +100 -0
  280. package/src/audit/prior-art.ts +153 -0
  281. package/src/audit/proof.test.ts +67 -0
  282. package/src/audit/proof.ts +70 -0
  283. package/src/audit/report-html.ts +9 -4
  284. package/src/audit/report-model.ts +16 -2
  285. package/src/audit/report.test.ts +33 -0
  286. package/src/audit/report.ts +5 -3
  287. package/src/audit/rules-doc.test.ts +34 -2
  288. package/src/audit/rules-doc.ts +82 -9
  289. package/src/audit/secrets.ts +15 -3
  290. package/src/audit/terraform-state.test.ts +144 -0
  291. package/src/audit/terraform-state.ts +131 -0
  292. package/src/build.ts +31 -1
  293. package/src/claimed-fields.test.ts +145 -0
  294. package/src/claimed-fields.ts +208 -0
  295. package/src/cli/build-params-cli.ts +2 -2
  296. package/src/cli/command-group.ts +14 -0
  297. package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
  298. package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
  299. package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
  300. package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
  301. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
  302. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
  303. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
  304. package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
  305. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
  306. package/src/cli/commands/audit.test.ts +191 -11
  307. package/src/cli/commands/audit.ts +78 -28
  308. package/src/cli/commands/build.test.ts +330 -9
  309. package/src/cli/commands/build.ts +170 -24
  310. package/src/cli/commands/carve-bridge.test.ts +237 -14
  311. package/src/cli/commands/carve-bridge.ts +21 -17
  312. package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
  313. package/src/cli/commands/check-lexicon-docs.ts +1 -1
  314. package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
  315. package/src/cli/commands/check-lexicon-examples.ts +42 -10
  316. package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
  317. package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
  318. package/src/cli/commands/init-lexicon.test.ts +97 -2
  319. package/src/cli/commands/init-lexicon.ts +4 -2
  320. package/src/cli/commands/init.test.ts +35 -1
  321. package/src/cli/commands/init.ts +14 -3
  322. package/src/cli/commands/lint.test.ts +194 -1
  323. package/src/cli/commands/lint.ts +205 -7
  324. package/src/cli/commands/onboard.test.ts +75 -0
  325. package/src/cli/commands/onboard.ts +54 -23
  326. package/src/cli/handlers/build.test.ts +81 -1
  327. package/src/cli/handlers/build.ts +15 -1
  328. package/src/cli/handlers/graph.test.ts +3 -3
  329. package/src/cli/handlers/lifecycle.test.ts +195 -12
  330. package/src/cli/handlers/lifecycle.ts +123 -6
  331. package/src/cli/handlers/misc.ts +1 -1
  332. package/src/cli/handlers/operator.test.ts +183 -11
  333. package/src/cli/handlers/operator.ts +341 -55
  334. package/src/cli/handlers/run.test.ts +568 -1295
  335. package/src/cli/handlers/run.ts +446 -912
  336. package/src/cli/main.test.ts +22 -16
  337. package/src/cli/main.ts +66 -33
  338. package/src/cli/mcp/op-tools.ts +147 -88
  339. package/src/cli/mcp/resource-handlers.ts +10 -37
  340. package/src/cli/mcp/resources/context.ts +11 -12
  341. package/src/cli/mcp/server.test.ts +25 -27
  342. package/src/cli/mcp/server.ts +2 -2
  343. package/src/cli/plugins.test.ts +68 -2
  344. package/src/cli/plugins.ts +39 -0
  345. package/src/cli/registry.ts +40 -9
  346. package/src/codegen/docs.ts +1 -1
  347. package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
  348. package/src/codegen/generate-post-synth-barrel.ts +1 -1
  349. package/src/components/README.md +4 -3
  350. package/src/components/__fixtures__/neo4j-fanout.json +1 -1
  351. package/src/components/auto-release.test.ts +4 -20
  352. package/src/components/auto-release.ts +17 -42
  353. package/src/components/capability.ts +4 -4
  354. package/src/components/cli-support.test.ts +28 -12
  355. package/src/components/cli-support.ts +60 -47
  356. package/src/components/component-schema.test.ts +18 -2
  357. package/src/components/component.schema.json +18 -5
  358. package/src/components/component.test.ts +2 -2
  359. package/src/components/component.ts +27 -7
  360. package/src/components/config-defaults.test.ts +2 -2
  361. package/src/components/driver-output.ts +14 -2
  362. package/src/components/driver.test.ts +109 -20
  363. package/src/components/driver.ts +201 -84
  364. package/src/components/index.ts +1 -6
  365. package/src/components/manifest-persistence.test.ts +2 -20
  366. package/src/components/manifest-persistence.ts +4 -24
  367. package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
  368. package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
  369. package/src/components/run-progress.ts +6 -6
  370. package/src/components/verbs/run-agent.test.ts +19 -0
  371. package/src/components/verbs/run-agent.ts +12 -24
  372. package/src/components/verbs/verify.ts +2 -2
  373. package/src/deep-observation.test.ts +75 -0
  374. package/src/deep-observation.ts +48 -0
  375. package/src/detectLexicon.ts +18 -1
  376. package/src/discovery/collect.test.ts +3 -3
  377. package/src/discovery/files.ts +4 -4
  378. package/src/discovery/fold-import.test.ts +1 -1
  379. package/src/discovery/fold-import.ts +105 -2
  380. package/src/discovery/param-deps.test.ts +112 -1
  381. package/src/discovery/param-deps.ts +193 -0
  382. package/src/discovery/sandbox/bundle.ts +15 -1
  383. package/src/discovery/sandbox/config-wire.test.ts +2 -2
  384. package/src/discovery/sandbox/config-wire.ts +2 -2
  385. package/src/fold/fold.test.ts +56 -0
  386. package/src/fold/foldable-helpers.ts +82 -2
  387. package/src/fold-provenance-exclusion.test.ts +186 -0
  388. package/src/fold-provenance.test.ts +495 -0
  389. package/src/fold-provenance.ts +441 -0
  390. package/src/graph-ops.test.ts +3 -3
  391. package/src/graph-ops.ts +1 -1
  392. package/src/held-elsewhere.test.ts +102 -0
  393. package/src/held-elsewhere.ts +114 -0
  394. package/src/index.ts +3 -0
  395. package/src/kubectl-context.ts +3 -3
  396. package/src/lexicon-config.test.ts +5 -5
  397. package/src/lexicon-config.ts +4 -4
  398. package/src/lexicon-plugin-helpers.ts +1 -1
  399. package/src/lexicon.ts +296 -16
  400. package/src/lifecycle/change-set.test.ts +49 -0
  401. package/src/lifecycle/change-set.ts +67 -0
  402. package/src/lifecycle/converge-ledger.ts +1 -1
  403. package/src/lifecycle/deep-diff.test.ts +267 -14
  404. package/src/lifecycle/deep-diff.ts +217 -14
  405. package/src/lifecycle/deep-observe.test.ts +3 -1
  406. package/src/lifecycle/deep-observe.ts +16 -6
  407. package/src/lifecycle/gate-ledger.test.ts +74 -2
  408. package/src/lifecycle/gate-ledger.ts +154 -36
  409. package/src/lifecycle/index.ts +1 -0
  410. package/src/lifecycle/release-ledger.ts +2 -2
  411. package/src/lifecycle/run-ledger.test.ts +268 -0
  412. package/src/lifecycle/run-ledger.ts +201 -0
  413. package/src/lifecycle/symptoms.ts +3 -3
  414. package/src/lint/config.test.ts +82 -1
  415. package/src/lint/config.ts +112 -3
  416. package/src/lint/pipeline-change-gate.test.ts +2 -2
  417. package/src/lint/policy.test.ts +1 -1
  418. package/src/lint/post-synth.test.ts +31 -0
  419. package/src/lint/post-synth.ts +54 -1
  420. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
  421. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
  422. package/src/lint/rules/comp/comp.test.ts +27 -1
  423. package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
  424. package/src/lint/rules/comp/index.ts +3 -3
  425. package/src/lint/rules/op/index.ts +23 -0
  426. package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
  427. package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
  428. package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
  429. package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
  430. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
  431. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
  432. package/src/lint/rules/op/support.ts +11 -0
  433. package/src/lint/suppressions.test.ts +163 -0
  434. package/src/lint/suppressions.ts +204 -0
  435. package/src/live-endpoint.ts +1 -1
  436. package/src/op/activities/activity-contracts.ts +66 -0
  437. package/src/op/activities/apply.test.ts +567 -0
  438. package/src/op/activities/apply.ts +662 -0
  439. package/src/op/activities/build.ts +26 -0
  440. package/src/op/activities/converge.test.ts +330 -0
  441. package/src/op/activities/converge.ts +449 -0
  442. package/src/op/activities/env-teardown.test.ts +187 -0
  443. package/src/op/activities/env-teardown.ts +171 -0
  444. package/src/op/activities/guard-validate.test.ts +139 -0
  445. package/src/op/activities/guard-validate.ts +223 -0
  446. package/src/op/activities/http-check.test.ts +48 -0
  447. package/src/op/activities/http-check.ts +55 -0
  448. package/src/op/activities/index.ts +119 -0
  449. package/src/op/activities/lexicon-upgrade.test.ts +492 -0
  450. package/src/op/activities/lexicon-upgrade.ts +673 -0
  451. package/src/op/activities/lifecycle.ts +85 -0
  452. package/src/op/activities/pipeline-audit.test.ts +67 -0
  453. package/src/op/activities/pipeline-audit.ts +201 -0
  454. package/src/op/activities/policy.test.ts +19 -0
  455. package/src/op/activities/policy.ts +37 -0
  456. package/src/op/activities/reconcile.test.ts +161 -0
  457. package/src/op/activities/reconcile.ts +354 -0
  458. package/src/op/activities/shell.ts +26 -0
  459. package/src/op/activities/teardown.ts +22 -0
  460. package/src/op/activities/util.ts +6 -0
  461. package/src/op/activities/wait.ts +69 -0
  462. package/src/op/activities/workflow-audit.test.ts +90 -0
  463. package/src/op/activities/workflow-audit.ts +203 -0
  464. package/src/op/activity-contract-registry.test.ts +98 -0
  465. package/src/op/activity-contract-registry.ts +114 -0
  466. package/src/op/activity-contract.test.ts +1 -1
  467. package/src/op/activity-contract.ts +37 -33
  468. package/src/op/activity-failure.ts +34 -0
  469. package/src/op/activity-profiles.test.ts +56 -0
  470. package/src/op/activity-profiles.ts +116 -0
  471. package/src/op/activity-registry.test.ts +37 -28
  472. package/src/op/activity-registry.ts +27 -56
  473. package/src/op/activity-runtime.ts +3 -47
  474. package/src/op/builders-exports.test.ts +0 -49
  475. package/src/op/builders-typed.test.ts +164 -0
  476. package/src/op/builders.ts +125 -41
  477. package/src/op/change-signal.test.ts +117 -0
  478. package/src/op/change-signal.ts +169 -0
  479. package/src/op/composites/apply-op.ts +218 -0
  480. package/src/op/composites/composites.test.ts +379 -0
  481. package/src/op/composites/converge-op.test.ts +168 -0
  482. package/src/op/composites/converge-op.ts +214 -0
  483. package/src/op/composites/index.ts +26 -0
  484. package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
  485. package/src/op/composites/lexicon-upgrade-op.ts +134 -0
  486. package/src/op/composites/pipeline-audit-op.test.ts +25 -0
  487. package/src/op/composites/pipeline-audit-op.ts +78 -0
  488. package/src/op/composites/reconcile-op.test.ts +51 -0
  489. package/src/op/composites/reconcile-op.ts +110 -0
  490. package/src/op/composites/watch-op.ts +108 -0
  491. package/src/op/composites/workflow-audit-op.test.ts +25 -0
  492. package/src/op/composites/workflow-audit-op.ts +88 -0
  493. package/src/op/converge-rule.ts +12 -10
  494. package/src/op/cron.test.ts +128 -0
  495. package/src/op/cron.ts +149 -0
  496. package/src/op/discover-root.test.ts +105 -1
  497. package/src/op/discover.test.ts +6 -2
  498. package/src/op/discover.ts +84 -16
  499. package/src/op/duration.ts +21 -0
  500. package/src/op/effect-step.test.ts +29 -14
  501. package/src/op/emulator-lifecycle.ts +1 -2
  502. package/src/op/gate-name.test.ts +65 -0
  503. package/src/op/gate-name.ts +60 -0
  504. package/src/op/gate-summary.ts +84 -0
  505. package/src/op/gate.ts +155 -0
  506. package/src/op/generate-pipeline.test.ts +65 -3
  507. package/src/op/generate-pipeline.ts +19 -2
  508. package/src/op/index.ts +48 -8
  509. package/src/op/local-executor.test.ts +178 -34
  510. package/src/op/local-executor.ts +371 -102
  511. package/src/op/local-output.test.ts +95 -11
  512. package/src/op/local-output.ts +33 -4
  513. package/src/op/op-ir.test.ts +292 -0
  514. package/src/op/op-ir.ts +419 -0
  515. package/src/op/op-verb-class.test.ts +2 -2
  516. package/src/op/op-verb-class.ts +19 -5
  517. package/src/op/op.test.ts +28 -7
  518. package/src/op/operator.test.ts +543 -6
  519. package/src/op/operator.ts +203 -20
  520. package/src/op/receipt-store.ts +1 -1
  521. package/src/op/resource.ts +20 -2
  522. package/src/op/runtime.ts +203 -0
  523. package/src/op/runtimes/local.test.ts +181 -0
  524. package/src/op/runtimes/local.ts +212 -0
  525. package/src/op/step-output-ref.ts +15 -13
  526. package/src/op/types.ts +106 -26
  527. package/src/ownership.ts +1 -1
  528. package/src/provenance.test.ts +6 -0
  529. package/src/provenance.ts +21 -1
  530. package/src/serializer-walker.test.ts +42 -0
  531. package/src/serializer-walker.ts +21 -2
  532. package/src/terraform/aws-resources.test.ts +13 -4
  533. package/src/terraform/bridge.test.ts +22 -9
  534. package/src/terraform/bridge.ts +89 -28
  535. package/src/terraform/carve-provider.ts +38 -2
  536. package/src/terraform/data-source-shape.ts +95 -0
  537. package/src/terraform/graph.ts +35 -7
  538. package/src/terraform/providers/kubernetes.ts +48 -2
  539. package/src/terraform/tier-map.ts +21 -6
  540. package/src/terraform/types.ts +8 -0
  541. package/dist/cli/handlers/op-progress.d.ts +0 -90
  542. package/dist/cli/handlers/op-progress.d.ts.map +0 -1
  543. package/dist/cli/handlers/run-client.d.ts +0 -127
  544. package/dist/cli/handlers/run-client.d.ts.map +0 -1
  545. package/dist/cli/handlers/run-report.d.ts +0 -5
  546. package/dist/cli/handlers/run-report.d.ts.map +0 -1
  547. package/dist/components/temporal-codegen-loader.d.ts +0 -27
  548. package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
  549. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
  550. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
  551. package/src/cli/handlers/op-progress.test.ts +0 -268
  552. package/src/cli/handlers/op-progress.ts +0 -248
  553. package/src/cli/handlers/run-client.test.ts +0 -82
  554. package/src/cli/handlers/run-client.ts +0 -219
  555. package/src/cli/handlers/run-report.test.ts +0 -62
  556. package/src/cli/handlers/run-report.ts +0 -122
  557. package/src/components/temporal-codegen-loader.ts +0 -41
  558. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
@@ -0,0 +1,354 @@
1
+ import { exec } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import { promisify } from "node:util";
4
+
5
+ const execAsync = promisify(exec);
6
+
7
+ /**
8
+ * What the reconcile activity does with the regenerated source.
9
+ *
10
+ * `comment` is the one mode that posts nothing new: it writes the body onto
11
+ * the pull request that triggered the run, updating the same comment on every
12
+ * re-run (chant #2231). It therefore needs a pull-request trigger, and
13
+ * {@link resolvePullRequestContext} fails the step by name when the run has
14
+ * none.
15
+ */
16
+ export type ReconcileMode = "pull-request" | "issue" | "report" | "comment";
17
+
18
+ /** A change-set entry that triggered reconciliation. */
19
+ export interface ReconcileEntry {
20
+ /** chant entity name. */
21
+ name: string;
22
+ /** create | update | delete | adopt | noop (from `chant lifecycle plan`). */
23
+ action: string;
24
+ /** Resource type, when known. */
25
+ type?: string;
26
+ }
27
+
28
+ export interface ReconcilePrArgs {
29
+ /** Environment to reconcile from (passed to `chant import --from`). */
30
+ env: string;
31
+ /**
32
+ * The change-set entries that triggered this reconcile. Omit to derive them
33
+ * from `chant lifecycle plan <env> --json` at run time — the form used inside
34
+ * an Op, where the entries aren't known until the activity runs.
35
+ */
36
+ entries?: ReconcileEntry[];
37
+ /** What to produce. Default: pull-request. */
38
+ mode?: ReconcileMode;
39
+ /** Output directory for regenerated source. Default: ./infra. */
40
+ output?: string;
41
+ /** Branch to open the PR from. Default: chant/reconcile-<env>. */
42
+ branch?: string;
43
+ /** Restrict live import to chant-owned resources. */
44
+ owned?: boolean;
45
+ /** PR / issue title. Default derived from env. */
46
+ title?: string;
47
+ /**
48
+ * Hidden marker identifying this Op's comment on the pull request (comment
49
+ * mode). The activity writes it as the comment's first line and finds the
50
+ * comment again by it on the next run, so a re-run edits one comment instead
51
+ * of stacking a new one. Default: {@link commentMarker} keyed on `env`, so
52
+ * two Ops over two roots get two comments and each updates in place.
53
+ */
54
+ marker?: string;
55
+ /**
56
+ * A finding body built by the caller, used verbatim as the issue/PR body in
57
+ * place of {@link reconcileSummary} (chant #2087).
58
+ *
59
+ * The summary this activity writes itself is a change-set table, which is
60
+ * the right artifact when the finding IS a change set. Some observe-dial
61
+ * Ops already hold a better one: `TerraformWatchOp` carries the
62
+ * `terraform plan -no-color` render its own Plan step produced, and
63
+ * re-deriving that from `chant lifecycle plan` here would both lose the
64
+ * plan and run a second, differently-timed read.
65
+ *
66
+ * Supplying it also suppresses the `chant lifecycle plan --json` derivation
67
+ * that fills `entries`: a caller that already knows what it wants to say
68
+ * is not asking this activity to go and find out.
69
+ */
70
+ body?: string;
71
+ }
72
+
73
+ export interface ReconcileResult {
74
+ mode: ReconcileMode;
75
+ /** Branch created (pull-request mode). */
76
+ branch?: string;
77
+ /** Opened PR URL (pull-request mode). */
78
+ prUrl?: string;
79
+ /** Opened issue URL (issue mode). */
80
+ issueUrl?: string;
81
+ /** The posted or updated PR comment's URL (comment mode). */
82
+ commentUrl?: string;
83
+ /** The pull request the comment landed on, `owner/repo#number` (comment mode). */
84
+ pullRequest?: string;
85
+ /** The markdown summary used as the PR/issue body. */
86
+ summary: string;
87
+ /** The entries that triggered the reconcile. */
88
+ entries: ReconcileEntry[];
89
+ }
90
+
91
+ /** Default branch name for a reconcile PR. Deterministic — no timestamp. */
92
+ export function reconcileBranchName(env: string): string {
93
+ const safe = env.replace(/[^a-zA-Z0-9._-]+/g, "-");
94
+ return `chant/reconcile-${safe}`;
95
+ }
96
+
97
+ /**
98
+ * Build the markdown body summarizing which change-set entries triggered the
99
+ * reconcile. Pure — used as the PR/issue body and returned in `report` mode.
100
+ */
101
+ export function reconcileSummary(env: string, entries: ReconcileEntry[]): string {
102
+ const lines = [
103
+ `Reconcile from live environment \`${env}\`.`,
104
+ "",
105
+ "This PR regenerates chant TypeScript from live state to close the gap between the cloud and source. It was triggered by the following change-set entries:",
106
+ "",
107
+ "| Entry | Action | Type |",
108
+ "|---|---|---|",
109
+ ];
110
+ for (const e of entries) {
111
+ lines.push(`| ${e.name} | ${e.action} | ${e.type ?? ""} |`);
112
+ }
113
+ if (entries.length === 0) {
114
+ lines.push("| _(none)_ | | |");
115
+ }
116
+ lines.push("");
117
+ lines.push("Review the diff before merging — live import may surface values that need redaction.");
118
+ return lines.join("\n");
119
+ }
120
+
121
+ function shellQuote(s: string): string {
122
+ return `'${s.replace(/'/g, "'\\''")}'`;
123
+ }
124
+
125
+ /** The pull request a `comment`-mode run posts onto. */
126
+ export interface PullRequestContext {
127
+ /** `owner/repo`, from `GITHUB_REPOSITORY`. */
128
+ repo: string;
129
+ /** The pull request number. */
130
+ number: number;
131
+ }
132
+
133
+ /**
134
+ * The hidden marker that makes a `comment`-mode finding findable across
135
+ * re-runs: written as the comment's first line, matched with `startswith` on
136
+ * the next run. Keyed on `env` (slugified the same way {@link
137
+ * reconcileBranchName} slugifies it, which also keeps the value free of the
138
+ * quotes and backslashes it is interpolated next to), so two Ops over two
139
+ * environments own two comments and each updates in place.
140
+ */
141
+ export function commentMarker(env: string): string {
142
+ return `<!-- chant-reconcile:${env.replace(/[^a-zA-Z0-9._-]+/g, "-")} -->`;
143
+ }
144
+
145
+ /** What a `comment`-mode step says when the run it is in has no pull request. */
146
+ export function noPullRequestContextMessage(): string {
147
+ return (
148
+ 'reconcilePr mode "comment" posts the finding on the pull request that triggered the run, and this run ' +
149
+ "has none. It needs GITHUB_REPOSITORY plus a pull request number, read from the event payload at " +
150
+ "GITHUB_EVENT_PATH (`.number` / `.pull_request.number`) or from GITHUB_REF (`refs/pull/<n>/merge`). " +
151
+ "GitHub Actions sets those on a pull_request event and on nothing else. Trigger this Op from a " +
152
+ 'pull_request workflow, or give it findingMode "issue" or "report".'
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Read the pull request number out of a parsed webhook event payload. Pure.
158
+ * A `pull_request` event carries it top-level as `number` and again under
159
+ * `pull_request.number`; both are accepted, neither is invented.
160
+ */
161
+ function prNumberFromPayload(payload: unknown): number | undefined {
162
+ if (typeof payload !== "object" || payload === null) return undefined;
163
+ const p = payload as { number?: unknown; pull_request?: { number?: unknown } };
164
+ if (typeof p.number === "number") return p.number;
165
+ if (typeof p.pull_request?.number === "number") return p.pull_request.number;
166
+ return undefined;
167
+ }
168
+
169
+ /**
170
+ * Derive the triggering pull request from CI environment variables plus the
171
+ * already-parsed event payload. Pure — exported for testing; the IO (reading
172
+ * `GITHUB_EVENT_PATH`) is {@link resolvePullRequestContext}'s.
173
+ *
174
+ * Returns undefined rather than throwing, so the caller owns the message.
175
+ */
176
+ export function pullRequestContextFrom(
177
+ env: Record<string, string | undefined>,
178
+ eventPayload?: unknown,
179
+ ): PullRequestContext | undefined {
180
+ const repo = env.GITHUB_REPOSITORY;
181
+ if (!repo) return undefined;
182
+ const fromRef = /^refs\/pull\/(\d+)\//.exec(env.GITHUB_REF ?? "")?.[1];
183
+ const number = prNumberFromPayload(eventPayload) ?? (fromRef ? Number(fromRef) : undefined);
184
+ if (number === undefined || !Number.isInteger(number) || number <= 0) return undefined;
185
+ return { repo, number };
186
+ }
187
+
188
+ /**
189
+ * Resolve the triggering pull request, reading and parsing the event payload
190
+ * `GITHUB_EVENT_PATH` names. Throws {@link noPullRequestContextMessage} when
191
+ * the run has no pull request, which is the whole point: a `comment` mode that
192
+ * quietly fell back to an issue would post the finding somewhere nobody asked
193
+ * for it.
194
+ */
195
+ export async function resolvePullRequestContext(
196
+ env: Record<string, string | undefined> = process.env,
197
+ ): Promise<PullRequestContext> {
198
+ let payload: unknown;
199
+ const eventPath = env.GITHUB_EVENT_PATH;
200
+ if (eventPath) {
201
+ try {
202
+ payload = JSON.parse(await readFile(eventPath, "utf8"));
203
+ } catch {
204
+ // An unreadable or malformed payload is not fatal on its own: GITHUB_REF
205
+ // may still name the pull request. If it does not, the error below says so.
206
+ payload = undefined;
207
+ }
208
+ }
209
+ const ctx = pullRequestContextFrom(env, payload);
210
+ if (!ctx) throw new Error(noPullRequestContextMessage());
211
+ return ctx;
212
+ }
213
+
214
+ /**
215
+ * Post `body` as one comment on `ctx`'s pull request, or edit the comment this
216
+ * Op already owns there. The sticky-comment recipe the github lexicon's
217
+ * `PrPlanReport` uses, run from the activity instead of from generated YAML:
218
+ * find the comment whose body starts with `marker`, PATCH it when there is
219
+ * one, POST otherwise. `gh` ships on GitHub's hosted runners and is already
220
+ * this activity's dependency for the issue and pull-request modes, so the
221
+ * mode needs nothing new on the runner.
222
+ */
223
+ async function postOrUpdateComment(
224
+ ctx: PullRequestContext,
225
+ marker: string,
226
+ body: string,
227
+ signal?: AbortSignal,
228
+ ): Promise<string> {
229
+ const listPath = `repos/${ctx.repo}/issues/${ctx.number}/comments`;
230
+ const jq = `map(select(.body | startswith("${marker}"))) | .[0].id // empty`;
231
+ const { stdout: found } = await execAsync(
232
+ `gh api ${shellQuote(listPath)} --paginate --jq ${shellQuote(jq)}`,
233
+ { signal },
234
+ );
235
+ // `--paginate` prints one `--jq` result per page, so take the first line
236
+ // that is an id and ignore the empty ones the other pages produce.
237
+ const existing = found.split("\n").map((l) => l.trim()).find((l) => /^\d+$/.test(l));
238
+ const field = `body=${marker}\n\n${body}`;
239
+
240
+ if (existing) {
241
+ const { stdout } = await execAsync(
242
+ `gh api --method PATCH ${shellQuote(`repos/${ctx.repo}/issues/comments/${existing}`)} ` +
243
+ `-f ${shellQuote(field)} --jq .html_url`,
244
+ { signal },
245
+ );
246
+ return stdout.trim();
247
+ }
248
+ const { stdout } = await execAsync(
249
+ `gh api --method POST ${shellQuote(listPath)} -f ${shellQuote(field)} --jq .html_url`,
250
+ { signal },
251
+ );
252
+ return stdout.trim();
253
+ }
254
+
255
+ /**
256
+ * Map a `chant lifecycle plan --json` ChangeSet to reconcile entries, dropping
257
+ * `noop` entries (nothing to reconcile). Pure — exported for testing.
258
+ */
259
+ export function entriesFromPlan(planJson: string): ReconcileEntry[] {
260
+ const cs = JSON.parse(planJson) as {
261
+ entries?: Array<{ name: string; action: string; type?: string }>;
262
+ };
263
+ return (cs.entries ?? [])
264
+ .filter((e) => e.action !== "noop")
265
+ .map((e) => ({ name: e.name, action: e.action, type: e.type }));
266
+ }
267
+
268
+ /** Derive reconcile entries from `chant lifecycle plan`. */
269
+ async function derivePlanEntries(
270
+ env: string,
271
+ owned: boolean,
272
+ signal?: AbortSignal,
273
+ ): Promise<ReconcileEntry[]> {
274
+ const ownedFlag = owned ? " --owned" : "";
275
+ const { stdout } = await execAsync(
276
+ `chant lifecycle plan ${shellQuote(env)}${ownedFlag} --json`,
277
+ { signal },
278
+ );
279
+ return entriesFromPlan(stdout);
280
+ }
281
+
282
+ /**
283
+ * Reconcile activity: turn regenerated TypeScript into a reviewable artifact.
284
+ *
285
+ * - `report` — return the summary only; no git, no network.
286
+ * - `issue` — open a GitHub issue describing the drift (no code change).
287
+ * - `comment` — post the body as one comment on the pull request that
288
+ * triggered the run, editing that same comment on every re-run rather than
289
+ * stacking a new one (#2231). Needs a pull-request-triggered run; fails by
290
+ * name when there is none. No code change, and the `pull-requests: write`
291
+ * the generated workflow already grants on that trigger is the whole scope
292
+ * it spends.
293
+ * - `pull-request` — create a branch, regenerate source via
294
+ * `chant import --from <env>`, commit, push, and open a PR whose diff is the
295
+ * regenerated TypeScript. Never commits to the main branch.
296
+ *
297
+ * The body is {@link reconcileSummary}'s change-set table unless `args.body`
298
+ * supplies one, in which case that text is used verbatim and no plan is
299
+ * derived (chant #2087).
300
+ *
301
+ * Requires `chant` and (for non-report modes) `gh`/`git` in the environment.
302
+ */
303
+ export async function reconcilePr(args: ReconcilePrArgs, signal?: AbortSignal): Promise<ReconcileResult> {
304
+ const mode = args.mode ?? "pull-request";
305
+ const owned = args.owned ?? false;
306
+ // A caller-supplied body means the finding is already written, so there is
307
+ // nothing for `chant lifecycle plan` to tell us (#2087).
308
+ const entries = args.entries ?? (args.body !== undefined ? [] : await derivePlanEntries(args.env, owned, signal));
309
+ const summary = args.body ?? reconcileSummary(args.env, entries);
310
+ const title = args.title ?? `Reconcile ${args.env}: ${entries.length} change(s) from live`;
311
+
312
+ if (mode === "report") {
313
+ return { mode, summary, entries };
314
+ }
315
+
316
+ if (mode === "issue") {
317
+ const { stdout } = await execAsync(
318
+ `gh issue create --title ${shellQuote(title)} --body ${shellQuote(summary)}`,
319
+ { signal },
320
+ );
321
+ return { mode, summary, entries, issueUrl: stdout.trim() };
322
+ }
323
+
324
+ if (mode === "comment") {
325
+ // The trigger context is read here rather than passed in: a step's args
326
+ // are serialized at build time, and the pull request is not known until
327
+ // the run. Missing context is fatal — see `noPullRequestContextMessage`.
328
+ const ctx = await resolvePullRequestContext();
329
+ const marker = args.marker ?? commentMarker(args.env);
330
+ const commentUrl = await postOrUpdateComment(ctx, marker, summary, signal);
331
+ return { mode, summary, entries, commentUrl, pullRequest: `${ctx.repo}#${ctx.number}` };
332
+ }
333
+
334
+ // pull-request
335
+ const branch = args.branch ?? reconcileBranchName(args.env);
336
+ const output = args.output ?? "./infra";
337
+ const ownedFlag = owned ? " --owned" : "";
338
+
339
+ // Never touch the main branch: cut a fresh branch first.
340
+ await execAsync(`git checkout -b ${shellQuote(branch)}`, { signal });
341
+ await execAsync(
342
+ `chant import --from ${shellQuote(args.env)}${ownedFlag} --output ${shellQuote(output)} --force`,
343
+ { signal },
344
+ );
345
+ await execAsync(`git add ${shellQuote(output)}`, { signal });
346
+ await execAsync(`git commit -m ${shellQuote(title)}`, { signal });
347
+ await execAsync(`git push -u origin ${shellQuote(branch)}`, { signal });
348
+ const { stdout } = await execAsync(
349
+ `gh pr create --title ${shellQuote(title)} --body ${shellQuote(summary)} --head ${shellQuote(branch)}`,
350
+ { signal },
351
+ );
352
+
353
+ return { mode, branch, summary, entries, prUrl: stdout.trim() };
354
+ }
@@ -0,0 +1,26 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+
4
+ const execAsync = promisify(exec);
5
+
6
+ export interface ShellCmdArgs {
7
+ cmd: string;
8
+ /** Additional environment variables. */
9
+ env?: Record<string, string>;
10
+ /** Working directory. Default: process.cwd(). */
11
+ cwd?: string;
12
+ }
13
+
14
+ /**
15
+ * Run an arbitrary shell command.
16
+ * Uses fastIdempotent profile — 5m timeout, 3 retries.
17
+ */
18
+ export async function shellCmd(args: ShellCmdArgs, signal?: AbortSignal): Promise<string> {
19
+ const { stdout, stderr } = await execAsync(args.cmd, {
20
+ cwd: args.cwd,
21
+ env: { ...process.env, ...args.env },
22
+ signal,
23
+ });
24
+ if (stderr) console.error(stderr);
25
+ return stdout.trim();
26
+ }
@@ -0,0 +1,22 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+
4
+ const execAsync = promisify(exec);
5
+
6
+ export interface ChantTeardownArgs {
7
+ /** Path to the chant project to tear down. */
8
+ path: string;
9
+ }
10
+
11
+ /**
12
+ * Run `chant teardown` in the given project path.
13
+ * Uses longInfra profile — 20m timeout.
14
+ */
15
+ export async function chantTeardown(args: ChantTeardownArgs, signal?: AbortSignal): Promise<void> {
16
+ const { stdout, stderr } = await execAsync("npm run teardown", {
17
+ cwd: args.path,
18
+ signal,
19
+ });
20
+ if (stdout) console.log(stdout);
21
+ if (stderr) console.error(stderr);
22
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-export shim — `sleep` is the shared activity-runtime helper one directory
3
+ * up (`../activity-runtime`). Kept here so existing `./util` imports resolve
4
+ * unchanged.
5
+ */
6
+ export { sleep } from "../activity-runtime";
@@ -0,0 +1,69 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { sleep } from "./util";
4
+
5
+ const execAsync = promisify(exec);
6
+
7
+ export interface WaitForStackArgs {
8
+ /** Stack name — used to locate the kubectl deployment/statefulset to poll. */
9
+ name: string;
10
+ /** Kubernetes namespace. */
11
+ namespace?: string;
12
+ /** kubectl context. */
13
+ context?: string;
14
+ /** Poll interval in ms. Default: 10000. */
15
+ intervalMs?: number;
16
+ }
17
+
18
+ /**
19
+ * Poll until a Kubernetes Deployment or StatefulSet named `name` is fully rolled out.
20
+ * Uses the `k8sWait` profile — 15m timeout.
21
+ *
22
+ * Progress goes to stdout, one line per poll, which is the executor's step-record
23
+ * channel: the local executor streams an activity's output alongside the step it
24
+ * belongs to, so a long rollout is visible without a liveness protocol. Nothing
25
+ * mid-run is durable here by design (chant #2114) — the op re-runs and converges.
26
+ *
27
+ * Deliberately NOT migrated onto the generic `waitForReady` (#957): `kubectl
28
+ * rollout status` encodes rollout-specific semantics — progress-deadline
29
+ * timeouts, partial/paused rollouts, generation tracking — that a status-field
30
+ * predicate spec does not replicate, and it targets built-in workloads rather
31
+ * than arbitrary operator CRDs. `waitForReady` is the right tool for CRD
32
+ * readiness; `waitForStack` stays the right tool for workload rollouts.
33
+ */
34
+ export async function waitForStack(args: WaitForStackArgs, signal?: AbortSignal): Promise<void> {
35
+ const ns = args.namespace ? `-n ${args.namespace}` : "";
36
+ const ctx = args.context ? `--context ${args.context}` : "";
37
+ const interval = args.intervalMs ?? 10_000;
38
+ let attempt = 0;
39
+
40
+ while (true) {
41
+ if (signal?.aborted) throw new Error("waitForStack aborted");
42
+ attempt++;
43
+ console.log(`[waitForStack] ${args.name}: poll ${attempt}`);
44
+
45
+ try {
46
+ await execAsync(
47
+ `kubectl rollout status deployment/${args.name} ${ns} ${ctx} --timeout=30s`,
48
+ { signal },
49
+ );
50
+ return;
51
+ } catch {
52
+ if (signal?.aborted) throw new Error("waitForStack aborted");
53
+ // Not ready yet — wait and retry
54
+ }
55
+
56
+ try {
57
+ await execAsync(
58
+ `kubectl rollout status statefulset/${args.name} ${ns} ${ctx} --timeout=30s`,
59
+ { signal },
60
+ );
61
+ return;
62
+ } catch {
63
+ if (signal?.aborted) throw new Error("waitForStack aborted");
64
+ // Not ready yet
65
+ }
66
+
67
+ await sleep(interval, signal);
68
+ }
69
+ }
@@ -0,0 +1,90 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import {
3
+ workflowSupplyChainAudit,
4
+ collectAuditRefs,
5
+ type ActionRefResolution,
6
+ type ActionRefResolver,
7
+ } from "./workflow-audit";
8
+
9
+ const SHA = "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b";
10
+
11
+ const WORKFLOW = `name: CI
12
+ on:
13
+ push:
14
+ jobs:
15
+ build:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@${SHA} # v4.1.0
19
+ - uses: evil/typo-action@v1
20
+ - uses: archived/old-action@v2
21
+ `;
22
+
23
+ /** Recorded upstream responses — no live network. */
24
+ function recordedResolver(records: Record<string, ActionRefResolution>): ActionRefResolver {
25
+ return async (slug, ref) =>
26
+ records[`${slug}@${ref}`] ?? { exists: true, tags: [], archived: false, advisories: [] };
27
+ }
28
+
29
+ describe("collectAuditRefs (#292)", () => {
30
+ test("collects external refs with version comments, skipping local/docker", () => {
31
+ const yaml = `jobs:
32
+ a:
33
+ steps:
34
+ - uses: actions/checkout@${SHA} # v4.1.0
35
+ - uses: ./.github/actions/local
36
+ - uses: docker://alpine:3.19
37
+ - uses: org/reusable/.github/workflows/x.yml@v1
38
+ `;
39
+ const refs = collectAuditRefs(yaml);
40
+ const slugs = refs.map((r) => r.slug);
41
+ expect(slugs).toContain("actions/checkout");
42
+ expect(slugs).toContain("org/reusable");
43
+ expect(slugs).not.toContain("./.github");
44
+ expect(refs.find((r) => r.slug === "actions/checkout")?.comment).toBe("v4.1.0");
45
+ });
46
+ });
47
+
48
+ describe("workflowSupplyChainAudit (#292)", () => {
49
+ test("flags stale pin, impostor, archived, and pin/comment mismatch", async () => {
50
+ const resolver = recordedResolver({
51
+ // SHA no longer on any tag → stale; actual tag differs from comment → mismatch
52
+ [`actions/checkout@${SHA}`]: { exists: true, tags: ["v4.2.0"], archived: false, advisories: [] },
53
+ "evil/typo-action@v1": { exists: false, tags: [], archived: false, advisories: [] },
54
+ "archived/old-action@v2": { exists: true, tags: ["v2"], archived: true, advisories: ["GHSA-xxxx"] },
55
+ });
56
+ const result = await workflowSupplyChainAudit({ yaml: WORKFLOW, resolver, mode: "issue" });
57
+ const kinds = result.findings.map((f) => `${f.slug}:${f.kind}`);
58
+
59
+ expect(kinds).toContain("evil/typo-action:impostor");
60
+ expect(kinds).toContain("archived/old-action:archived");
61
+ expect(kinds).toContain("archived/old-action:advisory");
62
+ expect(kinds).toContain("actions/checkout:pin-comment-mismatch");
63
+ expect(result.mode).toBe("issue");
64
+ expect(result.summary).toContain("Workflow supply-chain audit");
65
+ });
66
+
67
+ test("flags a stale SHA pin with no upstream tag", async () => {
68
+ const resolver = recordedResolver({
69
+ [`actions/checkout@${SHA}`]: { exists: true, tags: [], archived: false, advisories: [] },
70
+ "evil/typo-action@v1": { exists: true, tags: ["v1"], archived: false, advisories: [] },
71
+ "archived/old-action@v2": { exists: true, tags: ["v2"], archived: false, advisories: [] },
72
+ });
73
+ const result = await workflowSupplyChainAudit({ yaml: WORKFLOW, resolver });
74
+ expect(result.findings.some((f) => f.slug === "actions/checkout" && f.kind === "stale-pin")).toBe(true);
75
+ });
76
+
77
+ test("clean workflow yields no findings", async () => {
78
+ const yaml = `jobs:
79
+ build:
80
+ steps:
81
+ - uses: actions/checkout@${SHA}
82
+ `;
83
+ const resolver = recordedResolver({
84
+ [`actions/checkout@${SHA}`]: { exists: true, tags: ["v4"], archived: false, advisories: [] },
85
+ });
86
+ const result = await workflowSupplyChainAudit({ yaml, resolver });
87
+ expect(result.findings).toHaveLength(0);
88
+ expect(result.summary).toContain("No live drift");
89
+ });
90
+ });