@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
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant components pr-plan` and `chant components pr-apply` (#3183): the
|
|
3
|
+
* pull-request loop the generated CI runs.
|
|
4
|
+
*
|
|
5
|
+
* ```
|
|
6
|
+
* chant components pr-plan --base <ref> --pr <n> --env <env> [--forge github|gitlab|forgejo]
|
|
7
|
+
* chant approve pr-<n> pr-apply --plan <digest> --approver github:<login> --sign
|
|
8
|
+
* chant components pr-apply --base <ref> --env <env> [--pr <n>] [--forge <kind>] [--require-review]
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Both measure the change from the merge base of `--base` and `HEAD`, select
|
|
12
|
+
* the components it reaches and the ones that depend on them (the fan-out's
|
|
13
|
+
* derivation, #2417), and plan every member before anything applies
|
|
14
|
+
* (`../../components/pr-run.ts`). pr-plan writes the report and the note and
|
|
15
|
+
* applies nothing; it reads the gate ledger and writes nothing to it, since
|
|
16
|
+
* it runs the pull request's own code. pr-apply plans the same members on
|
|
17
|
+
* the merged commit, decides the gate against the digest it gets, and
|
|
18
|
+
* applies only when an approval stands for that digest. A moved plan stops
|
|
19
|
+
* it with both digests named and nothing applied (exit 3).
|
|
20
|
+
*
|
|
21
|
+
* Every run writes `pr-plan.json` or `pr-apply.json` (`pr-report.schema.json`),
|
|
22
|
+
* `change-set.json` and `pr-note.md` under `--output` (default `.chant/pr`).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
26
|
+
import { join, resolve } from "node:path";
|
|
27
|
+
import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
|
|
28
|
+
import { resolveCommit, resolveMergeBase } from "../../components/changed-files";
|
|
29
|
+
import { deriveFanOut, fanOutRegistry } from "../../components/fan-out-support";
|
|
30
|
+
import {
|
|
31
|
+
applyPrSet,
|
|
32
|
+
approvalOf,
|
|
33
|
+
approversWithoutReview,
|
|
34
|
+
decidePrGate,
|
|
35
|
+
planPrSet,
|
|
36
|
+
prReport,
|
|
37
|
+
readOnlyLedger,
|
|
38
|
+
type PrPlanSet,
|
|
39
|
+
} from "../../components/pr-run";
|
|
40
|
+
import { gitGateLedgerPort } from "../../op/gate";
|
|
41
|
+
import {
|
|
42
|
+
describePlanChanged,
|
|
43
|
+
PR_APPLY_GATE,
|
|
44
|
+
PR_STATUS_CONTEXTS,
|
|
45
|
+
prApproveCommand,
|
|
46
|
+
prNoteMarker,
|
|
47
|
+
prOp,
|
|
48
|
+
prStatusDescription,
|
|
49
|
+
prStatusState,
|
|
50
|
+
renderPrNote,
|
|
51
|
+
type PrApproval,
|
|
52
|
+
type PrReport,
|
|
53
|
+
} from "../../pr-loop";
|
|
54
|
+
import { FORGE_KINDS, forgeFromEnv, forgePrincipalOf, type ForgeKind, type PrForge } from "../../pr-forge";
|
|
55
|
+
import { GITHUB_COMMENT_LIMIT, GITLAB_NOTE_LIMIT } from "../../plan-summary";
|
|
56
|
+
import { resolveCliBuildParams, parseParamFlags } from "../build-params-cli";
|
|
57
|
+
import { formatError, formatInfo, formatSuccess, formatWarning } from "../format";
|
|
58
|
+
import { resolveChangedUnits } from "./fan-out";
|
|
59
|
+
import { GATED_EXIT_CODE, recordAutoReleasesForRun } from "./run";
|
|
60
|
+
import type { CommandContext } from "../registry";
|
|
61
|
+
import type { ComponentChangeSignal, FanOutPlan } from "../../components/fan-out";
|
|
62
|
+
import type { DriverComponent } from "../../components/driver";
|
|
63
|
+
import type { CapabilityRegistry } from "../../components/capability";
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/** Where the reports land unless `--output` says. */
|
|
67
|
+
export const PR_REPORT_DIR = ".chant/pr";
|
|
68
|
+
|
|
69
|
+
interface Prepared {
|
|
70
|
+
config: ChantConfig;
|
|
71
|
+
env: string;
|
|
72
|
+
base: string;
|
|
73
|
+
head: string;
|
|
74
|
+
gate: string;
|
|
75
|
+
forge?: PrForge;
|
|
76
|
+
components: DriverComponent[];
|
|
77
|
+
plan: FanOutPlan;
|
|
78
|
+
signal: ComponentChangeSignal;
|
|
79
|
+
registry: CapabilityRegistry;
|
|
80
|
+
set: PrPlanSet;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const fail = (message: string, hint?: string): number => {
|
|
84
|
+
console.error(formatError({ message, ...(hint ? { hint } : {}) }));
|
|
85
|
+
return 1;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** Everything both stages share: the change, the derivation and the plan of every member. */
|
|
89
|
+
async function prepare(ctx: CommandContext, stage: "plan" | "apply"): Promise<Prepared | number> {
|
|
90
|
+
const { args } = ctx;
|
|
91
|
+
const projectPath = resolve(".");
|
|
92
|
+
const { config } = await loadChantConfig(projectPath).catch(() => ({ config: {} as ChantConfig }));
|
|
93
|
+
const paramsResolution = resolveCliBuildParams(config.buildParams, {
|
|
94
|
+
cli: parseParamFlags(args.param),
|
|
95
|
+
paramsFile: args.paramsFile,
|
|
96
|
+
verbose: args.verbose,
|
|
97
|
+
});
|
|
98
|
+
if (!paramsResolution.success) {
|
|
99
|
+
for (const message of paramsResolution.errors) console.error(message);
|
|
100
|
+
return 1;
|
|
101
|
+
}
|
|
102
|
+
if (!args.base) {
|
|
103
|
+
return fail(
|
|
104
|
+
`pr-${stage} needs the commit the change is measured from: --base <ref>`,
|
|
105
|
+
stage === "plan" ? "On a pull request, the target branch's commit." : "On a push, the commit before it.",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
if (args.fromAffected) return fail(`pr-${stage} derives the change itself; drop --from-affected`);
|
|
109
|
+
if (args.forge !== undefined && !(FORGE_KINDS as readonly string[]).includes(args.forge)) {
|
|
110
|
+
return fail(`--forge ${args.forge} is not one of ${FORGE_KINDS.join(", ")}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let forge: PrForge | undefined;
|
|
114
|
+
if (args.forge) {
|
|
115
|
+
try {
|
|
116
|
+
forge = forgeFromEnv(args.forge as ForgeKind);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let base: string;
|
|
123
|
+
let head: string;
|
|
124
|
+
try {
|
|
125
|
+
head = await resolveCommit(projectPath, args.head ?? "HEAD");
|
|
126
|
+
base = await resolveMergeBase(projectPath, args.base, head);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const signal = await resolveChangedUnits(ctx, config, { base, stacksOnly: true });
|
|
132
|
+
if ("error" in signal) return fail(signal.error, signal.hint);
|
|
133
|
+
|
|
134
|
+
let derived;
|
|
135
|
+
try {
|
|
136
|
+
derived = await deriveFanOut({
|
|
137
|
+
path: projectPath,
|
|
138
|
+
units: signal.units,
|
|
139
|
+
sandbox: args.sandbox,
|
|
140
|
+
buildParams: paramsResolution.provenance,
|
|
141
|
+
config,
|
|
142
|
+
});
|
|
143
|
+
} catch (err) {
|
|
144
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
145
|
+
}
|
|
146
|
+
if (!derived.success) return fail(derived.error ?? "Could not discover components");
|
|
147
|
+
|
|
148
|
+
const seededOutputs: Record<string, Record<string, unknown>> = {};
|
|
149
|
+
for (const file of args.seedOutputs ?? []) {
|
|
150
|
+
try {
|
|
151
|
+
Object.assign(seededOutputs, JSON.parse(readFileSync(resolve(file), "utf8")));
|
|
152
|
+
} catch (err) {
|
|
153
|
+
return fail(`--seed-outputs: could not read "${file}": ${err instanceof Error ? err.message : String(err)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const env = args.env ?? "local";
|
|
158
|
+
const registry = await fanOutRegistry(projectPath, config);
|
|
159
|
+
const set = await planPrSet({ components: derived.components, plan: derived.plan, registry, env, seededOutputs });
|
|
160
|
+
return {
|
|
161
|
+
config,
|
|
162
|
+
env,
|
|
163
|
+
base,
|
|
164
|
+
head,
|
|
165
|
+
gate: args.gate ?? PR_APPLY_GATE,
|
|
166
|
+
...(forge ? { forge } : {}),
|
|
167
|
+
components: derived.components,
|
|
168
|
+
plan: derived.plan,
|
|
169
|
+
signal: derived.signal,
|
|
170
|
+
registry,
|
|
171
|
+
set,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Write the report, the change set and the note; print the note's path. */
|
|
176
|
+
function writeOutputs(ctx: CommandContext, report: PrReport, note: string): void {
|
|
177
|
+
const dir = resolve(ctx.args.output ?? PR_REPORT_DIR);
|
|
178
|
+
mkdirSync(dir, { recursive: true });
|
|
179
|
+
writeFileSync(join(dir, `pr-${report.stage}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
180
|
+
writeFileSync(join(dir, "change-set.json"), JSON.stringify(report.changeSet, null, 2) + "\n");
|
|
181
|
+
writeFileSync(join(dir, "pr-note.md"), note);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Post the note and the stage's status. A forge that refuses is a warning: the stage's outcome stands. */
|
|
185
|
+
async function publish(forge: PrForge | undefined, report: PrReport, note: string): Promise<void> {
|
|
186
|
+
if (!forge) return;
|
|
187
|
+
const status = {
|
|
188
|
+
context: PR_STATUS_CONTEXTS[report.stage],
|
|
189
|
+
state: prStatusState(report),
|
|
190
|
+
description: prStatusDescription(report),
|
|
191
|
+
...(forge.runUrl ? { url: forge.runUrl } : {}),
|
|
192
|
+
};
|
|
193
|
+
try {
|
|
194
|
+
await forge.setStatus(report.head, status);
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.error(formatWarning({ message: `could not set the ${status.context} status: ${err instanceof Error ? err.message : String(err)}` }));
|
|
197
|
+
}
|
|
198
|
+
if (report.pr === null) return;
|
|
199
|
+
try {
|
|
200
|
+
await forge.upsertNote(report.pr, prNoteMarker(report.env), note);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
console.error(formatWarning({ message: `could not post the note on #${report.pr}: ${err instanceof Error ? err.message : String(err)}` }));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function noteFor(report: PrReport, forge: PrForge | undefined): string {
|
|
207
|
+
return renderPrNote(report, {
|
|
208
|
+
limit: forge?.kind === "gitlab" ? GITLAB_NOTE_LIMIT : GITHUB_COMMENT_LIMIT,
|
|
209
|
+
approver: forge ? forgePrincipalOf(forge.kind, forge.host, "<your-login>") : "<you>",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function printMembers(report: PrReport): void {
|
|
214
|
+
for (const m of report.members) {
|
|
215
|
+
const c = m.counts;
|
|
216
|
+
console.error(` ${m.member.padEnd(20)} ${m.status.padEnd(12)} create ${c.create} update ${c.update} replace ${c.replace} delete ${c.delete}${m.error ? ` ${m.error}` : ""}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async function finish(ctx: CommandContext, p: Prepared, report: PrReport): Promise<void> {
|
|
221
|
+
const note = noteFor(report, p.forge);
|
|
222
|
+
writeOutputs(ctx, report, note);
|
|
223
|
+
await publish(p.forge, report, note);
|
|
224
|
+
if (ctx.args.json) console.log(JSON.stringify(report, null, 2));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** chant components pr-plan --base <ref> --pr <n> [--env <env>] [--gate <name>] [--forge <kind>] [--output <dir>] [--json] */
|
|
228
|
+
export async function runComponentsPrPlan(ctx: CommandContext): Promise<number> {
|
|
229
|
+
if (ctx.args.pr === undefined) {
|
|
230
|
+
return fail("pr-plan needs the pull or merge request: --pr <n>", "Its approval is recorded under op pr-<n>, so one pull request's approval never answers another's.");
|
|
231
|
+
}
|
|
232
|
+
const p = await prepare(ctx, "plan");
|
|
233
|
+
if (typeof p === "number") return p;
|
|
234
|
+
const op = prOp(ctx.args.pr);
|
|
235
|
+
|
|
236
|
+
let approval: PrApproval = { status: "pending" };
|
|
237
|
+
if (p.plan.order.length > 0) {
|
|
238
|
+
try {
|
|
239
|
+
approval = approvalOf(await decidePrGate(readOnlyLedger(gitGateLedgerPort()), { op, gate: p.gate, digest: p.set.doc.digest }));
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error(formatWarning({ message: `could not read the gate ledger, so the approval reads as pending: ${err instanceof Error ? err.message : String(err)}` }));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const status = p.plan.order.length === 0 ? "nothing" : p.set.failed ? "plan-failed" : "planned";
|
|
245
|
+
const report = prReport({
|
|
246
|
+
stage: "plan",
|
|
247
|
+
pr: ctx.args.pr,
|
|
248
|
+
env: p.env,
|
|
249
|
+
base: p.base,
|
|
250
|
+
head: p.head,
|
|
251
|
+
op,
|
|
252
|
+
gate: p.gate,
|
|
253
|
+
plan: p.plan,
|
|
254
|
+
signal: p.signal,
|
|
255
|
+
set: p.set,
|
|
256
|
+
approval,
|
|
257
|
+
status,
|
|
258
|
+
});
|
|
259
|
+
await finish(ctx, p, report);
|
|
260
|
+
|
|
261
|
+
console.error(formatInfo(`pr-plan: ${report.members.length} member(s), ${status}`));
|
|
262
|
+
printMembers(report);
|
|
263
|
+
if (status === "planned") {
|
|
264
|
+
console.error(formatInfo(`plan : ${report.digest}`));
|
|
265
|
+
console.error(formatInfo(approval.status === "approved" ? `approved by ${(approval.approvedBy ?? []).join(", ")}` : `approve : ${prApproveCommand(report)}`));
|
|
266
|
+
}
|
|
267
|
+
return status === "plan-failed" ? 1 : 0;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** chant components pr-apply --base <ref> [--pr <n>] [--env <env>] [--gate <name>] [--forge <kind>] [--require-review] [--output <dir>] [--json] */
|
|
271
|
+
export async function runComponentsPrApply(ctx: CommandContext): Promise<number> {
|
|
272
|
+
const { args } = ctx;
|
|
273
|
+
if (args.requireReview && !args.forge) return fail("--require-review reads the pull request's reviews, so it needs --forge <kind>");
|
|
274
|
+
const p = await prepare(ctx, "apply");
|
|
275
|
+
if (typeof p === "number") return p;
|
|
276
|
+
|
|
277
|
+
let pr: number | null = args.pr ?? null;
|
|
278
|
+
if (pr === null && p.forge && p.plan.order.length > 0) {
|
|
279
|
+
try {
|
|
280
|
+
pr = await p.forge.pullRequestFor(p.head);
|
|
281
|
+
} catch (err) {
|
|
282
|
+
return fail(`could not ask ${p.forge.kind} which pull request merged ${p.head}: ${err instanceof Error ? err.message : String(err)}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const op = pr === null ? "pr-unknown" : prOp(pr);
|
|
286
|
+
const base = { stage: "apply" as const, pr, env: p.env, base: p.base, head: p.head, op, gate: p.gate, plan: p.plan, signal: p.signal, set: p.set };
|
|
287
|
+
|
|
288
|
+
const stop = async (report: PrReport, code: number): Promise<number> => {
|
|
289
|
+
await finish(ctx, p, report);
|
|
290
|
+
console.error((code === 0 ? formatInfo : (m: string) => formatWarning({ message: m }))(`pr-apply: ${report.status}${report.refusal ? ` (${report.refusal})` : ""}`));
|
|
291
|
+
if (report.message) console.error(report.message);
|
|
292
|
+
printMembers(report);
|
|
293
|
+
return code;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
if (p.plan.order.length === 0) {
|
|
297
|
+
return stop(prReport({ ...base, approval: { status: "pending" }, status: "nothing" }), 0);
|
|
298
|
+
}
|
|
299
|
+
if (pr === null) {
|
|
300
|
+
return stop(
|
|
301
|
+
prReport({
|
|
302
|
+
...base,
|
|
303
|
+
approval: { status: "pending" },
|
|
304
|
+
status: "refused",
|
|
305
|
+
refusal: "no-pull-request",
|
|
306
|
+
message: `No pull request merged ${p.head}, so no approval answers for this change. Nothing was applied. Pass --pr <n>, or land the change through a pull request.`,
|
|
307
|
+
}),
|
|
308
|
+
GATED_EXIT_CODE,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
if (p.set.failed) {
|
|
312
|
+
return stop(
|
|
313
|
+
prReport({
|
|
314
|
+
...base,
|
|
315
|
+
approval: { status: "pending" },
|
|
316
|
+
status: "plan-failed",
|
|
317
|
+
message: "A member failed to plan, so there is no plan to compare with the approved one. Nothing was applied.",
|
|
318
|
+
}),
|
|
319
|
+
1,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const check = await decidePrGate(gitGateLedgerPort(), {
|
|
324
|
+
op,
|
|
325
|
+
gate: p.gate,
|
|
326
|
+
digest: p.set.doc.digest,
|
|
327
|
+
description: `pull request #${pr}: ${p.plan.order.join(", ")}`,
|
|
328
|
+
});
|
|
329
|
+
const approval = approvalOf(check);
|
|
330
|
+
if (!check.satisfied) {
|
|
331
|
+
const partial = { ...base, approval, status: "refused" as const };
|
|
332
|
+
const report = approval.status === "changed"
|
|
333
|
+
? prReport({ ...partial, refusal: "plan-changed", message: describePlanChanged({ op, gate: p.gate, digest: p.set.doc.digest, approval }) })
|
|
334
|
+
: prReport({
|
|
335
|
+
...partial,
|
|
336
|
+
refusal: "not-approved",
|
|
337
|
+
message: `No approval stands for this plan, so nothing was applied. Approve it: ${prApproveCommand({ op, gate: p.gate, digest: p.set.doc.digest })}; then run the apply again.`,
|
|
338
|
+
});
|
|
339
|
+
return stop(report, GATED_EXIT_CODE);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (args.requireReview && p.forge) {
|
|
343
|
+
let reviewers: string[];
|
|
344
|
+
try {
|
|
345
|
+
reviewers = (await p.forge.approvers(pr)).map((login) => p.forge!.principalOf(login));
|
|
346
|
+
} catch (err) {
|
|
347
|
+
return fail(`could not read the reviews of #${pr}: ${err instanceof Error ? err.message : String(err)}`);
|
|
348
|
+
}
|
|
349
|
+
const strangers = approversWithoutReview(approval.approvedBy ?? [], reviewers);
|
|
350
|
+
if (strangers.length > 0) {
|
|
351
|
+
return stop(
|
|
352
|
+
prReport({
|
|
353
|
+
...base,
|
|
354
|
+
approval,
|
|
355
|
+
status: "refused",
|
|
356
|
+
refusal: "not-a-reviewer",
|
|
357
|
+
message:
|
|
358
|
+
`The plan is approved by ${strangers.join(", ")}, who ${strangers.length === 1 ? "has" : "have"} no approving review on #${pr}` +
|
|
359
|
+
` (approving reviews: ${reviewers.join(", ") || "none"}). Nothing was applied. ` +
|
|
360
|
+
`An approval counts when it names the reviewer the way the forge does: ${p.forge.principalOf("<login>")}.`,
|
|
361
|
+
}),
|
|
362
|
+
GATED_EXIT_CODE,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const applied = await applyPrSet({ components: p.components, plan: p.plan, registry: p.registry, env: p.env, set: p.set });
|
|
368
|
+
await recordAutoReleasesForRun(applied.run.results, p.env, `${op}-${Date.now()}`, resolveAutoReleaseDisabled(p.config, args.noReleaseRecord));
|
|
369
|
+
const report = prReport({ ...base, approval, status: applied.status, members: applied.members });
|
|
370
|
+
const code = await stop(report, applied.status === "applied" ? 0 : 1);
|
|
371
|
+
if (applied.status === "applied") console.error(formatSuccess(`applied the plan ${report.digest} approved by ${(approval.approvedBy ?? []).join(", ")}`));
|
|
372
|
+
return code;
|
|
373
|
+
}
|
|
@@ -424,6 +424,30 @@ describe("runOp: a steward's turn (#2750)", () => {
|
|
|
424
424
|
expect(acquireStewardTurnMock).not.toHaveBeenCalled();
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
+
test("fountain form with run.on: fountain and no flag: runs on fountain like --on fountain (#2523)", async () => {
|
|
428
|
+
const runtime = {
|
|
429
|
+
name: "fountain",
|
|
430
|
+
start: vi.fn(async (op: { name: string }) => ({
|
|
431
|
+
op: op.name,
|
|
432
|
+
runId: "f-1",
|
|
433
|
+
result: async () => ({ op: op.name, runId: "f-1", state: "completed" as const, startedAt: "t", endedAt: "t" }),
|
|
434
|
+
})),
|
|
435
|
+
status: vi.fn(), log: vi.fn(), list: vi.fn(), cancel: vi.fn(),
|
|
436
|
+
};
|
|
437
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([localOp("release", [])]), errors: [] });
|
|
438
|
+
discoverStewardsMock.mockResolvedValueOnce(stewardOwning("release", "box-steward", "fountain"));
|
|
439
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["fountain"], run: { on: "fountain" } } });
|
|
440
|
+
makeStdoutSpy();
|
|
441
|
+
const exit = await runOp({
|
|
442
|
+
args: makeArgs({ path: "release" }),
|
|
443
|
+
plugins: [{ name: "fountain", opRuntime: runtime } as never], serializers: [],
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
expect(exit).toBe(0);
|
|
447
|
+
expect(runtime.start).toHaveBeenCalledTimes(1);
|
|
448
|
+
expect(acquireStewardTurnMock).not.toHaveBeenCalled();
|
|
449
|
+
});
|
|
450
|
+
|
|
427
451
|
test("local form, the turn lease's own acquire throws (a stale .lock): refused as a lease error, not an uncaught exception, and nothing runs", async () => {
|
|
428
452
|
discoverOpsMock.mockResolvedValue({
|
|
429
453
|
ops: new Map([localOp("release", [{ kind: "activity", fn: "shellCmd", args: { cmd: "true" } }])]),
|
|
@@ -899,6 +923,93 @@ describe("run subcommands on the resolved runtime", () => {
|
|
|
899
923
|
expect(stderr.join("\n")).toContain('lexicon "plain" does not host Op runs');
|
|
900
924
|
});
|
|
901
925
|
|
|
926
|
+
test("run.on in chant.config.ts is the default runtime when --on is not given (#2523)", async () => {
|
|
927
|
+
const runtime = makeStubRuntime();
|
|
928
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
929
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub"], run: { on: "stub" } } });
|
|
930
|
+
makeStdoutSpy();
|
|
931
|
+
makeStderrSpy();
|
|
932
|
+
const ctx = (over: Partial<ParsedArgs>) => ({ args: makeArgs(over), plugins: [stubPlugin(runtime)], serializers: [] });
|
|
933
|
+
|
|
934
|
+
expect(await runOp(ctx({ path: "hello" }))).toBe(0);
|
|
935
|
+
expect(await runOpStatus(ctx({ extraPositional: "hello" }))).toBe(0);
|
|
936
|
+
expect(await runOpLog(ctx({ extraPositional: "hello" }))).toBe(0);
|
|
937
|
+
expect(await runOpList(ctx({}))).toBe(0);
|
|
938
|
+
expect(runtime.start).toHaveBeenCalledTimes(1);
|
|
939
|
+
expect(runtime.status).toHaveBeenCalledWith("hello");
|
|
940
|
+
expect(runtime.log).toHaveBeenCalledTimes(1);
|
|
941
|
+
expect(runtime.list).toHaveBeenCalledTimes(1);
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
test("--on local overrides run.on and runs on the built-in runtime (#2523)", async () => {
|
|
945
|
+
const runtime = makeStubRuntime();
|
|
946
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
947
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub"], run: { on: "stub" } } });
|
|
948
|
+
makeStdoutSpy();
|
|
949
|
+
makeStderrSpy();
|
|
950
|
+
await runOpList({ args: makeArgs({ on: "local" }), plugins: [stubPlugin(runtime)], serializers: [] });
|
|
951
|
+
expect(runtime.list).not.toHaveBeenCalled();
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
test("run.on naming an unconfigured lexicon gets --on's refusal, naming run.on (#2523)", async () => {
|
|
955
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
956
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["aws"], run: { on: "nope" } } });
|
|
957
|
+
const stderr = makeStderrSpy();
|
|
958
|
+
const exit = await runOp({ args: makeArgs({ path: "hello" }), plugins: [], serializers: [] });
|
|
959
|
+
expect(exit).toBe(1);
|
|
960
|
+
expect(stderr.join("\n")).toContain('run.on "nope" in chant.config.ts: "nope" is not a configured lexicon');
|
|
961
|
+
expect(stderr.join("\n")).toContain("Configured lexicons: aws");
|
|
962
|
+
expect(stderr.join("\n")).toContain("--on local");
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
test("an explicit --on wins over run.on (#2523)", async () => {
|
|
966
|
+
const chosen = makeStubRuntime();
|
|
967
|
+
const other = makeStubRuntime();
|
|
968
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
969
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub", "other"], run: { on: "other" } } });
|
|
970
|
+
makeStdoutSpy();
|
|
971
|
+
makeStderrSpy();
|
|
972
|
+
const plugins = [stubPlugin(chosen), { name: "other", opRuntime: other } as never];
|
|
973
|
+
expect(await runOpList({ args: makeArgs({ on: "stub" }), plugins, serializers: [] })).toBe(0);
|
|
974
|
+
expect(chosen.list).toHaveBeenCalledTimes(1);
|
|
975
|
+
expect(other.list).not.toHaveBeenCalled();
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
test("run.on: local selects the built-in runtime (#2523)", async () => {
|
|
979
|
+
const runtime = makeStubRuntime();
|
|
980
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
981
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["stub"], run: { on: "local" } } });
|
|
982
|
+
makeStdoutSpy();
|
|
983
|
+
makeStderrSpy();
|
|
984
|
+
await runOpList({ args: makeArgs({}), plugins: [stubPlugin(runtime)], serializers: [] });
|
|
985
|
+
expect(runtime.list).not.toHaveBeenCalled();
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
test("an invalid run block is refused, not run locally (#2523)", async () => {
|
|
989
|
+
const { InvalidChantConfigError } = await vi.importActual<typeof import("../../config")>("../../config");
|
|
990
|
+
const runtime = makeStubRuntime();
|
|
991
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
992
|
+
loadChantConfigMock.mockRejectedValue(
|
|
993
|
+
new InvalidChantConfigError("Invalid chant config in /p/chant.config.ts: run.on: Expected string, received number", "run"),
|
|
994
|
+
);
|
|
995
|
+
const stderr = makeStderrSpy();
|
|
996
|
+
makeStdoutSpy();
|
|
997
|
+
expect(await runOpList({ args: makeArgs({}), plugins: [stubPlugin(runtime)], serializers: [] })).toBe(1);
|
|
998
|
+
expect(stderr.join("\n")).toContain("Invalid chant config in /p/chant.config.ts: run.on");
|
|
999
|
+
expect(runtime.list).not.toHaveBeenCalled();
|
|
1000
|
+
// --on local still runs: the flag needs nothing from the config.
|
|
1001
|
+
expect(await runOpList({ args: makeArgs({ on: "local" }), plugins: [stubPlugin(runtime)], serializers: [] })).toBe(0);
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
test("run.on naming a lexicon with no opRuntime gets --on's refusal, naming run.on (#2523)", async () => {
|
|
1005
|
+
discoverOpsMock.mockResolvedValue({ ops: new Map([makeOp("hello")]), errors: [] });
|
|
1006
|
+
loadChantConfigMock.mockResolvedValue({ config: { lexicons: ["plain"], run: { on: "plain" } } });
|
|
1007
|
+
const stderr = makeStderrSpy();
|
|
1008
|
+
const exit = await runOp({ args: makeArgs({ path: "hello" }), plugins: [{ name: "plain" } as never], serializers: [] });
|
|
1009
|
+
expect(exit).toBe(1);
|
|
1010
|
+
expect(stderr.join("\n")).toContain('run.on "plain" in chant.config.ts: lexicon "plain" does not host Op runs');
|
|
1011
|
+
});
|
|
1012
|
+
|
|
902
1013
|
test("--components on a runtime that cannot host them → one line, exit 1", async () => {
|
|
903
1014
|
const runtime = makeStubRuntime();
|
|
904
1015
|
const stderr = makeStderrSpy();
|
package/src/cli/handlers/run.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { lexiconNames } from "../../lexicon-module";
|
|
2
|
-
import { resolve, dirname } from "node:path";
|
|
2
|
+
import { resolve, dirname, basename } from "node:path";
|
|
3
3
|
import { writeFileSync, mkdirSync, readFileSync } from "node:fs";
|
|
4
|
-
import { loadChantConfig, resolveAutoReleaseDisabled, type ChantConfig } from "../../config";
|
|
4
|
+
import { loadChantConfig, resolveAutoReleaseDisabled, InvalidChantConfigError, type ChantConfig } from "../../config";
|
|
5
5
|
import { discoverOps, discoverStewards } from "../../op/discover";
|
|
6
6
|
import { stewardWorkHolder } from "../../op/work-lease-run";
|
|
7
7
|
import type { OpConfig } from "../../op/types";
|
|
@@ -108,10 +108,12 @@ function refuseDurableComponentSubcommand(what: string, hint: string): number {
|
|
|
108
108
|
/**
|
|
109
109
|
* Resolve the one runtime this invocation talks to.
|
|
110
110
|
*
|
|
111
|
-
* `--on <name>` picks the named lexicon's `opRuntime` (`../../lexicon.ts`)
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
111
|
+
* `--on <name>` picks the named lexicon's `opRuntime` (`../../lexicon.ts`).
|
|
112
|
+
* Without it, `run.on` in `chant.config.ts` does (#2523), and without either,
|
|
113
|
+
* core's built-in `local` provider runs the Op in this process. `local`, from
|
|
114
|
+
* either place, names the built-in provider. Every `chant run` subcommand goes
|
|
115
|
+
* through whichever comes back, so there is one dispatch path rather than a
|
|
116
|
+
* branch per runtime.
|
|
115
117
|
*
|
|
116
118
|
* A lexicon already loaded into the command context wins the lookup — that is
|
|
117
119
|
* how a test hands in a stub, and how a command that loaded plugins for its
|
|
@@ -121,22 +123,20 @@ function refuseDurableComponentSubcommand(what: string, hint: string): number {
|
|
|
121
123
|
*
|
|
122
124
|
* Returns `undefined` after printing an actionable error — an unconfigured
|
|
123
125
|
* name is answered with the configured list, a configured lexicon that hosts
|
|
124
|
-
* nothing is named outright.
|
|
126
|
+
* nothing is named outright. A `run.on` default gets the same messages as
|
|
127
|
+
* `--on`, labelled `run.on` and the config file instead of `--on`.
|
|
125
128
|
*/
|
|
126
129
|
async function resolveOpRuntime(ctx: CommandContext): Promise<OpRuntimeProvider | undefined> {
|
|
127
|
-
const
|
|
130
|
+
const choice = await chooseOpRuntime(ctx);
|
|
131
|
+
if (!choice) return undefined;
|
|
132
|
+
const { on, source, configured } = choice;
|
|
128
133
|
if (!on || on === "local") return createLocalOpRuntime({ projectPath: resolve(".") });
|
|
129
134
|
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
configured = lexiconNames((await loadChantConfig(resolve("."))).config.lexicons ?? []);
|
|
137
|
-
} catch {
|
|
138
|
-
// No/unreadable chant.config.ts — the error below says so by listing nothing.
|
|
139
|
-
}
|
|
135
|
+
// How the error names the choice, and how to get the built-in runtime back.
|
|
136
|
+
const label = source === "flag" ? `--on ${on}` : `run.on "${on}" in ${choice.configFile}`;
|
|
137
|
+
const fallback = source === "flag"
|
|
138
|
+
? "Omit --on to run on the built-in local runtime."
|
|
139
|
+
: `Fix \`run.on\` in ${choice.configFile}, or pass --on local to run on the built-in local runtime.`;
|
|
140
140
|
|
|
141
141
|
let plugin = ctx.plugins.find((p) => p.name === on);
|
|
142
142
|
if (!plugin && configured.includes(on)) {
|
|
@@ -146,18 +146,18 @@ async function resolveOpRuntime(ctx: CommandContext): Promise<OpRuntimeProvider
|
|
|
146
146
|
if (!plugin) {
|
|
147
147
|
const known = [...new Set([...ctx.plugins.map((p) => p.name), ...configured])];
|
|
148
148
|
console.error(formatError({
|
|
149
|
-
message:
|
|
149
|
+
message: `${label}: "${on}" is not a configured lexicon`,
|
|
150
150
|
hint: known.length > 0
|
|
151
|
-
? `Configured lexicons: ${known.join(", ")}.
|
|
152
|
-
:
|
|
151
|
+
? `Configured lexicons: ${known.join(", ")}. ${fallback}`
|
|
152
|
+
: `chant.config.ts configures no lexicons. ${fallback}`,
|
|
153
153
|
}));
|
|
154
154
|
return undefined;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
if (!plugin.opRuntime) {
|
|
158
158
|
console.error(formatError({
|
|
159
|
-
message:
|
|
160
|
-
hint:
|
|
159
|
+
message: `${label}: lexicon "${on}" does not host Op runs`,
|
|
160
|
+
hint: `It declares no opRuntime. ${fallback}`,
|
|
161
161
|
}));
|
|
162
162
|
return undefined;
|
|
163
163
|
}
|
|
@@ -165,6 +165,64 @@ async function resolveOpRuntime(ctx: CommandContext): Promise<OpRuntimeProvider
|
|
|
165
165
|
return plugin.opRuntime;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
/** Which runtime name an invocation asked for, and where the name came from. */
|
|
169
|
+
interface OpRuntimeChoice {
|
|
170
|
+
/** The runtime name; `undefined` or `"local"` is the built-in runtime. */
|
|
171
|
+
on: string | undefined;
|
|
172
|
+
/** `flag` for `--on`, `config` for `run.on`, `default` when neither named one. */
|
|
173
|
+
source: "flag" | "config" | "default";
|
|
174
|
+
/** The lexicons `chant.config.ts` configures. */
|
|
175
|
+
configured: string[];
|
|
176
|
+
/** The config file's name, for messages about `run.on`. */
|
|
177
|
+
configFile: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The runtime name `--on`, then `run.on` in `chant.config.ts` (#2523), then
|
|
182
|
+
* the built-in default pick, without loading any lexicon.
|
|
183
|
+
*
|
|
184
|
+
* Reads the configured list straight from `chant.config.ts` rather than
|
|
185
|
+
* through `resolveProjectLexicons`: `--on` names a *configured* lexicon, and
|
|
186
|
+
* that helper's fallback is a source scan of the whole project, which is a
|
|
187
|
+
* long wait to be told a name is wrong.
|
|
188
|
+
*
|
|
189
|
+
* A config that fails to load leaves the flag's choice alone, as before. With
|
|
190
|
+
* no flag, a config whose `run` block is invalid is refused (printed, then
|
|
191
|
+
* `undefined`): running the Op locally would hide that the project asked for
|
|
192
|
+
* another runtime. Any other load failure falls back to the built-in runtime,
|
|
193
|
+
* which is what a project with no `run.on` got before. `quiet` skips printing
|
|
194
|
+
* that refusal, for a caller that only peeks at the choice and leaves the
|
|
195
|
+
* reporting to {@link resolveOpRuntime}.
|
|
196
|
+
*/
|
|
197
|
+
async function chooseOpRuntime(ctx: CommandContext, quiet = false): Promise<OpRuntimeChoice | undefined> {
|
|
198
|
+
const flag = ctx.args.on;
|
|
199
|
+
if (flag === "local") return { on: "local", source: "flag", configured: [], configFile: "chant.config.ts" };
|
|
200
|
+
|
|
201
|
+
let configured: string[] = [];
|
|
202
|
+
let configuredOn: string | undefined;
|
|
203
|
+
let configFile = "chant.config.ts";
|
|
204
|
+
try {
|
|
205
|
+
const { config, configPath } = await loadChantConfig(resolve("."));
|
|
206
|
+
configured = lexiconNames(config.lexicons ?? []);
|
|
207
|
+
configuredOn = config.run?.on;
|
|
208
|
+
if (configPath) configFile = basename(configPath);
|
|
209
|
+
} catch (err) {
|
|
210
|
+
if (!flag && err instanceof InvalidChantConfigError && err.key === "run") {
|
|
211
|
+
if (quiet) return undefined;
|
|
212
|
+
console.error(formatError({
|
|
213
|
+
message: err.message,
|
|
214
|
+
hint: "`run.on` names the runtime that hosts this project's Op runs: a configured lexicon with an opRuntime, or \"local\". Fix it, or pass --on to pick the runtime for this run.",
|
|
215
|
+
}));
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
// No/unreadable chant.config.ts: an `--on` error says so by listing nothing.
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (flag) return { on: flag, source: "flag", configured, configFile };
|
|
222
|
+
if (configuredOn) return { on: configuredOn, source: "config", configured, configFile };
|
|
223
|
+
return { on: undefined, source: "default", configured, configFile };
|
|
224
|
+
}
|
|
225
|
+
|
|
168
226
|
/** An ISO-8601 instant trimmed to what a table cell has room for. */
|
|
169
227
|
function shortInstant(iso: string | undefined): string {
|
|
170
228
|
return iso ? iso.slice(0, 19).replace("T", " ") : "—";
|
|
@@ -395,6 +453,8 @@ export async function runOpApprove(ctx: CommandContext): Promise<number> {
|
|
|
395
453
|
note: ctx.args.note,
|
|
396
454
|
url: ctx.args.url,
|
|
397
455
|
plan: ctx.args.plan,
|
|
456
|
+
...(ctx.args.sign !== undefined ? { sign: ctx.args.sign } : {}),
|
|
457
|
+
...(ctx.args.relayedBy !== undefined ? { relayedBy: ctx.args.relayedBy } : {}),
|
|
398
458
|
});
|
|
399
459
|
if (!outcome.ok) return 1;
|
|
400
460
|
|
|
@@ -582,7 +642,9 @@ async function stewardTurnGate(opName: string, ctx: CommandContext): Promise<Ste
|
|
|
582
642
|
const form = stewardFormFor(owner, env);
|
|
583
643
|
|
|
584
644
|
if (form === "fountain") {
|
|
585
|
-
|
|
645
|
+
// `run.on: "fountain"` asks for the steward's thread as much as the flag
|
|
646
|
+
// does (#2523).
|
|
647
|
+
if ((await chooseOpRuntime(ctx, true))?.on === "fountain") return { ok: true };
|
|
586
648
|
return {
|
|
587
649
|
ok: false,
|
|
588
650
|
message: `Op "${opName}" is one of steward "${owner.name}"'s Ops, which runs on fountain in environment "${env}"`,
|