@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
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
|
|
12
12
|
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
13
|
+
import { readFileSync } from "node:fs";
|
|
13
14
|
import { join } from "node:path";
|
|
14
15
|
import { tmpdir } from "node:os";
|
|
15
16
|
import type { Component } from "../../components/component";
|
|
@@ -75,6 +76,12 @@ const ESTATE = [
|
|
|
75
76
|
|
|
76
77
|
let ran: string[] = [];
|
|
77
78
|
let failing: string[] = [];
|
|
79
|
+
/** What each component's step was handed, after wiring resolved. */
|
|
80
|
+
let inputs: Record<string, Record<string, unknown>> = {};
|
|
81
|
+
/** Stack outputs a component's step returns, as cfn-deploy's `outputs` does. */
|
|
82
|
+
let stepOutputs: Record<string, Record<string, unknown>> = {};
|
|
83
|
+
/** Called as a component's step starts, before it applies. */
|
|
84
|
+
let onStart: (component: string) => void = () => {};
|
|
78
85
|
|
|
79
86
|
function makeArgs(overrides: Partial<ParsedArgs>): ParsedArgs {
|
|
80
87
|
return {
|
|
@@ -101,6 +108,9 @@ beforeEach(() => {
|
|
|
101
108
|
vi.clearAllMocks();
|
|
102
109
|
ran = [];
|
|
103
110
|
failing = [];
|
|
111
|
+
inputs = {};
|
|
112
|
+
stepOutputs = {};
|
|
113
|
+
onStart = () => {};
|
|
104
114
|
gateLedger = memoryGateLedgerPort();
|
|
105
115
|
stderrLines = [];
|
|
106
116
|
stdoutLines = [];
|
|
@@ -129,10 +139,12 @@ beforeEach(() => {
|
|
|
129
139
|
const registry = new CapabilityRegistry();
|
|
130
140
|
registry.register({
|
|
131
141
|
kind: "cfn-deploy",
|
|
132
|
-
async run(runCtx: { component: string }) {
|
|
142
|
+
async run(runCtx: { component: string }, input: Record<string, unknown>) {
|
|
143
|
+
onStart(runCtx.component);
|
|
133
144
|
ran.push(runCtx.component);
|
|
145
|
+
inputs[runCtx.component] = input;
|
|
134
146
|
if (failing.includes(runCtx.component)) throw new Error(`${runCtx.component} failed`);
|
|
135
|
-
return { ok: true };
|
|
147
|
+
return { ok: true, ...(stepOutputs[runCtx.component] ? { outputs: stepOutputs[runCtx.component] } : {}) };
|
|
136
148
|
},
|
|
137
149
|
} as never);
|
|
138
150
|
return Promise.resolve(registry);
|
|
@@ -326,6 +338,76 @@ describe("proof: the re-run prints already-applied for what it skips, and finish
|
|
|
326
338
|
});
|
|
327
339
|
});
|
|
328
340
|
|
|
341
|
+
describe("proof: killed mid-fan-out, a re-run finishes without hand repair", () => {
|
|
342
|
+
test("the record keeps what applied before the kill, and the repeated command runs only the rest", async () => {
|
|
343
|
+
const dir = await mkdtemp(join(tmpdir(), "fan-out-"));
|
|
344
|
+
try {
|
|
345
|
+
const resume = join(dir, "attempt.json");
|
|
346
|
+
// The process dies as app-one starts. Whatever the record says at that
|
|
347
|
+
// instant is all a killed process leaves behind, so that is what the
|
|
348
|
+
// second run is handed.
|
|
349
|
+
let atKill: string | undefined;
|
|
350
|
+
onStart = (name) => {
|
|
351
|
+
if (name === "app-one") atKill = readFileSync(resume, "utf8");
|
|
352
|
+
};
|
|
353
|
+
await runComponentsFanOut(ctx({ base: "main", env: "test", resume }));
|
|
354
|
+
expect(atKill).toBeDefined();
|
|
355
|
+
expect(JSON.parse(atKill!).completed).toEqual(["cluster-a", "cluster-b", "net"]);
|
|
356
|
+
|
|
357
|
+
await writeFile(resume, atKill!);
|
|
358
|
+
ran = [];
|
|
359
|
+
onStart = () => {};
|
|
360
|
+
stderrLines = [];
|
|
361
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
362
|
+
expect([...ran].sort()).toEqual(["app-one", "app-three", "app-two"]);
|
|
363
|
+
expect(stderr()).toMatch(/net +already-applied/);
|
|
364
|
+
expect(stderr()).toContain("fan-out completed: 3 applied, 0 failed, 0 blocked");
|
|
365
|
+
} finally {
|
|
366
|
+
await rm(dir, { recursive: true, force: true });
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("a component left to run reads a completed dependency's outputs from the record", async () => {
|
|
371
|
+
const wired: Component = {
|
|
372
|
+
name: "cluster-a",
|
|
373
|
+
dependsOn: ["net"],
|
|
374
|
+
deploy: [
|
|
375
|
+
{
|
|
376
|
+
phase: "Apply",
|
|
377
|
+
steps: [{ kind: "cfn-deploy", stack: "cluster-a-stack", inputs: { topic: { stackOutput: { stack: "net", name: "TopicArn" } } } }],
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
};
|
|
381
|
+
const estate = ESTATE.map((c) => (c.name === "cluster-a" ? wired : c));
|
|
382
|
+
discoverComponentsMock.mockResolvedValue({
|
|
383
|
+
components: new Map(estate.map((c) => [c.name, { component: c, exportName: c.name, filePath: `${c.name}.component.ts` }])),
|
|
384
|
+
sourceFiles: [],
|
|
385
|
+
errors: [],
|
|
386
|
+
});
|
|
387
|
+
stepOutputs = { net: { TopicArn: "arn:aws:sns:us-east-1:000000000000:net" } };
|
|
388
|
+
|
|
389
|
+
const dir = await mkdtemp(join(tmpdir(), "fan-out-"));
|
|
390
|
+
try {
|
|
391
|
+
const resume = join(dir, "attempt.json");
|
|
392
|
+
failing = ["cluster-a"];
|
|
393
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(1);
|
|
394
|
+
expect(JSON.parse(await readFile(resume, "utf8")).outputs.net).toEqual(stepOutputs.net);
|
|
395
|
+
|
|
396
|
+
// net does not run again, and nobody passes --seed-outputs.
|
|
397
|
+
ran = [];
|
|
398
|
+
failing = [];
|
|
399
|
+
inputs = {};
|
|
400
|
+
expect(await runComponentsFanOut(ctx({ base: "main", env: "test", resume }))).toBe(0);
|
|
401
|
+
expect(ran).not.toContain("net");
|
|
402
|
+
expect(inputs["cluster-a"]).toEqual(
|
|
403
|
+
expect.objectContaining({ inputs: { topic: "arn:aws:sns:us-east-1:000000000000:net" } }),
|
|
404
|
+
);
|
|
405
|
+
} finally {
|
|
406
|
+
await rm(dir, { recursive: true, force: true });
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
329
411
|
describe("proof: one approval covers the set, and the printed digest is what approves it", () => {
|
|
330
412
|
test("an unapproved gate stops the whole fan-out before anything runs", async () => {
|
|
331
413
|
const exit = await runComponentsFanOut(ctx({ base: "main", env: "test", gate: "release" }));
|
|
@@ -392,3 +474,140 @@ describe("proof: one approval covers the set, and the printed digest is what app
|
|
|
392
474
|
expect(ran).toEqual([]);
|
|
393
475
|
});
|
|
394
476
|
});
|
|
477
|
+
|
|
478
|
+
describe("gated waves (#3049): one gate per wave, bound to the wave's set digest", () => {
|
|
479
|
+
/** What each root's plan would write. Change one to change a root. */
|
|
480
|
+
let versions: Record<string, string> = {};
|
|
481
|
+
|
|
482
|
+
beforeEach(() => {
|
|
483
|
+
versions = {};
|
|
484
|
+
buildCapabilityRegistryMock.mockImplementation(() => {
|
|
485
|
+
const registry = new CapabilityRegistry();
|
|
486
|
+
registry.register({
|
|
487
|
+
kind: "cfn-deploy",
|
|
488
|
+
async plan(_ctx: unknown, input: { stack: string }) {
|
|
489
|
+
const v = versions[input.stack] ?? "v1";
|
|
490
|
+
return { member: input.stack, planDigest: "jcs1-sha256:" + (v === "v1" ? "1" : "2").repeat(64) };
|
|
491
|
+
},
|
|
492
|
+
async run(runCtx: { component: string }) {
|
|
493
|
+
ran.push(runCtx.component);
|
|
494
|
+
return { ok: true };
|
|
495
|
+
},
|
|
496
|
+
} as never);
|
|
497
|
+
return Promise.resolve(registry);
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
test("wave 1 stops at its own gate, and the record names its digest", async () => {
|
|
502
|
+
const dir = await mkdtemp(join(tmpdir(), "fan-out-waves-"));
|
|
503
|
+
try {
|
|
504
|
+
const record = join(dir, "fan-out.json");
|
|
505
|
+
const exit = await runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", resume: record }));
|
|
506
|
+
expect(exit).toBe(3);
|
|
507
|
+
expect(ran).toEqual([]);
|
|
508
|
+
const pending = gateLedger.appended[0];
|
|
509
|
+
expect(pending.gate).toBe("release-wave-1");
|
|
510
|
+
expect(stderr()).toContain(`approve : chant approve fan-out release-wave-1 --plan ${pending.planDigest}`);
|
|
511
|
+
const saved = JSON.parse(readFileSync(record, "utf8"));
|
|
512
|
+
expect(saved.waves).toMatchObject([{ wave: 1, gate: "release-wave-1", status: "gated", digest: pending.planDigest }]);
|
|
513
|
+
} finally {
|
|
514
|
+
await rm(dir, { recursive: true, force: true });
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test("approve wave 1, change a root, re-run: it stops naming both digests and applies nothing", async () => {
|
|
519
|
+
const dir = await mkdtemp(join(tmpdir(), "fan-out-waves-"));
|
|
520
|
+
try {
|
|
521
|
+
const record = join(dir, "fan-out.json");
|
|
522
|
+
const run = () => runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", resume: record }));
|
|
523
|
+
await run();
|
|
524
|
+
const approved = gateLedger.appended[0].planDigest!;
|
|
525
|
+
gateLedger = memoryGateLedgerPort({
|
|
526
|
+
pending: [gateLedger.appended[0]],
|
|
527
|
+
resolutions: [
|
|
528
|
+
{
|
|
529
|
+
version: 1,
|
|
530
|
+
kind: "resolution",
|
|
531
|
+
op: "fan-out",
|
|
532
|
+
gate: "release-wave-1",
|
|
533
|
+
resolvedBy: "operator",
|
|
534
|
+
timestamp: new Date(Date.parse(gateLedger.appended[0].timestamp) + 1000).toISOString(),
|
|
535
|
+
planDigest: approved,
|
|
536
|
+
},
|
|
537
|
+
],
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
versions["net-stack"] = "v2";
|
|
541
|
+
stderrLines = [];
|
|
542
|
+
expect(await run()).toBe(3);
|
|
543
|
+
expect(ran).toEqual([]);
|
|
544
|
+
const planned = gateLedger.appended[0].planDigest!;
|
|
545
|
+
expect(planned).not.toBe(approved);
|
|
546
|
+
expect(stderr()).toContain(`approved: ${approved}; planned now: ${planned}`);
|
|
547
|
+
expect(stderr()).toContain("nothing in it was applied");
|
|
548
|
+
const saved = JSON.parse(readFileSync(record, "utf8"));
|
|
549
|
+
expect(saved.waves[0]).toMatchObject({ status: "gated", approved, digest: planned });
|
|
550
|
+
} finally {
|
|
551
|
+
await rm(dir, { recursive: true, force: true });
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
test("an approved wave applies, the run stops at the next wave, and the record carries both", async () => {
|
|
556
|
+
const dir = await mkdtemp(join(tmpdir(), "fan-out-waves-"));
|
|
557
|
+
try {
|
|
558
|
+
const record = join(dir, "fan-out.json");
|
|
559
|
+
const run = () => runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", resume: record }));
|
|
560
|
+
await run();
|
|
561
|
+
const first = gateLedger.appended[0];
|
|
562
|
+
gateLedger = memoryGateLedgerPort({
|
|
563
|
+
pending: [first],
|
|
564
|
+
resolutions: [
|
|
565
|
+
{
|
|
566
|
+
version: 1,
|
|
567
|
+
kind: "resolution",
|
|
568
|
+
op: "fan-out",
|
|
569
|
+
gate: "release-wave-1",
|
|
570
|
+
resolvedBy: "operator",
|
|
571
|
+
timestamp: new Date(Date.parse(first.timestamp) + 1000).toISOString(),
|
|
572
|
+
planDigest: first.planDigest,
|
|
573
|
+
},
|
|
574
|
+
],
|
|
575
|
+
});
|
|
576
|
+
expect(await run()).toBe(3);
|
|
577
|
+
expect(ran).toEqual(["net"]);
|
|
578
|
+
const saved = JSON.parse(readFileSync(record, "utf8"));
|
|
579
|
+
expect(saved.completed).toEqual(["net"]);
|
|
580
|
+
expect(saved.waves.map((w: { wave: number; status: string }) => [w.wave, w.status])).toEqual([
|
|
581
|
+
[1, "applied"],
|
|
582
|
+
[2, "gated"],
|
|
583
|
+
]);
|
|
584
|
+
|
|
585
|
+
// The same command again: wave 1 is not applied a second time.
|
|
586
|
+
ran = [];
|
|
587
|
+
expect(await run()).toBe(3);
|
|
588
|
+
expect(ran).toEqual([]);
|
|
589
|
+
} finally {
|
|
590
|
+
await rm(dir, { recursive: true, force: true });
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
test("--canary puts a component in wave 1, and the dry run names each wave's gate", async () => {
|
|
595
|
+
const exit = await runComponentsFanOut(ctx({ base: "main", dryRun: true, waveGate: "release", canary: ["cluster-b"] }));
|
|
596
|
+
expect(exit).toBe(0);
|
|
597
|
+
expect(stderr()).toContain("wave 1: cluster-b (gate release-wave-1)");
|
|
598
|
+
expect(stderr()).toContain("wave 2: app-three, net (gate release-wave-2)");
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
test("--wave 2 refuses while wave 1 has not applied", async () => {
|
|
602
|
+
const exit = await runComponentsFanOut(ctx({ base: "main", env: "test", waveGate: "release", wave: 2 }));
|
|
603
|
+
expect(exit).toBe(1);
|
|
604
|
+
expect(stderr()).toContain("wave 2 cannot run yet: wave 1 has not applied (net)");
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
test("--gate and --wave-gate together are refused, and --wave needs --wave-gate", async () => {
|
|
608
|
+
expect(await runComponentsFanOut(ctx({ base: "main", gate: "release", waveGate: "release" }))).toBe(1);
|
|
609
|
+
expect(stderr()).toContain("--gate and --wave-gate both name a gate");
|
|
610
|
+
expect(await runComponentsFanOut(ctx({ base: "main", wave: 1 }))).toBe(1);
|
|
611
|
+
expect(stderr()).toContain("--wave runs one wave");
|
|
612
|
+
});
|
|
613
|
+
});
|
|
@@ -33,19 +33,28 @@
|
|
|
33
33
|
* `--resume` carries the earlier attempt's progress, `remainingFanOut` narrows
|
|
34
34
|
* the plan before the gate is decided, and the digest is carried rather than
|
|
35
35
|
* recomputed, so the approval still stands.
|
|
36
|
+
*
|
|
37
|
+
* `--wave-gate <name>` (#3049) swaps the one gate for one per wave: the same
|
|
38
|
+
* repeated command stops at each wave's gate in turn, each planned after the
|
|
39
|
+
* wave before it applied, and `chant approve fan-out <name>-wave-<n>` answers
|
|
40
|
+
* it. `--wave <n>` runs one wave, for a CI job per wave.
|
|
36
41
|
*/
|
|
37
42
|
|
|
38
43
|
import { resolve, dirname } from "node:path";
|
|
39
|
-
import {
|
|
44
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
40
45
|
import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
|
|
41
46
|
import { samePlanDigest } from "../../lifecycle/plan-digest";
|
|
42
47
|
import { affectedStacks } from "../../lifecycle/affected";
|
|
48
|
+
import { changedFilesBetween, lexiconChangedUnits } from "../../components/changed-files";
|
|
43
49
|
import { deriveFanOut, fanOutRegistry } from "../../components/fan-out-support";
|
|
44
|
-
import { runFanOut } from "../../components/fan-out-run";
|
|
50
|
+
import { EarlierWaveNotAppliedError, runFanOut } from "../../components/fan-out-run";
|
|
51
|
+
import { readFanOutAttempt, writeFanOutAttempt, type FanOutAttempt } from "../../components/fan-out-record";
|
|
52
|
+
import { describeChangedWave, withWaveRecord, type WaveRecord } from "../../gated-waves";
|
|
45
53
|
import { renderFanOutHuman, renderFanOutJson, renderFanOutPlan } from "../../components/fan-out-output";
|
|
46
54
|
import { ndjsonProgressSink } from "../../components/run-progress";
|
|
47
55
|
import { summaryLedgerPrefix, writeGatedRunSummary } from "../../op/gate-summary";
|
|
48
56
|
import { approveCommand } from "../../op/gate";
|
|
57
|
+
import { getHeadCommit } from "../../lifecycle/git";
|
|
49
58
|
import { remainingFanOut, type ChangedUnits, type FanOutProgress } from "../../components/fan-out";
|
|
50
59
|
import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
|
|
51
60
|
import { formatError, formatInfo, formatWarning } from "../format";
|
|
@@ -54,37 +63,6 @@ import { resolveBuildRoot } from "./lifecycle";
|
|
|
54
63
|
import { GATED_EXIT_CODE, recordAutoReleasesForRun } from "./run";
|
|
55
64
|
import type { CommandContext } from "../registry";
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* What an attempt left behind, and what the next one reads (`--resume`).
|
|
61
|
-
*
|
|
62
|
-
* The digest is stored alongside the progress because progress is only
|
|
63
|
-
* meaningful for the plan it was made against. A fan-out derived from different
|
|
64
|
-
* source is a different fan-out, and carrying "cluster-a already applied" into
|
|
65
|
-
* it would be a claim about work nobody did.
|
|
66
|
-
*/
|
|
67
|
-
interface FanOutAttempt {
|
|
68
|
-
digest: string;
|
|
69
|
-
completed: string[];
|
|
70
|
-
failed: string[];
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function readAttempt(path: string): FanOutAttempt | undefined {
|
|
74
|
-
if (!existsSync(path)) return undefined;
|
|
75
|
-
const parsed = JSON.parse(readFileSync(path, "utf8")) as Partial<FanOutAttempt>;
|
|
76
|
-
return {
|
|
77
|
-
digest: typeof parsed.digest === "string" ? parsed.digest : "",
|
|
78
|
-
completed: Array.isArray(parsed.completed) ? parsed.completed.filter((n): n is string => typeof n === "string") : [],
|
|
79
|
-
failed: Array.isArray(parsed.failed) ? parsed.failed.filter((n): n is string => typeof n === "string") : [],
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function writeAttempt(path: string, attempt: FanOutAttempt): void {
|
|
84
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
85
|
-
writeFileSync(path, JSON.stringify(attempt, null, 2) + "\n");
|
|
86
|
-
}
|
|
87
|
-
|
|
88
66
|
/**
|
|
89
67
|
* The stack-level change signal, from whichever end the invocation supplied.
|
|
90
68
|
*
|
|
@@ -100,13 +78,20 @@ function writeAttempt(path: string, attempt: FanOutAttempt): void {
|
|
|
100
78
|
* consumes a changed export is affected at stack granularity in the same way a
|
|
101
79
|
* changed component is at component granularity.
|
|
102
80
|
*/
|
|
103
|
-
async function resolveChangedUnits(
|
|
81
|
+
export async function resolveChangedUnits(
|
|
104
82
|
ctx: CommandContext,
|
|
105
83
|
config: ChantConfig,
|
|
84
|
+
opts: {
|
|
85
|
+
/** Measure from this commit instead of `--base` (a pull request's merge base, #3183). */
|
|
86
|
+
base?: string;
|
|
87
|
+
/** Build both refs for `lifecycle affected` only when the project declares `stacks`. */
|
|
88
|
+
stacksOnly?: boolean;
|
|
89
|
+
} = {},
|
|
106
90
|
): Promise<{ units: ChangedUnits } | { error: string; hint?: string }> {
|
|
107
91
|
const { args } = ctx;
|
|
92
|
+
const base = opts.base ?? args.base;
|
|
108
93
|
const fromFile = args.fromAffected;
|
|
109
|
-
if (
|
|
94
|
+
if (base && fromFile) {
|
|
110
95
|
return {
|
|
111
96
|
error: "--base and --from-affected both name a change signal",
|
|
112
97
|
hint: "Pass --base <ref> to derive it here, or --from-affected <file> to read one `chant lifecycle affected --json` already wrote.",
|
|
@@ -136,7 +121,7 @@ async function resolveChangedUnits(
|
|
|
136
121
|
};
|
|
137
122
|
}
|
|
138
123
|
|
|
139
|
-
if (!
|
|
124
|
+
if (!base) {
|
|
140
125
|
return {
|
|
141
126
|
error: "A change signal is required: chant components fan-out --base <ref> [--head <ref>]",
|
|
142
127
|
hint: "Or pass --from-affected <file> with the JSON `chant lifecycle affected --base <ref> --json` wrote.",
|
|
@@ -144,23 +129,37 @@ async function resolveChangedUnits(
|
|
|
144
129
|
}
|
|
145
130
|
|
|
146
131
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
132
|
+
// A unit that is not chant source, such as a Terraform root, never shows
|
|
133
|
+
// in the artifact diff below; the lexicon that owns it answers from the
|
|
134
|
+
// changed paths (#3183).
|
|
135
|
+
const projectRoot = resolve(".");
|
|
136
|
+
const lexiconUnits = ctx.plugins.some((p) => p.changedUnits)
|
|
137
|
+
? await lexiconChangedUnits(ctx.plugins, {
|
|
138
|
+
projectRoot,
|
|
139
|
+
config: config as Record<string, unknown>,
|
|
140
|
+
changedFiles: await changedFilesBetween(projectRoot, base, args.head ?? "HEAD"),
|
|
141
|
+
})
|
|
142
|
+
: [];
|
|
143
|
+
const result =
|
|
144
|
+
opts.stacksOnly && !config.stacks?.length
|
|
145
|
+
? { changed: [], dependents: [], indeterminate: [] }
|
|
146
|
+
: await affectedStacks({
|
|
147
|
+
// Components are discovered from the current directory, the convention
|
|
148
|
+
// every component command follows. In a multi-stack project the diff
|
|
149
|
+
// reads the same root, because `stacks[].src` is written relative to it.
|
|
150
|
+
projectPath: config.stacks?.length ? resolve(".") : resolveBuildRoot(args, config),
|
|
151
|
+
serializers: ctx.plugins.map((p) => p.serializer),
|
|
152
|
+
baseRef: base,
|
|
153
|
+
headRef: args.head,
|
|
154
|
+
includeDependents: args.includeDependents,
|
|
155
|
+
// A project that declares its stacks gets an answer keyed by stack name,
|
|
156
|
+
// which is the name a component's deploy step uses. Without this the diff
|
|
157
|
+
// answers by lexicon partition and the join below claims none of it.
|
|
158
|
+
...(config.stacks ? { stacks: config.stacks } : {}),
|
|
159
|
+
});
|
|
161
160
|
return {
|
|
162
161
|
units: {
|
|
163
|
-
changed: [...new Set([...result.changed, ...result.dependents])].sort(),
|
|
162
|
+
changed: [...new Set([...result.changed, ...result.dependents, ...lexiconUnits])].sort(),
|
|
164
163
|
indeterminate: result.indeterminate,
|
|
165
164
|
},
|
|
166
165
|
};
|
|
@@ -190,6 +189,21 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
190
189
|
return 1;
|
|
191
190
|
}
|
|
192
191
|
|
|
192
|
+
// The two gate modes (#3049). `--gate` approves the whole set once, as
|
|
193
|
+
// #2417 decided; `--wave-gate` approves each wave once the waves before it
|
|
194
|
+
// applied. They answer different questions, so one run takes one of them.
|
|
195
|
+
if (args.gate && args.waveGate) {
|
|
196
|
+
console.error(formatError({
|
|
197
|
+
message: "--gate and --wave-gate both name a gate",
|
|
198
|
+
hint: "Pass --gate <name> for one approval over the whole set, or --wave-gate <name> for one per wave.",
|
|
199
|
+
}));
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
if (args.wave !== undefined && !args.waveGate) {
|
|
203
|
+
console.error(formatError({ message: "--wave runs one wave of a gated-wave fan-out, so it needs --wave-gate <name>" }));
|
|
204
|
+
return 1;
|
|
205
|
+
}
|
|
206
|
+
|
|
193
207
|
const signal = await resolveChangedUnits(ctx, config);
|
|
194
208
|
if ("error" in signal) {
|
|
195
209
|
console.error(formatError({ message: signal.error, ...(signal.hint ? { hint: signal.hint } : {}) }));
|
|
@@ -204,6 +218,7 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
204
218
|
sandbox: args.sandbox,
|
|
205
219
|
buildParams: paramsResolution.provenance,
|
|
206
220
|
config,
|
|
221
|
+
...(args.canary?.length ? { canary: args.canary } : {}),
|
|
207
222
|
});
|
|
208
223
|
} catch (err) {
|
|
209
224
|
// A cycle or an unknown `dependsOn` refuses here, over the whole graph and
|
|
@@ -226,6 +241,9 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
226
241
|
}
|
|
227
242
|
|
|
228
243
|
const gate = args.gate ? { op: FAN_OUT_GATE_OP, gate: args.gate } : undefined;
|
|
244
|
+
const waveGate = args.waveGate
|
|
245
|
+
? { op: FAN_OUT_GATE_OP, gate: args.waveGate, ...(args.wave !== undefined ? { only: args.wave } : {}) }
|
|
246
|
+
: undefined;
|
|
229
247
|
|
|
230
248
|
// `--resume`: what an earlier attempt at this same plan finished. Read before
|
|
231
249
|
// the dry-run branch so a plan-only invocation shows what is actually left
|
|
@@ -234,11 +252,13 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
234
252
|
// approval survives the resume rather than being re-asked for.
|
|
235
253
|
const resumePath = args.resume ? resolve(args.resume) : undefined;
|
|
236
254
|
let priorCompleted: string[] = [];
|
|
255
|
+
let priorOutputs: Record<string, Record<string, unknown>> = {};
|
|
256
|
+
let priorWaves: WaveRecord[] = [];
|
|
237
257
|
let progress: FanOutProgress | undefined;
|
|
238
258
|
if (resumePath) {
|
|
239
259
|
let attempt: FanOutAttempt | undefined;
|
|
240
260
|
try {
|
|
241
|
-
attempt =
|
|
261
|
+
attempt = readFanOutAttempt(resumePath);
|
|
242
262
|
} catch (err) {
|
|
243
263
|
console.error(formatError({ message: `--resume: could not read "${args.resume}": ${err instanceof Error ? err.message : String(err)}` }));
|
|
244
264
|
return 1;
|
|
@@ -255,16 +275,22 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
255
275
|
// exists to retry them — the operator repeated the command precisely
|
|
256
276
|
// because the thing that failed is now expected to work.
|
|
257
277
|
priorCompleted = attempt.completed;
|
|
278
|
+
priorOutputs = Object.fromEntries(
|
|
279
|
+
Object.entries(attempt.outputs).filter(([name]) => attempt.completed.includes(name)),
|
|
280
|
+
);
|
|
258
281
|
progress = { completed: attempt.completed };
|
|
282
|
+
priorWaves = attempt.waves ?? [];
|
|
259
283
|
}
|
|
260
284
|
}
|
|
261
285
|
|
|
262
286
|
if (args.dryRun) {
|
|
263
287
|
// `remainingFanOut` carries the digest rather than minting a new one, so
|
|
264
288
|
// the digest printed here is the same string that approves the real run.
|
|
265
|
-
|
|
289
|
+
// A gated-wave fan-out keeps the derivation's wave numbers, since they
|
|
290
|
+
// name the gates, so its plan is printed whole.
|
|
291
|
+
const plan = progress && !waveGate ? remainingFanOut(derived.plan, derived.components, progress) : derived.plan;
|
|
266
292
|
if (args.json) renderFanOutJson(plan);
|
|
267
|
-
else renderFanOutPlan(plan, { ...(gate ? { gate } : {}) });
|
|
293
|
+
else renderFanOutPlan(plan, { ...(gate ? { gate } : {}), ...(waveGate ? { waveGate } : {}) });
|
|
268
294
|
return 0;
|
|
269
295
|
}
|
|
270
296
|
|
|
@@ -279,13 +305,72 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
279
305
|
}
|
|
280
306
|
|
|
281
307
|
const registry = await fanOutRegistry(projectPath, config);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
308
|
+
// #3061: the commit this run deploys, for the workloads' vcs.ref.head.revision.
|
|
309
|
+
const revision = await getHeadCommit().catch(() => undefined);
|
|
310
|
+
|
|
311
|
+
// The record is rewritten as each component settles, not only once the run
|
|
312
|
+
// returns. A fan-out killed in its third wave (a cancelled CI job, a lost
|
|
313
|
+
// runner, ctrl-c) then still knows that the first two applied, and the
|
|
314
|
+
// repeated command picks up from there instead of redoing them.
|
|
315
|
+
const completedSoFar = new Set(priorCompleted);
|
|
316
|
+
const failedSoFar: string[] = [];
|
|
317
|
+
const outputsSoFar = { ...priorOutputs };
|
|
318
|
+
let wavesSoFar = priorWaves;
|
|
319
|
+
const recordAttempt = (): void => {
|
|
320
|
+
if (!resumePath) return;
|
|
321
|
+
const attempt: FanOutAttempt = {
|
|
322
|
+
digest: derived.plan.digest,
|
|
323
|
+
completed: [...completedSoFar].sort(),
|
|
324
|
+
failed: [...failedSoFar].sort(),
|
|
325
|
+
outputs: outputsSoFar,
|
|
326
|
+
...(wavesSoFar.length > 0 ? { waves: wavesSoFar } : {}),
|
|
327
|
+
};
|
|
328
|
+
writeFanOutAttempt(resumePath, attempt);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
let result;
|
|
332
|
+
try {
|
|
333
|
+
result = await runFanOut(derived.plan, derived.components, registry, {
|
|
334
|
+
env: args.env ?? "local",
|
|
335
|
+
releaseIdentity: () => (revision ? { revision } : {}),
|
|
336
|
+
// A completed component's recorded outputs win over a `--seed-outputs`
|
|
337
|
+
// entry for the same name, as a fresh apply's outputs merge over a seed in
|
|
338
|
+
// the driver: the record holds what this fan-out itself applied.
|
|
339
|
+
componentOutputs: { ...seededOutputs, ...priorOutputs },
|
|
340
|
+
...(gate ? { gate } : {}),
|
|
341
|
+
...(waveGate ? { waveGate } : {}),
|
|
342
|
+
...(waveGate
|
|
343
|
+
? {
|
|
344
|
+
onWaveSettled: (record: WaveRecord) => {
|
|
345
|
+
wavesSoFar = withWaveRecord(wavesSoFar, record);
|
|
346
|
+
recordAttempt();
|
|
347
|
+
},
|
|
348
|
+
}
|
|
349
|
+
: {}),
|
|
350
|
+
...(progress ? { progress } : {}),
|
|
351
|
+
...(args.progressJson ? { onProgress: ndjsonProgressSink() } : {}),
|
|
352
|
+
...(resumePath
|
|
353
|
+
? {
|
|
354
|
+
onComponentSettled: (settled, outputs) => {
|
|
355
|
+
if (settled.status === "ok") {
|
|
356
|
+
completedSoFar.add(settled.component);
|
|
357
|
+
if (outputs) outputsSoFar[settled.component] = outputs;
|
|
358
|
+
} else if (settled.status === "fail") {
|
|
359
|
+
failedSoFar.push(settled.component);
|
|
360
|
+
}
|
|
361
|
+
recordAttempt();
|
|
362
|
+
},
|
|
363
|
+
}
|
|
364
|
+
: {}),
|
|
365
|
+
});
|
|
366
|
+
} catch (err) {
|
|
367
|
+
// `--wave <n>` reached before an earlier wave applied: nothing ran.
|
|
368
|
+
if (err instanceof EarlierWaveNotAppliedError) {
|
|
369
|
+
console.error(formatError({ message: err.message }));
|
|
370
|
+
return 1;
|
|
371
|
+
}
|
|
372
|
+
throw err;
|
|
373
|
+
}
|
|
289
374
|
|
|
290
375
|
if (args.dumpOutputs) {
|
|
291
376
|
const dumpPath = resolve(args.dumpOutputs);
|
|
@@ -293,25 +378,28 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
293
378
|
writeFileSync(dumpPath, JSON.stringify(result.componentOutputs, null, 2));
|
|
294
379
|
}
|
|
295
380
|
|
|
296
|
-
// Written even on a failure and even on a gate:
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
writeAttempt(resumePath, {
|
|
301
|
-
digest: result.plan.digest,
|
|
302
|
-
completed: [...new Set([...priorCompleted, ...result.completed])].sort(),
|
|
303
|
-
failed: result.failed,
|
|
304
|
-
});
|
|
305
|
-
}
|
|
381
|
+
// Written again at the end, even on a failure and even on a gate: a gated
|
|
382
|
+
// attempt got through nothing, which is itself worth recording against this
|
|
383
|
+
// plan's digest.
|
|
384
|
+
recordAttempt();
|
|
306
385
|
|
|
307
386
|
if (args.json) renderFanOutJson(result);
|
|
308
|
-
else renderFanOutHuman(result, { ...(gate ? { gate } : {}) });
|
|
387
|
+
else renderFanOutHuman(result, { ...(gate ? { gate } : {}), ...(waveGate ? { waveGate } : {}) });
|
|
388
|
+
|
|
389
|
+
// A wave whose set moved after its approval stops with both digests named
|
|
390
|
+
// (#3049), the #2300 refusal on a set. Printed on stderr even under --json,
|
|
391
|
+
// since it is the line a CI log reader is looking for.
|
|
392
|
+
for (const wave of result.waves ?? []) {
|
|
393
|
+
if (wave.status === "gated" && wave.approved) console.error(formatWarning({ message: describeChangedWave(wave) }));
|
|
394
|
+
}
|
|
309
395
|
|
|
310
396
|
// The same durable trace `chant run --components` leaves (#597), for the
|
|
311
397
|
// components this fan-out actually applied. A partial fan-out records the
|
|
312
398
|
// branches that finished and nothing else, which is the whole reason the
|
|
313
399
|
// runner reports `completed` separately from `failed`.
|
|
314
|
-
|
|
400
|
+
// A gated-wave run can stop at a later wave's gate after earlier waves
|
|
401
|
+
// applied, and those applies are recorded like any other.
|
|
402
|
+
if (result.status !== "gated" || result.completed.length > 0) {
|
|
315
403
|
await recordAutoReleasesForRun(
|
|
316
404
|
result.results,
|
|
317
405
|
args.env ?? "local",
|
|
@@ -320,7 +408,9 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
320
408
|
);
|
|
321
409
|
}
|
|
322
410
|
|
|
323
|
-
|
|
411
|
+
// A failed root outranks a gate in the status, but a gated-wave run that
|
|
412
|
+
// stopped at a wave's gate still prints how to approve it.
|
|
413
|
+
if (result.gate && (result.status === "gated" || waveGate)) {
|
|
324
414
|
const pending = result.gate;
|
|
325
415
|
// The pending fact's own plan: the fan-out's digest for the gate over the
|
|
326
416
|
// set, or a component's plan and environment for a gate inside one (#2574).
|
|
@@ -337,7 +427,7 @@ export async function runComponentsFanOut(ctx: CommandContext): Promise<number>
|
|
|
337
427
|
...(await summaryLedgerPrefix()),
|
|
338
428
|
...(pending.environment ? { environment: pending.environment } : {}),
|
|
339
429
|
});
|
|
340
|
-
return GATED_EXIT_CODE;
|
|
430
|
+
return result.status === "gated" ? GATED_EXIT_CODE : 1;
|
|
341
431
|
}
|
|
342
432
|
|
|
343
433
|
return result.status === "ok" ? 0 : 1;
|
|
@@ -637,6 +637,9 @@ async function runComponentGraphView(
|
|
|
637
637
|
// `chant workspace graph --composites` labels a component without
|
|
638
638
|
// importing its source.
|
|
639
639
|
...(graph.archetypes?.[name] ? { archetype: graph.archetypes[name] } : {}),
|
|
640
|
+
// The environments the component declares (#3153), where each release goes, so
|
|
641
|
+
// `chant workspace graph --composites` lists them without importing its source.
|
|
642
|
+
...(graph.environments?.[name] ? { environments: graph.environments[name] } : {}),
|
|
640
643
|
},
|
|
641
644
|
// Deep-link the node to its `*.component.ts` (behold's inspect panel).
|
|
642
645
|
...(graph.files?.[name] ? { sourceLoc: { file: graph.files[name] } } : {}),
|