@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.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +20 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +14 -8
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +28 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +26 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +20 -21
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +3 -3
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +66 -36
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +9 -15
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +104 -14
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +71 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +89 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +84 -29
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +113 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +23 -7
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +184 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +30 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +79 -27
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +61 -17
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +91 -15
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +189 -11
- package/src/cli/commands/audit.ts +73 -27
- package/src/cli/commands/build.test.ts +292 -9
- package/src/cli/commands/build.ts +156 -24
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +48 -0
- package/src/cli/commands/lint.ts +123 -0
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +260 -55
- package/src/cli/handlers/run.test.ts +431 -1287
- package/src/cli/handlers/run.ts +365 -915
- package/src/cli/main.test.ts +23 -15
- package/src/cli/main.ts +88 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/registry.ts +26 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +3 -2
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +10 -5
- package/src/components/cli-support.ts +52 -44
- package/src/components/component.schema.json +2 -2
- package/src/components/component.ts +3 -3
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +92 -22
- package/src/components/driver.ts +193 -83
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.ts +11 -17
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +81 -1
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +2 -2
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +120 -14
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +143 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +1 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +74 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +81 -0
- package/src/op/activities/reconcile.ts +187 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +123 -39
- package/src/op/composites/apply-op.ts +208 -0
- package/src/op/composites/composites.test.ts +366 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +107 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +26 -11
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +39 -6
- package/src/op/local-executor.test.ts +163 -34
- package/src/op/local-executor.ts +370 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +281 -0
- package/src/op/op-ir.ts +417 -0
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +26 -5
- package/src/op/operator.test.ts +175 -6
- package/src/op/operator.ts +63 -16
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +84 -24
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
package/src/op/operator.test.ts
CHANGED
|
@@ -13,9 +13,27 @@ import {
|
|
|
13
13
|
} from "./operator";
|
|
14
14
|
import { readLease } from "../lifecycle/lease";
|
|
15
15
|
import { appendConvergeRecord, readConvergeLedger } from "../lifecycle/converge-ledger";
|
|
16
|
+
import { readRunLedger } from "../lifecycle/run-ledger";
|
|
17
|
+
import type { OpRunRecord } from "./runtime";
|
|
16
18
|
|
|
17
19
|
const PROFILES: Record<string, ActivityProfile> = {};
|
|
18
20
|
|
|
21
|
+
/** A minimal `OpRunRecord` for a result literal that never touches a ledger. */
|
|
22
|
+
function runRecord(op: string, status: OpRunRecord["status"] = "ok"): OpRunRecord {
|
|
23
|
+
return {
|
|
24
|
+
version: 1,
|
|
25
|
+
id: "00000000-0000-4000-8000-000000000000",
|
|
26
|
+
op,
|
|
27
|
+
env: "staging",
|
|
28
|
+
started: "2026-01-01T00:00:00.000Z",
|
|
29
|
+
ended: "2026-01-01T00:00:01.000Z",
|
|
30
|
+
status,
|
|
31
|
+
labels: {},
|
|
32
|
+
outcomes: {},
|
|
33
|
+
phases: [],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
19
37
|
function git(args: string[], cwd: string): { stdout: string; exitCode: number } {
|
|
20
38
|
const r = spawnSync("git", args, { cwd, encoding: "utf-8" });
|
|
21
39
|
return { stdout: r.stdout ?? "", exitCode: r.status ?? -1 };
|
|
@@ -34,7 +52,7 @@ async function initRepo(dir: string): Promise<void> {
|
|
|
34
52
|
* Write a minimal fixture ConvergeOp — the same `{ props: OpConfig }` shape
|
|
35
53
|
* `discoverOps` reads from a real `*.op.ts` file's default export
|
|
36
54
|
* (`../op/discover.ts`), hand-built here rather than going through the real
|
|
37
|
-
* `ConvergeOp()` composite
|
|
55
|
+
* `ConvergeOp()` composite so this suite tests the
|
|
38
56
|
* operator's own discovery/lease/tick-loop logic without depending on that
|
|
39
57
|
* lexicon at all. One "Converge" phase calling a single fake activity —
|
|
40
58
|
* `runOpLocally` doesn't care what the phases are named or how many there
|
|
@@ -50,7 +68,26 @@ function writeFixtureConvergeOp(dir: string, opName: string, env: string): void
|
|
|
50
68
|
name: ${JSON.stringify(opName)},
|
|
51
69
|
overview: "fixture converge op",
|
|
52
70
|
phases: [{ name: "Converge", steps: [{ kind: "activity", fn: "fakeTick", args: {} }] }],
|
|
53
|
-
|
|
71
|
+
labels: { Converge: "true", Env: ${JSON.stringify(env)}, Dial: "observe" },
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The same fixture with a cadence of its own (#2120) — what `ConvergeOp({ schedule })` produces. */
|
|
79
|
+
function writeFixtureScheduledConvergeOp(dir: string, opName: string, env: string, cron: string): void {
|
|
80
|
+
const opsDir = join(dir, "ops");
|
|
81
|
+
mkdirSync(opsDir, { recursive: true });
|
|
82
|
+
writeFileSync(
|
|
83
|
+
join(opsDir, `${opName}.op.ts`),
|
|
84
|
+
`export default {
|
|
85
|
+
props: {
|
|
86
|
+
name: ${JSON.stringify(opName)},
|
|
87
|
+
overview: "fixture scheduled converge op",
|
|
88
|
+
phases: [{ name: "Converge", steps: [{ kind: "activity", fn: "fakeTick", args: {} }] }],
|
|
89
|
+
labels: { Converge: "true", Env: ${JSON.stringify(env)}, Dial: "observe" },
|
|
90
|
+
schedule: { cron: ${JSON.stringify(cron)}, overlap: "skip" },
|
|
54
91
|
},
|
|
55
92
|
};
|
|
56
93
|
`,
|
|
@@ -99,7 +136,7 @@ function fakeTickActivities(dir: string, env: string, opName: string, opts?: { t
|
|
|
99
136
|
}
|
|
100
137
|
|
|
101
138
|
describe("discoverConvergeOps", () => {
|
|
102
|
-
test("finds only ops with
|
|
139
|
+
test("finds only ops with labels.Converge === 'true'", async () => {
|
|
103
140
|
await withTestDir(async (dir) => {
|
|
104
141
|
await initRepo(dir);
|
|
105
142
|
writeFixtureConvergeOp(dir, "staging-converge", "staging");
|
|
@@ -132,6 +169,28 @@ describe("discoverConvergeOps", () => {
|
|
|
132
169
|
expect(ops.map((d) => d.config.name)).toEqual(["prod-converge", "staging-converge"]);
|
|
133
170
|
});
|
|
134
171
|
});
|
|
172
|
+
|
|
173
|
+
test("a ConvergeOp declaring no labels.Env is discovered unfiltered but never matches --env", async () => {
|
|
174
|
+
await withTestDir(async (dir) => {
|
|
175
|
+
await initRepo(dir);
|
|
176
|
+
mkdirSync(join(dir, "ops"), { recursive: true });
|
|
177
|
+
writeFileSync(
|
|
178
|
+
join(dir, "ops", "envless-converge.op.ts"),
|
|
179
|
+
`export default {
|
|
180
|
+
props: {
|
|
181
|
+
name: "envless-converge",
|
|
182
|
+
overview: "a hand-built ConvergeOp with no Env label",
|
|
183
|
+
phases: [{ name: "Converge", steps: [{ kind: "activity", fn: "fakeTick", args: {} }] }],
|
|
184
|
+
labels: { Converge: "true" },
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
`,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect((await discoverConvergeOps({ cwd: dir })).ops.map((d) => d.config.name)).toEqual(["envless-converge"]);
|
|
191
|
+
expect((await discoverConvergeOps({ cwd: dir, env: "staging" })).ops).toEqual([]);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
135
194
|
});
|
|
136
195
|
|
|
137
196
|
describe("runOperatorRound — lease + tick execution over a fixture ConvergeOp (offline)", () => {
|
|
@@ -142,7 +201,7 @@ describe("runOperatorRound — lease + tick execution over a fixture ConvergeOp
|
|
|
142
201
|
const activities = fakeTickActivities(dir, "staging", "staging-converge");
|
|
143
202
|
|
|
144
203
|
const events = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES });
|
|
145
|
-
expect(events).toEqual([{ kind: "ticked", op: "staging-converge", env: "staging", result: expect.objectContaining({
|
|
204
|
+
expect(events).toEqual([{ kind: "ticked", op: "staging-converge", env: "staging", result: expect.objectContaining({ status: "ok" }) }]);
|
|
146
205
|
|
|
147
206
|
const { records } = await readConvergeLedger("staging", { cwd: dir });
|
|
148
207
|
expect(records).toHaveLength(1);
|
|
@@ -150,6 +209,27 @@ describe("runOperatorRound — lease + tick execution over a fixture ConvergeOp
|
|
|
150
209
|
});
|
|
151
210
|
});
|
|
152
211
|
|
|
212
|
+
test("the tick's own run lands on the run ledger, keyed by the op's labels.Env (#2118)", async () => {
|
|
213
|
+
await withTestDir(async (dir) => {
|
|
214
|
+
await initRepo(dir);
|
|
215
|
+
writeFixtureConvergeOp(dir, "staging-converge", "staging");
|
|
216
|
+
const activities = fakeTickActivities(dir, "staging", "staging-converge");
|
|
217
|
+
|
|
218
|
+
await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES });
|
|
219
|
+
|
|
220
|
+
const { records, malformed } = await readRunLedger("staging", "staging-converge", { cwd: dir });
|
|
221
|
+
expect(malformed).toBe(0);
|
|
222
|
+
expect(records).toHaveLength(1);
|
|
223
|
+
expect(records[0]).toMatchObject({
|
|
224
|
+
op: "staging-converge",
|
|
225
|
+
env: "staging",
|
|
226
|
+
status: "ok",
|
|
227
|
+
labels: { Converge: "true", Env: "staging", Dial: "observe" },
|
|
228
|
+
});
|
|
229
|
+
expect(records[0].phases.map((p) => p.name)).toEqual(["Converge"]);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
153
233
|
test("a second operator process (different holder) sees the lease held and skips — never queues", async () => {
|
|
154
234
|
await withTestDir(async (dir) => {
|
|
155
235
|
await initRepo(dir);
|
|
@@ -330,10 +410,97 @@ describe("runOperatorForever — interval/timer behavior", () => {
|
|
|
330
410
|
});
|
|
331
411
|
});
|
|
332
412
|
|
|
413
|
+
describe("runOperatorRound — an Op's own schedule is its tick cadence (#2120)", () => {
|
|
414
|
+
/** 2026-09-06T13:30 local — a minute `*/10 * * * *` fires on. */
|
|
415
|
+
const firing = () => new Date(2026, 8, 6, 13, 30, 0, 0);
|
|
416
|
+
/** …and 13:33, which it does not. */
|
|
417
|
+
const quiet = () => new Date(2026, 8, 6, 13, 33, 0, 0);
|
|
418
|
+
|
|
419
|
+
test("a round on a firing minute ticks the op", async () => {
|
|
420
|
+
await withTestDir(async (dir) => {
|
|
421
|
+
await initRepo(dir);
|
|
422
|
+
writeFixtureScheduledConvergeOp(dir, "staging-converge", "staging", "*/10 * * * *");
|
|
423
|
+
const activities = fakeTickActivities(dir, "staging", "staging-converge");
|
|
424
|
+
|
|
425
|
+
const events = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES, now: firing });
|
|
426
|
+
expect(events).toEqual([
|
|
427
|
+
{ kind: "ticked", op: "staging-converge", env: "staging", result: expect.objectContaining({ status: "ok" }) },
|
|
428
|
+
]);
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test("a round off the cron skips without touching the lease, and writes no ledger record", async () => {
|
|
433
|
+
await withTestDir(async (dir) => {
|
|
434
|
+
await initRepo(dir);
|
|
435
|
+
writeFixtureScheduledConvergeOp(dir, "staging-converge", "staging", "*/10 * * * *");
|
|
436
|
+
const activities = fakeTickActivities(dir, "staging", "staging-converge");
|
|
437
|
+
|
|
438
|
+
const events = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES, now: quiet });
|
|
439
|
+
expect(events).toEqual([
|
|
440
|
+
{ kind: "skipped-not-due", op: "staging-converge", env: "staging", cron: "*/10 * * * *" },
|
|
441
|
+
]);
|
|
442
|
+
|
|
443
|
+
const { records } = await readConvergeLedger("staging", { cwd: dir });
|
|
444
|
+
expect(records).toHaveLength(0);
|
|
445
|
+
expect((await readLease("staging-converge", { cwd: dir })).record).toBeUndefined();
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test("a late round still owes the tick: a firing minute passed since this op was last considered", async () => {
|
|
450
|
+
await withTestDir(async (dir) => {
|
|
451
|
+
await initRepo(dir);
|
|
452
|
+
writeFixtureScheduledConvergeOp(dir, "staging-converge", "staging", "*/10 * * * *");
|
|
453
|
+
const activities = fakeTickActivities(dir, "staging", "staging-converge");
|
|
454
|
+
const scheduleState = new Map<string, Date>();
|
|
455
|
+
|
|
456
|
+
// 13:33 — first sight, not a firing minute: recorded, not ticked.
|
|
457
|
+
const first = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES, now: quiet, scheduleState });
|
|
458
|
+
expect(first[0].kind).toBe("skipped-not-due");
|
|
459
|
+
|
|
460
|
+
// 13:42 — 13:40 fired while nobody was looking, so this round ticks.
|
|
461
|
+
const late = () => new Date(2026, 8, 6, 13, 42, 0, 0);
|
|
462
|
+
const second = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES, now: late, scheduleState });
|
|
463
|
+
expect(second[0].kind).toBe("ticked");
|
|
464
|
+
|
|
465
|
+
// 13:43 — nothing has fired since 13:42.
|
|
466
|
+
const after = () => new Date(2026, 8, 6, 13, 43, 0, 0);
|
|
467
|
+
const third = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES, now: after, scheduleState });
|
|
468
|
+
expect(third[0].kind).toBe("skipped-not-due");
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
test("an op with no cadence of its own still ticks every round — `--interval` is the fallback", async () => {
|
|
473
|
+
await withTestDir(async (dir) => {
|
|
474
|
+
await initRepo(dir);
|
|
475
|
+
writeFixtureConvergeOp(dir, "staging-converge", "staging");
|
|
476
|
+
const activities = fakeTickActivities(dir, "staging", "staging-converge");
|
|
477
|
+
|
|
478
|
+
const events = await runOperatorRound({ cwd: dir, holder: "op-a", activities, profiles: PROFILES, now: quiet });
|
|
479
|
+
expect(events[0].kind).toBe("ticked");
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
333
484
|
describe("formatRoundLine", () => {
|
|
334
485
|
test("renders each event kind as one line", () => {
|
|
335
|
-
expect(formatRoundLine({
|
|
336
|
-
|
|
486
|
+
expect(formatRoundLine({
|
|
487
|
+
kind: "ticked", op: "x", env: "staging",
|
|
488
|
+
result: {
|
|
489
|
+
op: "x", records: [], totalMs: 1, status: "ok", startedAt: "2026-09-05T12:00:00.000Z",
|
|
490
|
+
record: runRecord("x", "ok"),
|
|
491
|
+
},
|
|
492
|
+
})).toContain("ticked=1 status=ok");
|
|
493
|
+
expect(formatRoundLine({
|
|
494
|
+
kind: "ticked", op: "x", env: "staging",
|
|
495
|
+
result: {
|
|
496
|
+
op: "x", records: [], totalMs: 1, status: "gated", startedAt: "2026-09-05T12:00:00.000Z",
|
|
497
|
+
gate: {
|
|
498
|
+
version: 1, kind: "pending", op: "x", gate: "rollout-gate",
|
|
499
|
+
timestamp: "2026-09-05T12:00:00.000Z", expiresAt: "2026-09-07T12:00:00.000Z",
|
|
500
|
+
},
|
|
501
|
+
record: runRecord("x", "gated"),
|
|
502
|
+
},
|
|
503
|
+
})).toContain('status=gated gate="rollout-gate"');
|
|
337
504
|
expect(formatRoundLine({ kind: "skipped-lease-held", op: "x", env: "staging", heldBy: "holder-a" }))
|
|
338
505
|
.toContain("lease-held:holder-a");
|
|
339
506
|
expect(formatRoundLine({ kind: "tick-failed", op: "x", env: "staging", error: "boom" }))
|
|
@@ -342,5 +509,7 @@ describe("formatRoundLine", () => {
|
|
|
342
509
|
.toContain("fenced=1");
|
|
343
510
|
expect(formatRoundLine({ kind: "lease-error", op: "x", env: "staging", error: "stale lock at .../x.lock" }))
|
|
344
511
|
.toContain("stale lock at .../x.lock");
|
|
512
|
+
expect(formatRoundLine({ kind: "skipped-not-due", op: "x", env: "staging", cron: "*/10 * * * *" }))
|
|
513
|
+
.toContain("not-due:*/10 * * * *");
|
|
345
514
|
});
|
|
346
515
|
});
|
package/src/op/operator.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `chant operator` (#1485, epic #1487) —
|
|
3
|
-
*
|
|
2
|
+
* `chant operator` (#1485, epic #1487) — durable ticks with no service behind
|
|
3
|
+
* them. A deliberately small daemon: a timer, a lease
|
|
4
4
|
* (../lifecycle/lease.ts), and the existing local executor
|
|
5
5
|
* (./local-executor.ts) in a loop. No new service, no new state store — the
|
|
6
6
|
* lease lives on a git ref, tick state lives on the `chant/lifecycle`
|
|
7
7
|
* orphan branch via the same `convergeTick` activity `chant run <op>`
|
|
8
8
|
* already calls for a single one-shot tick.
|
|
9
9
|
*
|
|
10
|
-
* One round: discover every `ConvergeOp` (
|
|
10
|
+
* One round: discover every `ConvergeOp` (label `Converge:
|
|
11
11
|
* "true"`, optionally filtered to one env), and for each one, try to
|
|
12
12
|
* acquire (or renew) its lease. Win it — run one tick via `runOpLocally` on
|
|
13
13
|
* the Op's own Observe → Converge phases, the identical path `chant run
|
|
@@ -37,23 +37,32 @@
|
|
|
37
37
|
*/
|
|
38
38
|
import type { ActivityFn, ActivityProfile } from "./activity-registry";
|
|
39
39
|
import { discoverOps, type DiscoveredOp } from "./discover";
|
|
40
|
-
import { runOpLocally, OpRunFailure,
|
|
40
|
+
import { runOpLocally, OpRunFailure, type OpRunResult } from "./local-executor";
|
|
41
41
|
import { acquireLease, stillHoldsLease, currentHolderId, DEFAULT_LEASE_TTL_MS, type LeaseRecord, type AcquireLeaseResult } from "../lifecycle/lease";
|
|
42
42
|
import { StaleLockError } from "../lifecycle/git";
|
|
43
|
+
import { cronMatches, cronDueBetween } from "./cron";
|
|
43
44
|
|
|
44
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* Poll interval between rounds — the operator's own cadence, and the fallback
|
|
47
|
+
* for an Op that declares none. Since #2120 an Op can carry its own
|
|
48
|
+
* `schedule.cron` (`./composites/converge-op.ts`), which this loop honours per
|
|
49
|
+
* Op: the round still wakes every `intervalMs`, but an Op with a cron is
|
|
50
|
+
* ticked only on the minutes that cron fires. Chosen short enough to converge
|
|
51
|
+
* promptly, long enough not to hammer `chant lifecycle plan --live` every few
|
|
52
|
+
* seconds — and short enough that a per-minute cron is not missed.
|
|
53
|
+
*/
|
|
45
54
|
export const DEFAULT_OPERATOR_INTERVAL_MS = 60_000;
|
|
46
55
|
|
|
47
|
-
/** One ConvergeOp's own `
|
|
56
|
+
/** One ConvergeOp's own `labels.Env` (`./composites/converge-op.ts` always sets it). `undefined` for a non-ConvergeOp or a hand-built one missing it — filtered out by `isConvergeOp` before this is trusted. */
|
|
48
57
|
function envOf(config: DiscoveredOp["config"]): string | undefined {
|
|
49
|
-
return config.
|
|
58
|
+
return config.labels?.Env;
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
function isConvergeOp(config: DiscoveredOp["config"]): boolean {
|
|
53
|
-
return config.
|
|
62
|
+
return config.labels?.Converge === "true";
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
/** Discover every `ConvergeOp` in the project (`
|
|
65
|
+
/** Discover every `ConvergeOp` in the project (`labels.Converge === "true"`), optionally filtered to one environment. Ops that don't declare an `Env` label are excluded from an `--env`-filtered discovery (there's nothing to match), but included when no `env` filter is given. */
|
|
57
66
|
export async function discoverConvergeOps(
|
|
58
67
|
opts?: { cwd?: string; env?: string },
|
|
59
68
|
): Promise<{ ops: DiscoveredOp[]; errors: string[] }> {
|
|
@@ -67,6 +76,8 @@ export async function discoverConvergeOps(
|
|
|
67
76
|
export type OperatorTickEvent =
|
|
68
77
|
| { kind: "ticked"; op: string; env: string; result: OpRunResult }
|
|
69
78
|
| { kind: "skipped-lease-held"; op: string; env: string; heldBy?: string }
|
|
79
|
+
/** The Op declares its own `schedule.cron` (#2120) and this round did not land on a firing minute — the lease was never touched. An Op without a cron is never reported this way: it ticks every round, on `--interval`. */
|
|
80
|
+
| { kind: "skipped-not-due"; op: string; env: string; cron: string }
|
|
70
81
|
| { kind: "tick-failed"; op: string; env: string; error: string }
|
|
71
82
|
/** The lease was lost between acquiring it and the tick finishing (e.g. this process stalled past its TTL and another operator reclaimed it) — the tick's own ledger record (written inside `convergeTick`) still landed, since a converge tick is idempotent by design; this event exists purely so `chant operator`'s log and the ledger-independent test surface can see the fencing violation happened. Never a hard failure. */
|
|
72
83
|
| { kind: "fenced"; op: string; env: string }
|
|
@@ -96,6 +107,16 @@ export interface OperatorRoundOptions {
|
|
|
96
107
|
profiles: Record<string, ActivityProfile>;
|
|
97
108
|
now?: () => Date;
|
|
98
109
|
signal?: AbortSignal;
|
|
110
|
+
/**
|
|
111
|
+
* When each Op with its own `schedule.cron` was last considered (#2120) —
|
|
112
|
+
* the state a round needs to answer "has a firing minute passed since I
|
|
113
|
+
* last looked at this Op?". `runOperatorForever` owns one map across
|
|
114
|
+
* rounds; a bare `runOperatorRound` with none given falls back to "is this
|
|
115
|
+
* minute a firing minute", which is what a single round can know on its
|
|
116
|
+
* own. Every considered Op's entry is updated, ticked or not, so a late
|
|
117
|
+
* round makes up exactly one tick rather than a backlog.
|
|
118
|
+
*/
|
|
119
|
+
scheduleState?: Map<string, Date>;
|
|
99
120
|
}
|
|
100
121
|
|
|
101
122
|
/**
|
|
@@ -112,6 +133,24 @@ export async function runOperatorRound(opts: OperatorRoundOptions): Promise<Oper
|
|
|
112
133
|
for (const { config } of ops) {
|
|
113
134
|
const env = envOf(config) ?? "unknown";
|
|
114
135
|
|
|
136
|
+
// An Op that declares its own cadence (#2120) is ticked on that cron
|
|
137
|
+
// rather than on every round. Level-triggered: the question is whether a
|
|
138
|
+
// firing minute has passed since this Op was last looked at, so a round
|
|
139
|
+
// that arrives late still owes exactly one tick — a converge tick
|
|
140
|
+
// re-observes everything anyway, and several missed fires are one tick's
|
|
141
|
+
// worth of work.
|
|
142
|
+
const cron = config.schedule?.cron;
|
|
143
|
+
if (cron) {
|
|
144
|
+
const now = (opts.now ?? (() => new Date()))();
|
|
145
|
+
const lastSeen = opts.scheduleState?.get(config.name);
|
|
146
|
+
const due = lastSeen === undefined ? cronMatches(cron, now) : cronDueBetween(cron, lastSeen, now);
|
|
147
|
+
opts.scheduleState?.set(config.name, now);
|
|
148
|
+
if (!due) {
|
|
149
|
+
events.push({ kind: "skipped-not-due", op: config.name, env, cron });
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
115
154
|
let acquired: AcquireLeaseResult;
|
|
116
155
|
try {
|
|
117
156
|
acquired = await acquireLease(config.name, holder, {
|
|
@@ -137,18 +176,18 @@ export async function runOperatorRound(opts: OperatorRoundOptions): Promise<Oper
|
|
|
137
176
|
|
|
138
177
|
const lease = acquired.lease as LeaseRecord;
|
|
139
178
|
try {
|
|
140
|
-
const result = await runOpLocally(config, opts.activities, opts.profiles, opts.signal
|
|
179
|
+
const result = await runOpLocally(config, opts.activities, opts.profiles, opts.signal, {
|
|
180
|
+
ledger: { cwd: opts.cwd },
|
|
181
|
+
});
|
|
141
182
|
const held = await stillHoldsLease(config.name, holder, lease.token, { cwd: opts.cwd });
|
|
142
183
|
events.push(held ? { kind: "ticked", op: config.name, env, result } : { kind: "fenced", op: config.name, env });
|
|
143
184
|
} catch (err) {
|
|
144
185
|
const message =
|
|
145
186
|
err instanceof OpRunFailure
|
|
146
187
|
? `Op "${config.name}" failed — see its ledger record for step-level detail`
|
|
147
|
-
: err instanceof
|
|
188
|
+
: err instanceof Error
|
|
148
189
|
? err.message
|
|
149
|
-
: err
|
|
150
|
-
? err.message
|
|
151
|
-
: String(err);
|
|
190
|
+
: String(err);
|
|
152
191
|
events.push({ kind: "tick-failed", op: config.name, env, error: message });
|
|
153
192
|
}
|
|
154
193
|
}
|
|
@@ -188,8 +227,13 @@ export interface OperatorLoopOptions extends OperatorRoundOptions {
|
|
|
188
227
|
*/
|
|
189
228
|
export async function runOperatorForever(opts: OperatorLoopOptions): Promise<void> {
|
|
190
229
|
const holder = opts.holder ?? currentHolderId();
|
|
230
|
+
// Per-op cron state (#2120) lives for the life of the loop. A restart starts
|
|
231
|
+
// it empty, which means the first round ticks a scheduled Op only if it
|
|
232
|
+
// lands on a firing minute — a fresh operator owes no catch-up for the ticks
|
|
233
|
+
// it was not running for.
|
|
234
|
+
const scheduleState = opts.scheduleState ?? new Map<string, Date>();
|
|
191
235
|
while (!opts.signal?.aborted) {
|
|
192
|
-
const events = await runOperatorRound({ ...opts, holder });
|
|
236
|
+
const events = await runOperatorRound({ ...opts, holder, scheduleState });
|
|
193
237
|
opts.onRound?.(events);
|
|
194
238
|
if (opts.signal?.aborted) break;
|
|
195
239
|
await sleepAbortable(opts.intervalMs ?? DEFAULT_OPERATOR_INTERVAL_MS, opts.signal);
|
|
@@ -200,9 +244,12 @@ export async function runOperatorForever(opts: OperatorLoopOptions): Promise<voi
|
|
|
200
244
|
export function formatRoundLine(event: OperatorTickEvent): string {
|
|
201
245
|
switch (event.kind) {
|
|
202
246
|
case "ticked":
|
|
203
|
-
return `operator: ${event.op}@${event.env} ticked=1
|
|
247
|
+
return `operator: ${event.op}@${event.env} ticked=1 status=${event.result.status}` +
|
|
248
|
+
(event.result.gate ? ` gate="${event.result.gate.gate}"` : "");
|
|
204
249
|
case "skipped-lease-held":
|
|
205
250
|
return `operator: ${event.op}@${event.env} skipped=1(lease-held${event.heldBy ? `:${event.heldBy}` : ""})`;
|
|
251
|
+
case "skipped-not-due":
|
|
252
|
+
return `operator: ${event.op}@${event.env} skipped=1(not-due:${event.cron})`;
|
|
206
253
|
case "tick-failed":
|
|
207
254
|
return `operator: ${event.op}@${event.env} failed=1 error="${event.error}"`;
|
|
208
255
|
case "fenced":
|
package/src/op/receipt-store.ts
CHANGED
|
@@ -108,7 +108,7 @@ export interface ReceiptReadArgs extends ReceiptCheckInput {}
|
|
|
108
108
|
export interface ReceiptReadResult {
|
|
109
109
|
/** The receipt's live stored value, or null when absent. */
|
|
110
110
|
current: string | null;
|
|
111
|
-
/** The resolved expectation the
|
|
111
|
+
/** The resolved expectation the effect step compares and later writes. */
|
|
112
112
|
expectation: string;
|
|
113
113
|
/** Convenience: `current === expectation`. */
|
|
114
114
|
applied: boolean;
|
package/src/op/resource.ts
CHANGED
|
@@ -2,7 +2,25 @@ import { createResource } from "../runtime";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The Declarable resource backing an Op definition.
|
|
5
|
-
* entityType: "
|
|
5
|
+
* entityType: "Chant::Op", lexicon: "chant"
|
|
6
6
|
* Discovered automatically alongside infra files — no pipeline changes needed.
|
|
7
|
+
*
|
|
8
|
+
* An Op is chant's own verb, not a runtime's (#2118, epic #2114): the model,
|
|
9
|
+
* the executor and the ledger all live in core, and a lexicon that hosts runs
|
|
10
|
+
* is one runtime among several. The entity type says so.
|
|
7
11
|
*/
|
|
8
|
-
export const
|
|
12
|
+
export const OP_ENTITY_TYPE = "Chant::Op";
|
|
13
|
+
|
|
14
|
+
export const OpResource = createResource(OP_ENTITY_TYPE, "chant", {});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Is this entity an Op declaration?
|
|
18
|
+
*
|
|
19
|
+
* Duck-typed on `entityType` rather than `instanceof OpResource` for the same
|
|
20
|
+
* reason `../build.ts`'s dependency inference is: an entity can be built
|
|
21
|
+
* against a different copy of core (a linked lexicon, a child project) and
|
|
22
|
+
* still be the same declaration.
|
|
23
|
+
*/
|
|
24
|
+
export function isOpEntity(entity: unknown): boolean {
|
|
25
|
+
return (entity as { entityType?: string } | null)?.entityType === OP_ENTITY_TYPE;
|
|
26
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The op-runtime seam (#2121, epic #2114).
|
|
3
|
+
*
|
|
4
|
+
* An Op is a convergent verb; *where* it runs is a separate question from
|
|
5
|
+
* *what* it does. This module states that question once, as a provider
|
|
6
|
+
* contract, so `chant run` has one dispatch path instead of a branch per
|
|
7
|
+
* runtime. Core ships the `local` provider (./runtimes/local.ts) and never
|
|
8
|
+
* imports a hosting lexicon; a lexicon that hosts runs implements
|
|
9
|
+
* {@link OpRuntimeProvider} and hangs it off `LexiconPlugin.opRuntime`, where
|
|
10
|
+
* `chant run <op> --on <lexicon>` finds it.
|
|
11
|
+
*
|
|
12
|
+
* The record shapes below are the run ledger's (#2118): what a run wrote to
|
|
13
|
+
* `<env>/runs__<op>.jsonl` is what a provider's `status` and `log` read back,
|
|
14
|
+
* so a run's outcome survives the process that produced it. A provider with no
|
|
15
|
+
* ledger behind it (a hosting lexicon reporting a live run) fills the same
|
|
16
|
+
* shape from whatever it does know.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { OpConfig } from "./types";
|
|
20
|
+
import type { StepRecord, OpRunResult } from "./local-executor";
|
|
21
|
+
import type { GateResolutionRecord } from "../lifecycle/gate-ledger";
|
|
22
|
+
import type { RunComponentsOptions, RunComponentsResult } from "../components/cli-support";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* How a run ended, or that it has not. `gated` is the state a run reaches when
|
|
26
|
+
* a gate has no recorded resolution — a fact, not a wait (#2119).
|
|
27
|
+
*
|
|
28
|
+
* This is the coarse state a *runtime* reports. The ledger records the
|
|
29
|
+
* executor's own three-state outcome instead ({@link OpRunRecord.status}),
|
|
30
|
+
* which has no `running` or `cancelled`: a record is only written once a run
|
|
31
|
+
* has settled.
|
|
32
|
+
*/
|
|
33
|
+
export type OpRunState = "running" | "completed" | "failed" | "gated" | "cancelled";
|
|
34
|
+
|
|
35
|
+
/** Map a settled run's ledger status onto the coarser runtime state. */
|
|
36
|
+
export function runStateOf(status: OpRunRecord["status"]): OpRunState {
|
|
37
|
+
return status === "ok" ? "completed" : status === "gated" ? "gated" : "failed";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** One step's outcome as the run ledger keeps it — `StepRecord` minus the fields only a live renderer needs. */
|
|
41
|
+
export interface OpRunStepRecord {
|
|
42
|
+
/** The activity function name, or `gate:<signal>` for a gate step. */
|
|
43
|
+
fn: string;
|
|
44
|
+
status: StepRecord["status"];
|
|
45
|
+
durationMs: number;
|
|
46
|
+
/** The step's `outcomeAttribute` capture, when it declared one. */
|
|
47
|
+
outcome?: { name: string; value: unknown };
|
|
48
|
+
/** Who cleared this gate step and when (#2119), for a gate the run passed. */
|
|
49
|
+
approval?: { gate: string; resolvedBy: string; timestamp: string; url?: string };
|
|
50
|
+
/** The failure message, for `status: "fail"`. */
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** One phase's steps and the verdict they add up to. */
|
|
55
|
+
export interface OpRunPhaseRecord {
|
|
56
|
+
name: string;
|
|
57
|
+
/** `fail` if any step failed, `skipped` if every step was skipped, else `ok`. */
|
|
58
|
+
status: "ok" | "fail" | "skipped";
|
|
59
|
+
steps: OpRunStepRecord[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A run's current state, as every runtime reports it.
|
|
64
|
+
*
|
|
65
|
+
* `records` and `result` are populated by a runtime that has the executor's
|
|
66
|
+
* own step records to hand (the local one does, for a run it just executed in
|
|
67
|
+
* this process); a runtime answering from the ledger alone omits them rather
|
|
68
|
+
* than inventing them.
|
|
69
|
+
*/
|
|
70
|
+
export interface OpRunStatus {
|
|
71
|
+
op: string;
|
|
72
|
+
runId: string;
|
|
73
|
+
state: OpRunState;
|
|
74
|
+
/** ISO-8601 instant the run started. */
|
|
75
|
+
startedAt: string;
|
|
76
|
+
/** ISO-8601 instant the run settled; absent while it is still running. */
|
|
77
|
+
endedAt?: string;
|
|
78
|
+
/** Per-step records, when the runtime has them. */
|
|
79
|
+
records?: StepRecord[];
|
|
80
|
+
/** The executor's own result, when the runtime is executing in this process. */
|
|
81
|
+
result?: OpRunResult;
|
|
82
|
+
/** The gate this run is waiting on, when `state` is `gated`. */
|
|
83
|
+
gate?: { name: string; since: string };
|
|
84
|
+
/** Free-text detail for a failed run. */
|
|
85
|
+
error?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* One immutable, settled Op run — the run ledger's line
|
|
90
|
+
* (`../lifecycle/run-ledger.ts`), and what `chant run log <op>` prints a row
|
|
91
|
+
* per.
|
|
92
|
+
*
|
|
93
|
+
* This is where a run's outcome lives now that `OpConfig` no longer carries
|
|
94
|
+
* `searchAttributes` for the generated workflow to upsert (#2118). `labels` is
|
|
95
|
+
* copied off the declaration so a reader can filter runs the way it filters
|
|
96
|
+
* declarations; `outcomes` is every `outcomeAttribute` the run captured, later
|
|
97
|
+
* steps winning over earlier ones for a repeated name, exactly as an upsert
|
|
98
|
+
* would have.
|
|
99
|
+
*/
|
|
100
|
+
export interface OpRunRecord {
|
|
101
|
+
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
102
|
+
version: 1;
|
|
103
|
+
/** Stable run id — the same string a pending gate fact records for this run. */
|
|
104
|
+
id: string;
|
|
105
|
+
/** The Op's name (`OpConfig.name`). */
|
|
106
|
+
op: string;
|
|
107
|
+
/** The Op's `labels.Env`, or `local` when it declares none. */
|
|
108
|
+
env: string;
|
|
109
|
+
/** ISO-8601 instant the run started. */
|
|
110
|
+
started: string;
|
|
111
|
+
/** ISO-8601 instant the run settled. */
|
|
112
|
+
ended: string;
|
|
113
|
+
/**
|
|
114
|
+
* The executor's three-state outcome. `gated` is neither success nor
|
|
115
|
+
* failure: the run reached a gate nobody has approved, recorded the fact,
|
|
116
|
+
* and stopped (#2119).
|
|
117
|
+
*/
|
|
118
|
+
status: "ok" | "fail" | "gated";
|
|
119
|
+
/** The Op's own `labels`, copied at run time. */
|
|
120
|
+
labels: Record<string, string>;
|
|
121
|
+
/** Every `outcomeAttribute` the run captured, name → value. */
|
|
122
|
+
outcomes: Record<string, unknown>;
|
|
123
|
+
/** Per-phase, per-step status, in execution order. */
|
|
124
|
+
phases: OpRunPhaseRecord[];
|
|
125
|
+
/** The gate the run stopped on, for `status: "gated"`. */
|
|
126
|
+
gate?: { name: string; since: string };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** An {@link OpRunRecord} before the ledger stamps its version and mints an id. */
|
|
130
|
+
export type OpRunRecordInput = Omit<OpRunRecord, "version" | "id"> & { id?: string };
|
|
131
|
+
|
|
132
|
+
/** A started run. `result()` settles with the run's final status. */
|
|
133
|
+
export interface OpRunHandle {
|
|
134
|
+
op: string;
|
|
135
|
+
runId: string;
|
|
136
|
+
result(): Promise<OpRunStatus>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** What a caller hands a runtime when it starts a run. */
|
|
140
|
+
export interface OpRunStartOptions {
|
|
141
|
+
/** Build-time parameter bindings, when the caller resolved any. */
|
|
142
|
+
params?: Record<string, unknown>;
|
|
143
|
+
/** Target environment (`--env`). */
|
|
144
|
+
env?: string;
|
|
145
|
+
/**
|
|
146
|
+
* `-p, --profile <name>` (#2124, restored in #2192) — the named connection
|
|
147
|
+
* profile this runtime should target. Only a runtime that has profiles
|
|
148
|
+
* reads it; the local one ignores it, and a runtime that reads it decides
|
|
149
|
+
* for itself what an unknown name means (fountain refuses it rather than
|
|
150
|
+
* falling back to its default).
|
|
151
|
+
*/
|
|
152
|
+
profile?: string;
|
|
153
|
+
/** Called once per settled step, so `--progress-json` can stream. */
|
|
154
|
+
progress?: (record: StepRecord) => void;
|
|
155
|
+
/** Aborts in-flight work (Ctrl-C). */
|
|
156
|
+
signal?: AbortSignal;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The contract a runtime implements to host Op runs.
|
|
161
|
+
*
|
|
162
|
+
* `chant run` resolves exactly one provider per invocation — the named
|
|
163
|
+
* lexicon's for `--on <name>`, the built-in `local` one otherwise — and every
|
|
164
|
+
* subcommand calls it. A provider that cannot do something (cancel a
|
|
165
|
+
* foreground run, host components) says so by throwing a message the CLI
|
|
166
|
+
* prints verbatim, or by omitting the optional member.
|
|
167
|
+
*/
|
|
168
|
+
export interface OpRuntimeProvider {
|
|
169
|
+
/** How the CLI names this runtime in messages, and what `--on` matches. */
|
|
170
|
+
readonly name: string;
|
|
171
|
+
|
|
172
|
+
/** Start a run. Rejects with an actionable Error when it cannot. */
|
|
173
|
+
start(op: OpConfig, opts: OpRunStartOptions): Promise<OpRunHandle>;
|
|
174
|
+
|
|
175
|
+
/** The latest run's state, or `undefined` when this runtime has none recorded. */
|
|
176
|
+
status(op: string): Promise<OpRunStatus | undefined>;
|
|
177
|
+
|
|
178
|
+
/** Run history, newest first. Empty when nothing is recorded. */
|
|
179
|
+
log(op: string, opts?: { limit?: number }): Promise<OpRunRecord[]>;
|
|
180
|
+
|
|
181
|
+
/** Latest state for each of `ops`, keyed by op name. */
|
|
182
|
+
list(ops: OpConfig[]): Promise<Map<string, OpRunStatus | undefined>>;
|
|
183
|
+
|
|
184
|
+
/** Cancel the active run. `force` is the CLI's confirmation, already checked. */
|
|
185
|
+
cancel(op: string, opts: { force: boolean }): Promise<void>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Wake a run whose gate has just been resolved. The ledger write is the
|
|
189
|
+
* fact and `chant approve` owns it; this is the runtime's chance to act on
|
|
190
|
+
* it. Omit when a run re-reads the ledger on its own.
|
|
191
|
+
*/
|
|
192
|
+
resolveGate?(op: string, gate: string, resolution: GateResolutionRecord): Promise<void>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Host `chant run --components`. Optional: a runtime without it refuses the
|
|
196
|
+
* flag with one line naming itself.
|
|
197
|
+
*/
|
|
198
|
+
runComponents?(
|
|
199
|
+
projectPath: string,
|
|
200
|
+
selector: string,
|
|
201
|
+
options: RunComponentsOptions,
|
|
202
|
+
): Promise<RunComponentsResult>;
|
|
203
|
+
}
|