@intentius/chant 0.101.0 → 0.104.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/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/core.d.ts +2 -0
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/change-set.d.ts +232 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/cli/commands/audit.d.ts +7 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/change-set.d.ts +11 -0
- package/dist/cli/handlers/change-set.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts +33 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +16 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/pr.d.ts +31 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +4 -3
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +74 -3
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +16 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts +53 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/changed-files.d.ts +31 -0
- package/dist/components/changed-files.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +9 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +24 -0
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/driver.d.ts +13 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out-output.d.ts +6 -0
- package/dist/components/fan-out-output.d.ts.map +1 -1
- package/dist/components/fan-out-record.d.ts +41 -0
- package/dist/components/fan-out-record.d.ts.map +1 -0
- package/dist/components/fan-out-run.d.ts +65 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-support.d.ts +2 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts +6 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/gated-wave-pipeline.d.ts +50 -0
- package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layers.d.ts +25 -0
- package/dist/components/layers.d.ts.map +1 -0
- package/dist/components/pr-pipeline.d.ts +61 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -0
- package/dist/components/pr-run.d.ts +119 -0
- package/dist/components/pr-run.d.ts.map +1 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/shell.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/components/wave-plan.d.ts +49 -0
- package/dist/components/wave-plan.d.ts.map +1 -0
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +19 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +103 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +22 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +46 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +8 -8
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +137 -11
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/change-set.d.ts +62 -0
- package/dist/op/activities/change-set.d.ts.map +1 -0
- package/dist/op/activities/decide.d.ts +2 -0
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/factory.d.ts +137 -0
- package/dist/op/activities/factory.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +5 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts +11 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts +5 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts +4 -2
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +6 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +2 -0
- package/dist/op/op-ir.d.ts.map +1 -1
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +16 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/plan-summary.d.ts +207 -0
- package/dist/plan-summary.d.ts.map +1 -0
- package/dist/pr-forge.d.ts +105 -0
- package/dist/pr-forge.d.ts.map +1 -0
- package/dist/pr-loop.d.ts +178 -0
- package/dist/pr-loop.d.ts.map +1 -0
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.d.ts.map +1 -1
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/hcl2json.d.ts +45 -0
- package/dist/terraform/hcl2json.d.ts.map +1 -0
- package/dist/terraform/parse.d.ts +4 -40
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/box-cli.d.ts +12 -0
- package/dist/workspace/box-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +97 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/box-listing.d.ts +85 -0
- package/dist/workspace/box-listing.d.ts.map +1 -0
- package/dist/workspace/box-publish.d.ts +147 -0
- package/dist/workspace/box-publish.d.ts.map +1 -0
- package/dist/workspace/broker-protocol.d.ts +190 -0
- package/dist/workspace/broker-protocol.d.ts.map +1 -0
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks.d.ts +5 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +10 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/composites.d.ts +2 -2
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
- package/dist/workspace/conformance/broker.d.ts +202 -0
- package/dist/workspace/conformance/broker.d.ts.map +1 -0
- package/dist/workspace/conformance/index.d.ts +68 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +19 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +462 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +126 -12
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decision-points.schema.json +11 -4
- package/dist/workspace/declaration.d.ts +156 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +383 -5
- package/dist/workspace/environments.d.ts +36 -10
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/factory-rules.d.ts +180 -0
- package/dist/workspace/factory-rules.d.ts.map +1 -0
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.d.ts.map +1 -0
- package/dist/workspace/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +36 -2
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +249 -8
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/json-edit.d.ts +24 -0
- package/dist/workspace/json-edit.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +11 -0
- package/dist/workspace/jsonc.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +66 -4
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lexicon-symbols.d.ts +29 -0
- package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +2 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/point-answer.schema.json +42 -2
- package/dist/workspace/points-cli.d.ts +10 -3
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points.d.ts +66 -5
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +53 -4
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +5 -7
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +34 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +7 -3
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +68 -7
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +43 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +296 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +544 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.d.ts.map +1 -1
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/squash.d.ts +80 -0
- package/dist/workspace/squash.d.ts.map +1 -0
- package/dist/workspace/status-gates.d.ts +17 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +64 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +63 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts.map +1 -1
- package/dist/workspace/trust/run-commits.d.ts +46 -0
- package/dist/workspace/trust/run-commits.d.ts.map +1 -0
- package/dist/workspace/trust/run-statement.d.ts +128 -0
- package/dist/workspace/trust/run-statement.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +38 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify-cli.d.ts +1 -1
- package/dist/workspace/trust/verify.d.ts +16 -2
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/wip-cli.d.ts +21 -0
- package/dist/workspace/wip-cli.d.ts.map +1 -0
- package/dist/workspace/wip.d.ts +268 -0
- package/dist/workspace/wip.d.ts.map +1 -0
- package/dist/workspace/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-size.d.ts +55 -0
- package/dist/workspace/work-size.d.ts.map +1 -0
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-kinds.schema.json +122 -0
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-lock-cli.d.ts +60 -0
- package/dist/workspace/write-lock-cli.d.ts.map +1 -0
- package/dist/workspace/write-lock.d.ts +152 -0
- package/dist/workspace/write-lock.d.ts.map +1 -0
- package/dist/workspace/write-scope.d.ts +83 -19
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +7 -2
- package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
- package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
- package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
- package/src/__fixtures__/change-set/warden.plan.json +44 -0
- package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
- package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
- package/src/audit/core.test.ts +15 -0
- package/src/audit/core.ts +8 -2
- package/src/audit/discover.test.ts +11 -0
- package/src/audit/discover.ts +7 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/change-set-bundle.test.ts +57 -0
- package/src/change-set.test.ts +215 -0
- package/src/change-set.ts +445 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/audit-opt-in.test.ts +54 -0
- package/src/cli/commands/audit.ts +29 -2
- package/src/cli/commands/build.test.ts +19 -0
- package/src/cli/commands/build.ts +3 -2
- package/src/cli/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +18 -0
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +21 -3
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/build.ts +13 -1
- package/src/cli/handlers/change-set.test.ts +56 -0
- package/src/cli/handlers/change-set.ts +44 -0
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +221 -2
- package/src/cli/handlers/fan-out.ts +165 -75
- package/src/cli/handlers/graph.ts +3 -0
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +121 -6
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +86 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +21 -0
- package/src/cli/main.ts +246 -30
- package/src/cli/mcp/never-over-mcp.test.ts +101 -0
- package/src/cli/mcp/op-tools.ts +24 -2
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -7
- package/src/cli/registry.ts +74 -3
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/components/auto-release.ts +1 -1
- package/src/components/capability.ts +55 -0
- package/src/components/changed-files.ts +66 -0
- package/src/components/cli-support.ts +28 -5
- package/src/components/component.schema.json +17 -0
- package/src/components/component.ts +25 -0
- package/src/components/deploy-units.ts +3 -0
- package/src/components/driver.test.ts +52 -0
- package/src/components/driver.ts +31 -13
- package/src/components/fan-out-output.ts +42 -1
- package/src/components/fan-out-record.ts +69 -0
- package/src/components/fan-out-run.test.ts +17 -0
- package/src/components/fan-out-run.ts +304 -1
- package/src/components/fan-out-support.ts +3 -0
- package/src/components/fan-out-waves.test.ts +375 -0
- package/src/components/fan-out.ts +18 -17
- package/src/components/gated-wave-pipeline.ts +82 -0
- package/src/components/index.ts +1 -0
- package/src/components/layers.ts +30 -0
- package/src/components/pr-pipeline.ts +91 -0
- package/src/components/pr-run.test.ts +205 -0
- package/src/components/pr-run.ts +280 -0
- package/src/components/promote.ts +5 -0
- package/src/components/verbs/shell.test.ts +11 -0
- package/src/components/verbs/shell.ts +7 -3
- package/src/components/wave-plan.ts +124 -0
- package/src/config.test.ts +21 -0
- package/src/config.ts +15 -0
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/sandbox/bundle.ts +1 -1
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/gated-waves-bundle.test.ts +62 -0
- package/src/gated-waves.test.ts +118 -0
- package/src/gated-waves.ts +240 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/index.ts +1 -0
- package/src/lexicon.ts +106 -3
- package/src/lifecycle/gate-ledger.ts +23 -0
- package/src/lifecycle/git.ts +102 -16
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- package/src/lint/post-synth.test.ts +19 -0
- package/src/lint/post-synth.ts +19 -1
- package/src/meta/declared-imports.test.ts +1 -1
- package/src/op/activities/activity-contracts.ts +84 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/change-set.ts +114 -0
- package/src/op/activities/decide.ts +3 -0
- package/src/op/activities/factory.ts +675 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activity-contract.test.ts +21 -1
- package/src/op/activity-contract.ts +19 -9
- package/src/op/builders.ts +23 -0
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +11 -1
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/op-ir.test.ts +9 -0
- package/src/op/op-ir.ts +4 -0
- package/src/op/op-verb-class.ts +3 -0
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +16 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +76 -11
- package/src/plan-summary.test.ts +263 -0
- package/src/plan-summary.ts +845 -0
- package/src/pr-forge.test.ts +237 -0
- package/src/pr-forge.ts +332 -0
- package/src/pr-loop-bundle.test.ts +46 -0
- package/src/pr-loop.test.ts +171 -0
- package/src/pr-loop.ts +324 -0
- package/src/provenance.ts +35 -0
- package/src/telemetry-attribution.test.ts +23 -1
- package/src/telemetry-attribution.ts +51 -0
- package/src/terraform/hcl2json.test.ts +21 -0
- package/src/terraform/hcl2json.ts +81 -0
- package/src/terraform/parse.ts +11 -74
- package/src/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +323 -0
- package/src/workspace/box-factory.ts +136 -0
- package/src/workspace/box-listing-write.schema.json +204 -0
- package/src/workspace/box-listing.test.ts +234 -0
- package/src/workspace/box-listing.ts +324 -0
- package/src/workspace/box-publish.schema.json +498 -0
- package/src/workspace/box-publish.test.ts +204 -0
- package/src/workspace/box-publish.ts +420 -0
- package/src/workspace/box-ship.test.ts +96 -0
- package/src/workspace/broker-protocol.schema.json +186 -0
- package/src/workspace/broker-protocol.test.ts +122 -0
- package/src/workspace/broker-protocol.ts +317 -0
- package/src/workspace/builder-tiers.test.ts +146 -0
- package/src/workspace/change-set.schema.json +460 -0
- package/src/workspace/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +5 -0
- package/src/workspace/checks.ts +39 -8
- package/src/workspace/component-environments.test.ts +105 -0
- package/src/workspace/compose-graph.ts +7 -0
- package/src/workspace/composites.schema.json +23 -4
- package/src/workspace/composites.test.ts +8 -8
- package/src/workspace/composites.ts +13 -2
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
- package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/src/workspace/conformance/broker.test.ts +122 -0
- package/src/workspace/conformance/broker.ts +792 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
- package/src/workspace/conformance/index.mjs +51 -3
- package/src/workspace/conformance/index.ts +107 -15
- package/src/workspace/conformance/vitest.ts +76 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
- package/src/workspace/conformance/writer.test.ts +186 -0
- package/src/workspace/conformance/writer.ts +1191 -0
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +433 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +383 -5
- package/src/workspace/declaration.ts +315 -10
- package/src/workspace/environments.ts +66 -14
- package/src/workspace/factory-rules.test.ts +62 -0
- package/src/workspace/factory-rules.ts +218 -0
- package/src/workspace/graph-cli.ts +6 -3
- package/src/workspace/graph.schema.json +314 -0
- package/src/workspace/identity.test.ts +219 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +84 -13
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +336 -1
- package/src/workspace/intent-record.ts +96 -16
- package/src/workspace/intent-reviews.test.ts +76 -0
- package/src/workspace/intent-squash.test.ts +213 -0
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +950 -9
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +722 -65
- package/src/workspace/json-edit.test.ts +121 -0
- package/src/workspace/json-edit.ts +142 -0
- package/src/workspace/jsonc.ts +20 -0
- package/src/workspace/kinds.ts +201 -39
- package/src/workspace/lexicon-symbols.test.ts +148 -0
- package/src/workspace/lexicon-symbols.ts +125 -0
- package/src/workspace/lineage-upgrade.test.ts +63 -0
- package/src/workspace/lineage-upgrade.ts +146 -5
- package/src/workspace/plan-summary.schema.json +155 -0
- package/src/workspace/point-answer.schema.json +42 -2
- package/src/workspace/points-cli.ts +42 -16
- package/src/workspace/points-write.schema.json +163 -4
- package/src/workspace/points.schema.json +157 -2
- package/src/workspace/points.test.ts +13 -1
- package/src/workspace/points.ts +118 -12
- package/src/workspace/pr-report.schema.json +95 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +23 -3
- package/src/workspace/reason-codes.ts +61 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +80 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +123 -17
- package/src/workspace/records-close.schema.json +79 -0
- package/src/workspace/records-close.ts +31 -7
- package/src/workspace/records-concurrent.e2e.test.ts +135 -0
- package/src/workspace/records-concurrent.test.ts +145 -0
- package/src/workspace/records-formats.test.ts +46 -10
- package/src/workspace/records-new.schema.json +9 -0
- package/src/workspace/records-review.schema.json +80 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +219 -30
- package/src/workspace/records.schema.json +88 -1
- package/src/workspace/records.ts +76 -8
- package/src/workspace/reference-kinds/app/package.json +10 -0
- package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/src/workspace/run-statement.schema.json +622 -0
- package/src/workspace/runs-cli.ts +710 -0
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +994 -0
- package/src/workspace/runs.schema.json +1257 -0
- package/src/workspace/runs.test.ts +281 -0
- package/src/workspace/runs.ts +970 -0
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +10 -2
- package/src/workspace/status-gates.ts +25 -9
- package/src/workspace/status.schema.json +252 -4
- package/src/workspace/status.ts +110 -1
- package/src/workspace/symbols.ts +191 -0
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +58 -1
- package/src/workspace/trust/verify-cli.ts +6 -5
- package/src/workspace/trust/verify.ts +39 -6
- package/src/workspace/wip-cli.ts +97 -0
- package/src/workspace/wip-write.schema.json +504 -0
- package/src/workspace/wip.schema.json +334 -0
- package/src/workspace/wip.test.ts +294 -0
- package/src/workspace/wip.ts +753 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +136 -8
- package/src/workspace/work-evidence.schema.json +5 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-kinds.schema.json +122 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-lock-cli.ts +131 -0
- package/src/workspace/write-lock.schema.json +172 -0
- package/src/workspace/write-lock.test.ts +189 -0
- package/src/workspace/write-lock.ts +474 -0
- package/src/workspace/write-scope.test.ts +144 -3
- package/src/workspace/write-scope.ts +192 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* Cloud implementations are a later phase (see epic #551, issue #554).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import type { ReleaseIdentity } from "../telemetry-attribution";
|
|
16
|
+
import type { ChangeSetPart } from "../change-set";
|
|
17
|
+
|
|
15
18
|
/**
|
|
16
19
|
* Ambient information a capability's `run`/`rollback` receives, independent of
|
|
17
20
|
* its typed `input`. Deliberately minimal for this phase: the orchestrator
|
|
@@ -27,6 +30,42 @@ export interface DeployContext {
|
|
|
27
30
|
component: string;
|
|
28
31
|
/** Arbitrary environment config resolved by the orchestrator (registry URLs, cluster names, ...). */
|
|
29
32
|
vars?: Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* The release this run deploys (#3061, ws-081): the commit, set by the
|
|
35
|
+
* caller, and the digest of the artifact a publish step has promoted so
|
|
36
|
+
* far in this component's run, set by the driver. A deploy step passes it
|
|
37
|
+
* to the workload with `releaseEnvironment()`. Absent outside
|
|
38
|
+
* `chant run --components`.
|
|
39
|
+
*/
|
|
40
|
+
release?: ReleaseIdentity;
|
|
41
|
+
/**
|
|
42
|
+
* What this component's steps planned before its wave's gate was decided
|
|
43
|
+
* (#3049), keyed by {@link CapabilityPlan.member}. Set by a gated-wave
|
|
44
|
+
* fan-out and by a pull request's apply (#3183). A capability whose `run`
|
|
45
|
+
* finds its own member here applies that plan, the one the approver
|
|
46
|
+
* approved, instead of planning again.
|
|
47
|
+
*/
|
|
48
|
+
plans?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* What a capability's `plan` produced (#3049): the member it planned, that
|
|
53
|
+
* plan's digest, and whatever `run` needs to apply exactly that plan.
|
|
54
|
+
*/
|
|
55
|
+
export interface CapabilityPlan {
|
|
56
|
+
/** The member's name in a wave's set digest. For a terraform-family step, the root. */
|
|
57
|
+
member: string;
|
|
58
|
+
/** The digest a gate on this member alone would bind (#2300). */
|
|
59
|
+
planDigest: string;
|
|
60
|
+
/** Handed back to `run` as `DeployContext.plans[member]`. Opaque to the runner. */
|
|
61
|
+
artifact?: unknown;
|
|
62
|
+
/**
|
|
63
|
+
* The member's part of a change-set document (#3181): every change the
|
|
64
|
+
* plan proposes. A pull request's plan (#3183) composes the parts into the
|
|
65
|
+
* document whose grouped summary the PR note shows. Without it the member
|
|
66
|
+
* still counts toward the digest, with no entries.
|
|
67
|
+
*/
|
|
68
|
+
changeSet?: ChangeSetPart;
|
|
30
69
|
}
|
|
31
70
|
|
|
32
71
|
/**
|
|
@@ -61,6 +100,22 @@ export interface Capability<In = unknown, Out = unknown> {
|
|
|
61
100
|
* never needs it (most of them) simply ignores the third parameter.
|
|
62
101
|
*/
|
|
63
102
|
rollback?(ctx: DeployContext, input: In, output?: Out): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Optional: say what `run` would change, without changing it (#3049). A
|
|
105
|
+
* gated-wave fan-out calls this for every step of every component in a
|
|
106
|
+
* wave, once the waves before it have applied, and binds the wave's gate
|
|
107
|
+
* to the set digest of the results. `run` then receives the result's
|
|
108
|
+
* `artifact` through `DeployContext.plans`. A capability without `plan`
|
|
109
|
+
* is covered by its component's composition digest instead.
|
|
110
|
+
*/
|
|
111
|
+
plan?(ctx: DeployContext, input: In): Promise<CapabilityPlan>;
|
|
112
|
+
/**
|
|
113
|
+
* Optional: the outputs `run` exposed when it last ran, read without
|
|
114
|
+
* changing anything (#3183). A pull request's plan reads them for each
|
|
115
|
+
* component a planned one depends on, so a `stackOutput()` wiring resolves
|
|
116
|
+
* to the value standing now. The shape is `run`'s `outputs` field.
|
|
117
|
+
*/
|
|
118
|
+
outputs?(ctx: DeployContext, input: In): Promise<Record<string, unknown>>;
|
|
64
119
|
/**
|
|
65
120
|
* How this verb relates to rollback, for the COMP003 composition check.
|
|
66
121
|
* Usually derivable and left unset: a capability with a `rollback` method is
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files a change touched, and the units lexicons own that those files
|
|
3
|
+
* belong to (#3183).
|
|
4
|
+
*
|
|
5
|
+
* `lifecycle affected` judges chant source by diffing what it builds. A unit
|
|
6
|
+
* that is not chant source, such as a hand-written Terraform root, never
|
|
7
|
+
* shows in that diff, so a lexicon that owns such units answers from the
|
|
8
|
+
* changed paths instead (`LexiconPlugin.changedUnits`).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execFile } from "node:child_process";
|
|
12
|
+
import { promisify } from "node:util";
|
|
13
|
+
import type { LexiconPlugin } from "../lexicon";
|
|
14
|
+
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
16
|
+
|
|
17
|
+
async function git(cwd: string, args: string[]): Promise<string> {
|
|
18
|
+
const { stdout } = await execFileAsync("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
19
|
+
return stdout;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The commit a change is measured from: the merge base of `base` and `head`.
|
|
24
|
+
* A pull request's head that branched before `base` moved is measured from
|
|
25
|
+
* where it branched, so the other changes on `base` are not counted as its
|
|
26
|
+
* own; a merge commit's first parent is its own merge base.
|
|
27
|
+
*/
|
|
28
|
+
export async function resolveMergeBase(cwd: string, base: string, head = "HEAD"): Promise<string> {
|
|
29
|
+
try {
|
|
30
|
+
return (await git(cwd, ["merge-base", base, head])).trim();
|
|
31
|
+
} catch (err) {
|
|
32
|
+
const detail = (err as { stderr?: string }).stderr?.trim();
|
|
33
|
+
throw new Error(
|
|
34
|
+
`cannot find where ${head} and ${base} meet${detail ? `: ${detail}` : ""}. ` +
|
|
35
|
+
"Is the base fetched? A CI checkout needs the history (fetch-depth: 0, GIT_DEPTH: 0).",
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The full commit `ref` names. */
|
|
41
|
+
export async function resolveCommit(cwd: string, ref: string): Promise<string> {
|
|
42
|
+
return (await git(cwd, ["rev-parse", "--verify", `${ref}^{commit}`])).trim();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Files changed between `base` and `head`, relative to `cwd` and limited to
|
|
47
|
+
* it, with `/` separators. A rename counts as its old and its new path.
|
|
48
|
+
*/
|
|
49
|
+
export async function changedFilesBetween(cwd: string, base: string, head = "HEAD"): Promise<string[]> {
|
|
50
|
+
const out = await git(cwd, ["diff", "--name-only", "-z", "--no-renames", "--relative", base, head]);
|
|
51
|
+
return out.split("\0").filter(Boolean).sort();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The union of every plugin's `changedUnits` answer, sorted. */
|
|
55
|
+
export async function lexiconChangedUnits(
|
|
56
|
+
plugins: readonly Pick<LexiconPlugin, "changedUnits">[],
|
|
57
|
+
ctx: { projectRoot: string; config: Record<string, unknown>; changedFiles: string[] },
|
|
58
|
+
): Promise<string[]> {
|
|
59
|
+
if (ctx.changedFiles.length === 0) return [];
|
|
60
|
+
const units = new Set<string>();
|
|
61
|
+
for (const plugin of plugins) {
|
|
62
|
+
if (!plugin.changedUnits) continue;
|
|
63
|
+
for (const unit of await plugin.changedUnits(ctx)) units.add(unit);
|
|
64
|
+
}
|
|
65
|
+
return [...units].sort();
|
|
66
|
+
}
|
|
@@ -22,11 +22,13 @@
|
|
|
22
22
|
* executor, the CLI entrypoint the driver (#556) never had.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
+
import { UnknownCanaryError } from "../gated-waves";
|
|
25
26
|
import { lexiconModulePath, lexiconNames, importLexiconPackage } from "../lexicon-module";
|
|
26
27
|
import { discoverComponents } from "./discover";
|
|
27
28
|
import type { BuildParamProvenance } from "../provenance";
|
|
28
|
-
import { inferArchetype, projectToJson, type Archetype } from "./component";
|
|
29
|
+
import { inferArchetype, projectToJson, type Archetype, type ComponentEnvironmentDeclaration } from "./component";
|
|
29
30
|
import {
|
|
31
|
+
deployContext,
|
|
30
32
|
resolveComponentGraph,
|
|
31
33
|
runInterpretDriver,
|
|
32
34
|
runComponentDeploy,
|
|
@@ -43,7 +45,9 @@ import type { GateDigestMismatch, GateLedgerPort } from "../op/gate";
|
|
|
43
45
|
import { gateName } from "../op/gate-name";
|
|
44
46
|
import { isLexiconPlugin, type LexiconPlugin, type ComponentPipelineOptions } from "../lexicon";
|
|
45
47
|
import type { RunProgressEvent } from "./run-progress";
|
|
46
|
-
import { relative } from "node:path";
|
|
48
|
+
import { dirname, relative } from "node:path";
|
|
49
|
+
import { existsSync, statSync } from "node:fs";
|
|
50
|
+
import { getHeadCommit } from "../lifecycle/git";
|
|
47
51
|
import { buildCapabilityRegistry } from "./capability-plugin-loader";
|
|
48
52
|
import type { CapabilityRegistry } from "./capability";
|
|
49
53
|
import { applyConfigDefaults } from "./config-defaults";
|
|
@@ -156,6 +160,8 @@ export interface ComponentGraphResult {
|
|
|
156
160
|
* (`inferArchetype`), so a reader can label a component without its source
|
|
157
161
|
* (#2662). */
|
|
158
162
|
archetypes?: Record<string, Archetype>;
|
|
163
|
+
/** Component name → the environments it declares (#3153), present only for components that declared them. */
|
|
164
|
+
environments?: Record<string, ComponentEnvironmentDeclaration[]>;
|
|
159
165
|
error?: string;
|
|
160
166
|
}
|
|
161
167
|
|
|
@@ -192,7 +198,10 @@ export async function computeComponentGraph(
|
|
|
192
198
|
// that declared them — no identity fallback (see ComponentGraphResult doc).
|
|
193
199
|
const composites: Record<string, string[]> = {};
|
|
194
200
|
const archetypes: Record<string, Archetype> = {};
|
|
201
|
+
const environments: Record<string, ComponentEnvironmentDeclaration[]> = {};
|
|
195
202
|
for (const [name, discovered] of result.components) {
|
|
203
|
+
const declaredEnvironments = discovered.component.environments;
|
|
204
|
+
if (declaredEnvironments && declaredEnvironments.length > 0) environments[name] = declaredEnvironments.map((e) => ({ ...e }));
|
|
196
205
|
archetypes[name] = discovered.component.archetype ?? inferArchetype(discovered.component);
|
|
197
206
|
files[name] = relative(path, discovered.filePath);
|
|
198
207
|
const declared = discovered.component.liveNames;
|
|
@@ -207,7 +216,7 @@ export async function computeComponentGraph(
|
|
|
207
216
|
for (const c of driverComponents) {
|
|
208
217
|
for (const dep of c.dependsOn ?? []) edges.push({ from: c.name, to: dep });
|
|
209
218
|
}
|
|
210
|
-
return { success: true, order, waves, edges, files, liveNames, composites, archetypes };
|
|
219
|
+
return { success: true, order, waves, edges, files, liveNames, composites, archetypes, environments };
|
|
211
220
|
} catch (err) {
|
|
212
221
|
if (err instanceof UnknownDependencyError || err instanceof DependencyCycleError) {
|
|
213
222
|
return { success: false, order: [], waves: [], edges: [], error: err.message };
|
|
@@ -302,7 +311,7 @@ export async function generateComponentsPipeline(
|
|
|
302
311
|
const { yaml, stages, jobs, env } = plugin.generateComponentPipeline(driverComponents, options);
|
|
303
312
|
return { success: true, yaml, stages, jobs, ...(env ? { env } : {}), buildParams };
|
|
304
313
|
} catch (err) {
|
|
305
|
-
if (err instanceof UnknownDependencyError || err instanceof DependencyCycleError) {
|
|
314
|
+
if (err instanceof UnknownDependencyError || err instanceof DependencyCycleError || err instanceof UnknownCanaryError) {
|
|
306
315
|
return { success: false, error: err.message };
|
|
307
316
|
}
|
|
308
317
|
throw err;
|
|
@@ -421,6 +430,12 @@ export interface RunComponentsOptions {
|
|
|
421
430
|
buildParams?: BuildParamProvenance[];
|
|
422
431
|
/** Where a `gate` step's facts are read and written (#2119). Defaults to the `chant/lifecycle` orphan branch; a test passes `memoryGateLedgerPort()` from `../op/gate.ts`. */
|
|
423
432
|
gates?: GateLedgerPort;
|
|
433
|
+
/**
|
|
434
|
+
* The commit the run deploys, for the workloads' `vcs.ref.head.revision`
|
|
435
|
+
* (#3061). Default: `git rev-parse HEAD` in the project, or nothing outside
|
|
436
|
+
* a checkout. `null` passes none.
|
|
437
|
+
*/
|
|
438
|
+
revision?: string | null;
|
|
424
439
|
}
|
|
425
440
|
|
|
426
441
|
/** Result of `chant run --components <name|all>`. */
|
|
@@ -571,11 +586,19 @@ export async function runComponents(
|
|
|
571
586
|
const { onProgress } = options;
|
|
572
587
|
|
|
573
588
|
const gates = options.gates;
|
|
589
|
+
// #3061: the commit this run deploys, for the workloads' vcs.ref.head.revision. The digest comes
|
|
590
|
+
// from the run's own publish step. Best effort: outside a git checkout nothing is passed.
|
|
591
|
+
const revision =
|
|
592
|
+
options.revision !== undefined
|
|
593
|
+
? options.revision ?? undefined
|
|
594
|
+
: await getHeadCommit({ cwd: existsSync(path) && statSync(path).isDirectory() ? path : dirname(path) }).catch(() => undefined);
|
|
595
|
+
const releaseIdentity = () => (revision ? { revision } : {});
|
|
574
596
|
|
|
575
597
|
try {
|
|
576
598
|
if (selector === "all") {
|
|
577
599
|
const run = await runInterpretDriver(resolvedTargets, registry, {
|
|
578
600
|
env,
|
|
601
|
+
releaseIdentity,
|
|
579
602
|
componentOutputs: seedOutputs,
|
|
580
603
|
onProgress,
|
|
581
604
|
...(gates ? { gates } : {}),
|
|
@@ -618,7 +641,7 @@ export async function runComponents(
|
|
|
618
641
|
onProgress?.({ type: "component-start", wave: 1, component: componentName });
|
|
619
642
|
const componentResult = await runComponentDeploy(
|
|
620
643
|
resolvedTargets[0],
|
|
621
|
-
{ env,
|
|
644
|
+
deployContext({ env, releaseIdentity }, componentName),
|
|
622
645
|
registry,
|
|
623
646
|
componentOutputs,
|
|
624
647
|
onProgress,
|
|
@@ -60,6 +60,23 @@
|
|
|
60
60
|
"description": "Optional: the composite kind name(s) this component's deployed resources come from, when a consumer cannot infer it from `name` (#1492). Without this, a consumer joining a composite graph to the component DAG guesses by kebab-casing each composite's kind and matching it against this component's `name`, which only holds when a component maps 1:1 to a composite named for it. Omitted entirely (the default), the naming convention stays in effect with no behavior change. A component built from several composites may list them all.",
|
|
61
61
|
"items": { "type": "string", "minLength": 1 },
|
|
62
62
|
"minItems": 1
|
|
63
|
+
},
|
|
64
|
+
"environments": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"description": "Optional: where a release of this component goes, by environment (#3153). Each names an environment --env takes and, for it, the runtime that hosts the release, the URL it answers on, a custom domain attached to it, and the git remote its lifecycle records are pushed to. chant workspace graph --composites lists them first among the component's environments, with source component. Omitted, the component's environments are its member's.",
|
|
67
|
+
"minItems": 1,
|
|
68
|
+
"items": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["name"],
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"properties": {
|
|
73
|
+
"name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,62}$", "description": "The environment's name, as --env takes it." },
|
|
74
|
+
"runtime": { "type": "string", "minLength": 1, "description": "The runtime that hosts a release here, such as local or fly." },
|
|
75
|
+
"url": { "type": "string", "pattern": "^https?://", "description": "Where the released component answers." },
|
|
76
|
+
"domain": { "type": "string", "minLength": 1, "description": "A custom domain the release attaches to it." },
|
|
77
|
+
"lifecycle": { "type": "string", "minLength": 1, "description": "The git remote this environment's approvals, effect receipts and ledger records are pushed to." }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
63
80
|
}
|
|
64
81
|
},
|
|
65
82
|
"$defs": {
|
|
@@ -183,6 +183,31 @@ export interface Component {
|
|
|
183
183
|
* default and nothing changes.
|
|
184
184
|
*/
|
|
185
185
|
composites?: string[];
|
|
186
|
+
/**
|
|
187
|
+
* Optional: where a release of this component goes, by environment
|
|
188
|
+
* (#3153, ws-095). Each names an environment `--env` takes and, for that
|
|
189
|
+
* environment, the runtime that hosts the release, the URL its health
|
|
190
|
+
* answers on, a custom domain attached to it, and the git remote its
|
|
191
|
+
* approvals, effect receipts and ledger records are pushed to. `chant
|
|
192
|
+
* workspace graph --composites` lists them first among the component's
|
|
193
|
+
* environments, with source `component`. Omitted, the component's
|
|
194
|
+
* environments are its member's, as before.
|
|
195
|
+
*/
|
|
196
|
+
environments?: ComponentEnvironmentDeclaration[];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** One environment a component declares it deploys to (#3153). */
|
|
200
|
+
export interface ComponentEnvironmentDeclaration {
|
|
201
|
+
/** The environment's name, as `--env` takes it. */
|
|
202
|
+
name: string;
|
|
203
|
+
/** The runtime that hosts a release here, such as `local` or a lexicon's runtime (`fly`). */
|
|
204
|
+
runtime?: string;
|
|
205
|
+
/** Where the released component answers, such as its health endpoint's origin. */
|
|
206
|
+
url?: string;
|
|
207
|
+
/** A custom domain the release attaches to it. */
|
|
208
|
+
domain?: string;
|
|
209
|
+
/** The git remote this environment's approvals, effect receipts and ledger records are pushed to. */
|
|
210
|
+
lifecycle?: string;
|
|
186
211
|
}
|
|
187
212
|
|
|
188
213
|
/** Author a named phase. `steps` may mix capability `Step`s, `Gate`s, and nested `Phase`s (fan-out). */
|
|
@@ -56,6 +56,9 @@ export const DEPLOY_UNIT_RULES: readonly DeployUnitRule[] = [
|
|
|
56
56
|
{ kind: "argo-app", field: "stack", lexicon: "k8s" },
|
|
57
57
|
{ kind: "flux-reconcile", field: "stack", lexicon: "k8s" },
|
|
58
58
|
{ kind: "helm-upgrade", field: "release", lexicon: "helm" },
|
|
59
|
+
// A Terraform-family root (#3049). Its unit is the root's name in
|
|
60
|
+
// `terraform.roots`, which is also the member a gated wave's digest names.
|
|
61
|
+
{ kind: "terraform-apply", field: "root", lexicon: "terraform" },
|
|
59
62
|
];
|
|
60
63
|
|
|
61
64
|
/** One resolved unit a component's deploy composition targets. */
|
|
@@ -1069,3 +1069,55 @@ describe("capabilities are consumed exactly as the registry provides them", () =
|
|
|
1069
1069
|
expect(failed?.error).toMatch(/capability "some-future-verb" is not implemented/);
|
|
1070
1070
|
});
|
|
1071
1071
|
});
|
|
1072
|
+
|
|
1073
|
+
describe("the release a deploy step sees (#3061, ws-081)", () => {
|
|
1074
|
+
function setup() {
|
|
1075
|
+
const registry = new CapabilityRegistry();
|
|
1076
|
+
registry.register(fakeCapability("publish-image", { run: () => ({ uri: "ghcr.io/acme/api@sha256:abc", digest: "sha256:abc" }) }).capability);
|
|
1077
|
+
registry.register(fakeCapability("generate-sbom", { run: () => ({ digest: "sha256:sbom" }) }).capability);
|
|
1078
|
+
const deploy = fakeCapability("deploy");
|
|
1079
|
+
registry.register(deploy.capability);
|
|
1080
|
+
return { registry, deploy };
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
it("carries the caller's revision and the digest a publish step promoted, not an SBOM's", async () => {
|
|
1084
|
+
const { registry, deploy } = setup();
|
|
1085
|
+
const api: DriverComponent = {
|
|
1086
|
+
name: "api",
|
|
1087
|
+
dependsOn: [],
|
|
1088
|
+
deploy: [
|
|
1089
|
+
{ phase: "Publish", steps: [{ kind: "publish-image" }, { kind: "generate-sbom" }] },
|
|
1090
|
+
{ phase: "Deploy", steps: [{ kind: "deploy" }] },
|
|
1091
|
+
],
|
|
1092
|
+
};
|
|
1093
|
+
const result = await runInterpretDriver([api], registry, { env: "prod", releaseIdentity: () => ({ revision: "0123abc" }) });
|
|
1094
|
+
expect(result.ok).toBe(true);
|
|
1095
|
+
expect(deploy.calls[0]!.ctx.release).toEqual({ revision: "0123abc", version: "sha256:abc" });
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
it("keeps each component's release its own, and passes none without releaseIdentity", async () => {
|
|
1099
|
+
const { registry, deploy } = setup();
|
|
1100
|
+
const api: DriverComponent = { name: "api", dependsOn: [], deploy: [{ phase: "P", steps: [{ kind: "publish-image" }, { kind: "deploy" }] }] };
|
|
1101
|
+
const worker: DriverComponent = { name: "worker", dependsOn: ["api"], deploy: [{ phase: "D", steps: [{ kind: "deploy" }] }] };
|
|
1102
|
+
await runInterpretDriver([api, worker], registry, { env: "prod", releaseIdentity: () => ({ revision: "r1" }) });
|
|
1103
|
+
expect(deploy.calls.map((c) => [c.ctx.component, c.ctx.release])).toEqual([
|
|
1104
|
+
["api", { revision: "r1", version: "sha256:abc" }],
|
|
1105
|
+
["worker", { revision: "r1" }],
|
|
1106
|
+
]);
|
|
1107
|
+
const plain = setup();
|
|
1108
|
+
await runInterpretDriver([{ ...worker, dependsOn: [] }], plain.registry, { env: "prod" });
|
|
1109
|
+
expect(plain.deploy.calls[0]!.ctx.release).toBeUndefined();
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
it("a promote's recorded digest is the version when no step publishes one", async () => {
|
|
1113
|
+
const { registry, deploy } = setup();
|
|
1114
|
+
const api: DriverComponent = { name: "api", dependsOn: [], deploy: [{ phase: "D", steps: [{ kind: "deploy" }] }] };
|
|
1115
|
+
await runInterpretDriver([api], registry, {
|
|
1116
|
+
env: "prod",
|
|
1117
|
+
gates: memoryGateLedgerPort(),
|
|
1118
|
+
releases: new Map([["api", "sha256:recorded"]]),
|
|
1119
|
+
releaseIdentity: () => ({ revision: "r0" }),
|
|
1120
|
+
});
|
|
1121
|
+
expect(deploy.calls[0]!.ctx.release).toEqual({ revision: "r0", version: "sha256:recorded" });
|
|
1122
|
+
});
|
|
1123
|
+
});
|
package/src/components/driver.ts
CHANGED
|
@@ -47,11 +47,14 @@
|
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
49
|
import { topoSort } from "../codegen/topo-sort";
|
|
50
|
+
import { kahnLayers } from "./layers";
|
|
50
51
|
import { evaluateGate, gitGateLedgerPort, type GateDigestMismatch, type GateLedgerPort } from "../op/gate";
|
|
51
52
|
import { gateName } from "../op/gate-name";
|
|
52
53
|
import { componentPlanDigest } from "./gate-plan";
|
|
53
54
|
import type { PendingGateRecord } from "../lifecycle/gate-ledger";
|
|
54
55
|
import type { CapabilityRegistry, DeployContext } from "./capability";
|
|
56
|
+
import { isPromotedArtifact } from "./auto-release";
|
|
57
|
+
import type { ReleaseIdentity } from "../telemetry-attribution";
|
|
55
58
|
import type { RunProgressEvent, RunProgressStatus } from "./run-progress";
|
|
56
59
|
|
|
57
60
|
export type { RunProgressEvent } from "./run-progress";
|
|
@@ -237,18 +240,9 @@ export function resolveComponentGraph(components: DriverComponent[]): ComponentG
|
|
|
237
240
|
const deps = new Map<string, Set<string>>();
|
|
238
241
|
for (const c of components) deps.set(c.name, new Set(c.dependsOn ?? []));
|
|
239
242
|
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const wave = [...remaining]
|
|
244
|
-
.filter((n) => [...deps.get(n)!].every((d) => !remaining.has(d)))
|
|
245
|
-
.sort();
|
|
246
|
-
if (wave.length === 0) {
|
|
247
|
-
throw new DependencyCycleError([...remaining].sort());
|
|
248
|
-
}
|
|
249
|
-
for (const n of wave) remaining.delete(n);
|
|
250
|
-
waves.push(wave);
|
|
251
|
-
}
|
|
243
|
+
const layered = kahnLayers(deps);
|
|
244
|
+
if (layered.cycle) throw new DependencyCycleError(layered.cycle);
|
|
245
|
+
const waves = layered.waves;
|
|
252
246
|
|
|
253
247
|
const order = topoSort(
|
|
254
248
|
components,
|
|
@@ -566,6 +560,11 @@ async function runPhase(
|
|
|
566
560
|
});
|
|
567
561
|
if (record.status === "ok") {
|
|
568
562
|
phaseOutputs[phaseDef.phase] = { ...(phaseOutputs[phaseDef.phase] ?? {}), ...(output as object) };
|
|
563
|
+
// The release's service.version is the digest a later deploy step stamps (#3061): the
|
|
564
|
+
// last artifact this component promoted, the same one auto-release records.
|
|
565
|
+
if (ctx.release && isPromotedArtifact(output) && typeof output.digest === "string" && output.digest !== "") {
|
|
566
|
+
ctx.release.version = output.digest;
|
|
567
|
+
}
|
|
569
568
|
}
|
|
570
569
|
return {
|
|
571
570
|
records: [record],
|
|
@@ -715,11 +714,15 @@ export async function runComponentDeploy(
|
|
|
715
714
|
onProgress?: (event: RunProgressEvent) => void,
|
|
716
715
|
gateContext: GateContext = { port: gitGateLedgerPort() },
|
|
717
716
|
): Promise<DriverComponentResult> {
|
|
717
|
+
// Each component tracks its own release: a digest one component promoted never stamps another's deploy.
|
|
718
|
+
if (ctx.release) ctx = { ...ctx, release: { ...ctx.release } };
|
|
718
719
|
const phaseOutputs: Record<string, Record<string, unknown>> = {};
|
|
719
720
|
// #2574: every gate this component reaches binds its approval to this
|
|
720
721
|
// environment and this composition, so an approval for staging or for last
|
|
721
722
|
// week's deploy cannot pass it.
|
|
722
723
|
const release = gateContext.releases?.get(component.name);
|
|
724
|
+
// A promote or rollback deploys a recorded digest without publishing one (#2574); that digest is the release's version.
|
|
725
|
+
if (ctx.release && release !== undefined && ctx.release.version === undefined) ctx.release.version = release;
|
|
723
726
|
const gates: GateContext = {
|
|
724
727
|
...gateContext,
|
|
725
728
|
planDigest: componentPlanDigest({
|
|
@@ -909,6 +912,12 @@ export interface InterpretRunOptions {
|
|
|
909
912
|
now?: string;
|
|
910
913
|
/** The recorded digest a promote or rollback deploys, per component (#2574). Part of the plan a gate approval is bound to. */
|
|
911
914
|
releases?: ReadonlyMap<string, string>;
|
|
915
|
+
/**
|
|
916
|
+
* The release each component deploys (#3061, ws-081), threaded into its
|
|
917
|
+
* `DeployContext.release`. The driver fills in `version` when a publish
|
|
918
|
+
* step promotes an artifact. Absent: no deploy step sees a release.
|
|
919
|
+
*/
|
|
920
|
+
releaseIdentity?: (component: string) => ReleaseIdentity | undefined;
|
|
912
921
|
}
|
|
913
922
|
|
|
914
923
|
/**
|
|
@@ -930,6 +939,15 @@ export interface InterpretRunOptions {
|
|
|
930
939
|
* purely on the generic `Component`/`Phase`/`Step` shapes and the registry —
|
|
931
940
|
* no branch anywhere names a specific component or capability.
|
|
932
941
|
*/
|
|
942
|
+
/** A component's `DeployContext` for a run: its env, vars and, when the caller knows it, its release. */
|
|
943
|
+
export function deployContext(
|
|
944
|
+
options: { env: string; vars?: Record<string, unknown>; releaseIdentity?: (component: string) => ReleaseIdentity | undefined },
|
|
945
|
+
component: string,
|
|
946
|
+
): DeployContext {
|
|
947
|
+
const release = options.releaseIdentity?.(component);
|
|
948
|
+
return { env: options.env, component, ...(options.vars ? { vars: options.vars } : {}), ...(release ? { release: { ...release } } : {}) };
|
|
949
|
+
}
|
|
950
|
+
|
|
933
951
|
export async function runInterpretDriver(
|
|
934
952
|
components: DriverComponent[],
|
|
935
953
|
registry: CapabilityRegistry,
|
|
@@ -960,7 +978,7 @@ export async function runInterpretDriver(
|
|
|
960
978
|
onProgress?.({ type: "component-start", wave: waveNum, component: component.name });
|
|
961
979
|
const result = await runComponentDeploy(
|
|
962
980
|
component,
|
|
963
|
-
|
|
981
|
+
deployContext(options, component.name),
|
|
964
982
|
registry,
|
|
965
983
|
componentOutputs,
|
|
966
984
|
onProgress,
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
import type { FanOutPlan, FanOutSkip } from "./fan-out";
|
|
33
33
|
import type { FanOutRunResult } from "./fan-out-run";
|
|
34
|
+
import { waveGateName, type WaveRecord } from "../gated-waves";
|
|
34
35
|
|
|
35
36
|
type Writer = (line: string) => void;
|
|
36
37
|
|
|
@@ -47,6 +48,12 @@ export interface FanOutRenderOptions {
|
|
|
47
48
|
write?: Writer;
|
|
48
49
|
/** Present when a gate covers the set, so the render can print the exact approve line. */
|
|
49
50
|
gate?: FanOutGateRef;
|
|
51
|
+
/**
|
|
52
|
+
* Present when each wave has its own gate (#3049). A wave's digest is known
|
|
53
|
+
* only once it is planned, so a plan-only render names each wave's gate and
|
|
54
|
+
* no digest.
|
|
55
|
+
*/
|
|
56
|
+
waveGate?: FanOutGateRef;
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
/** `unaffected` → `unaffected`; `blocked` also names the failure it was reached from. */
|
|
@@ -85,7 +92,8 @@ export function renderFanOutPlan(plan: FanOutPlan, options: FanOutRenderOptions
|
|
|
85
92
|
write(" nothing to run");
|
|
86
93
|
} else {
|
|
87
94
|
for (const [index, wave] of plan.waves.entries()) {
|
|
88
|
-
|
|
95
|
+
const gated = options.waveGate ? ` (gate ${waveGateName(options.waveGate.gate, index + 1)})` : "";
|
|
96
|
+
write(` wave ${index + 1}: ${wave.join(", ")}${gated}`);
|
|
89
97
|
}
|
|
90
98
|
}
|
|
91
99
|
|
|
@@ -117,6 +125,28 @@ export function renderFanOutPlan(plan: FanOutPlan, options: FanOutRenderOptions
|
|
|
117
125
|
if (options.gate) {
|
|
118
126
|
write(` approve: chant approve ${options.gate.op} ${options.gate.gate} --plan ${plan.digest}`);
|
|
119
127
|
}
|
|
128
|
+
if (options.waveGate) {
|
|
129
|
+
write(` each wave is planned when it is reached, and its gate binds that wave's set digest`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** One line per wave a gated-wave run reached (#3049): its digest, members and where it got to. */
|
|
134
|
+
function renderWaves(waves: readonly WaveRecord[], write: Writer): void {
|
|
135
|
+
for (const wave of waves) {
|
|
136
|
+
const state =
|
|
137
|
+
wave.status === "applied"
|
|
138
|
+
? `applied, approved by ${wave.approvedBy ?? "unknown"}`
|
|
139
|
+
: wave.status === "gated"
|
|
140
|
+
? wave.approved
|
|
141
|
+
? "stopped: the set changed after it was approved"
|
|
142
|
+
: "waiting for approval"
|
|
143
|
+
: "failed";
|
|
144
|
+
write(`wave ${wave.wave} (${wave.gate}): ${state}`);
|
|
145
|
+
if (wave.digest) write(` set digest: ${wave.digest}`);
|
|
146
|
+
for (const member of wave.members) write(` ${member.member} ${member.planDigest}`);
|
|
147
|
+
if (wave.approved) write(` approved digest: ${wave.approved}`);
|
|
148
|
+
for (const f of wave.failed ?? []) write(` ${f.component} failed${f.error ? `: ${f.error}` : ""}`);
|
|
149
|
+
}
|
|
120
150
|
}
|
|
121
151
|
|
|
122
152
|
/**
|
|
@@ -130,6 +160,17 @@ export function renderFanOutPlan(plan: FanOutPlan, options: FanOutRenderOptions
|
|
|
130
160
|
export function renderFanOutHuman(result: FanOutRunResult, options: FanOutRenderOptions = {}): void {
|
|
131
161
|
const write = options.write ?? stderr;
|
|
132
162
|
renderFanOutPlan(result.plan, { ...options, write });
|
|
163
|
+
if (result.waves) renderWaves(result.waves, write);
|
|
164
|
+
|
|
165
|
+
if (result.status === "gated" && result.waves) {
|
|
166
|
+
const at = result.waves[result.waves.length - 1];
|
|
167
|
+
write(
|
|
168
|
+
`gated at wave ${at?.wave ?? "?"}: ${result.completed.length} applied before it, ` +
|
|
169
|
+
`nothing in it or after it ran.`,
|
|
170
|
+
);
|
|
171
|
+
if (result.gate?.expiresAt) write(` expires: ${result.gate.expiresAt}`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
133
174
|
|
|
134
175
|
if (result.status === "gated") {
|
|
135
176
|
const gate = result.gate;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fan-out attempt record (`--resume`, #2420, #2417, #3049): what an
|
|
3
|
+
* attempt left behind and what the next one reads.
|
|
4
|
+
*
|
|
5
|
+
* It lives here rather than in the CLI handler so a caller that runs a wave
|
|
6
|
+
* per CI job (#3183) reads and writes the same file without importing the
|
|
7
|
+
* command.
|
|
8
|
+
*
|
|
9
|
+
* The digest is stored alongside the progress because progress is only
|
|
10
|
+
* meaningful for the plan it was made against. A fan-out derived from different
|
|
11
|
+
* source is a different fan-out, and carrying "cluster-a already applied" into
|
|
12
|
+
* it would be a claim about work nobody did.
|
|
13
|
+
*
|
|
14
|
+
* `outputs` holds what each completed component exposed. A component left to
|
|
15
|
+
* run may read one of them through `stackOutput()`, and without the record the
|
|
16
|
+
* re-run would resolve that reference to nothing unless somebody supplied the
|
|
17
|
+
* value by hand with `--seed-outputs`.
|
|
18
|
+
*
|
|
19
|
+
* `waves`, for a gated-wave fan-out, holds one entry per wave reached: its set
|
|
20
|
+
* digest, its members, its gate and where it got to. A resumed attempt plans
|
|
21
|
+
* a wave afresh rather than trusting this, since the point of the gate is the
|
|
22
|
+
* plan now. The entries are for whoever reads the record, the plan report
|
|
23
|
+
* (#3349) among them.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { dirname } from "node:path";
|
|
27
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
28
|
+
import { readWaveRecords, type WaveRecord } from "../gated-waves";
|
|
29
|
+
|
|
30
|
+
export interface FanOutAttempt {
|
|
31
|
+
digest: string;
|
|
32
|
+
completed: string[];
|
|
33
|
+
failed: string[];
|
|
34
|
+
outputs: Record<string, Record<string, unknown>>;
|
|
35
|
+
/** Gated-wave fan-outs only (#3049). */
|
|
36
|
+
waves?: WaveRecord[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
40
|
+
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
|
+
|
|
42
|
+
/** Read an attempt record, or `undefined` when there is none yet. Throws on a file that is not JSON. */
|
|
43
|
+
export function readFanOutAttempt(path: string): FanOutAttempt | undefined {
|
|
44
|
+
if (!existsSync(path)) return undefined;
|
|
45
|
+
const parsed = JSON.parse(readFileSync(path, "utf8")) as Partial<FanOutAttempt>;
|
|
46
|
+
const outputs: Record<string, Record<string, unknown>> = {};
|
|
47
|
+
if (isRecord(parsed.outputs)) {
|
|
48
|
+
for (const [name, value] of Object.entries(parsed.outputs)) if (isRecord(value)) outputs[name] = value;
|
|
49
|
+
}
|
|
50
|
+
const waves = readWaveRecords(parsed.waves);
|
|
51
|
+
return {
|
|
52
|
+
digest: typeof parsed.digest === "string" ? parsed.digest : "",
|
|
53
|
+
completed: Array.isArray(parsed.completed) ? parsed.completed.filter((n): n is string => typeof n === "string") : [],
|
|
54
|
+
failed: Array.isArray(parsed.failed) ? parsed.failed.filter((n): n is string => typeof n === "string") : [],
|
|
55
|
+
outputs,
|
|
56
|
+
...(waves.length > 0 ? { waves } : {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Written through a temporary file and a rename, so a process killed during the
|
|
62
|
+
* write leaves the previous record whole rather than half a JSON document.
|
|
63
|
+
*/
|
|
64
|
+
export function writeFanOutAttempt(path: string, attempt: FanOutAttempt): void {
|
|
65
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
66
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
67
|
+
writeFileSync(temporary, JSON.stringify(attempt, null, 2) + "\n");
|
|
68
|
+
renameSync(temporary, path);
|
|
69
|
+
}
|
|
@@ -116,6 +116,23 @@ describe("resuming", () => {
|
|
|
116
116
|
expect(ran.sort()).toEqual(["app-one", "app-two", "cluster-a"]);
|
|
117
117
|
expect(second.plan.skipped).toContainEqual({ component: "net", reason: "already-applied" });
|
|
118
118
|
});
|
|
119
|
+
|
|
120
|
+
test("each component is reported as it settles, so progress survives a run that never returns", async () => {
|
|
121
|
+
const plan = planFanOut({ components: ESTATE, changed: ["net"] });
|
|
122
|
+
const settled: string[] = [];
|
|
123
|
+
const { registry, ran } = registryWith(["cluster-a"]);
|
|
124
|
+
const result = await runFanOut(plan, ESTATE, registry, {
|
|
125
|
+
...opts(),
|
|
126
|
+
onComponentSettled: (r) => {
|
|
127
|
+
settled.push(`${r.component}:${r.status}`);
|
|
128
|
+
// Every report lands before any later wave starts.
|
|
129
|
+
if (r.component === "net") expect(ran).toEqual(["net"]);
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
expect(result.status).toBe("fail");
|
|
134
|
+
expect(settled.sort()).toEqual(["app-three:ok", "cluster-a:fail", "cluster-b:ok", "net:ok"]);
|
|
135
|
+
});
|
|
119
136
|
});
|
|
120
137
|
|
|
121
138
|
describe("one approval over the whole set", () => {
|