@intentius/chant 0.100.0 → 0.102.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/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/build.d.ts +6 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/cli/build-options.d.ts +2 -0
- package/dist/cli/build-options.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/dev.d.ts.map +1 -1
- 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 +9 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- 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/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 +9 -1
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +33 -2
- 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/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out.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/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/composite.d.ts.map +1 -1
- package/dist/config.d.ts +30 -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/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/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 +78 -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 +15 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -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-digest.d.ts +26 -5
- package/dist/lifecycle/plan-digest.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 +4 -4
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +12 -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/decide.d.ts.map +1 -1
- package/dist/op/activities/index.d.ts +1 -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/activities/propose-upgrade.d.ts +2 -0
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +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.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.map +1 -1
- 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/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 +3 -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/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 +8 -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/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/serializer.d.ts +8 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +77 -0
- package/dist/telemetry-attribution.d.ts.map +1 -0
- package/dist/terraform/emit-source.d.ts.map +1 -1
- 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 +88 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +73 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/changes-cli.d.ts.map +1 -1
- package/dist/workspace/changes.d.ts +8 -1
- 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/links.d.ts +1 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/live.d.ts +40 -0
- package/dist/workspace/checks/live.d.ts.map +1 -0
- package/dist/workspace/checks.d.ts +26 -2
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +73 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/conformance/index.d.ts +67 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +12 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +368 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +1 -1
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/declaration.d.ts +119 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +368 -4
- package/dist/workspace/export-cli.d.ts +12 -0
- package/dist/workspace/export-cli.d.ts.map +1 -0
- package/dist/workspace/export.d.ts +145 -0
- package/dist/workspace/export.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/import.d.ts +73 -0
- package/dist/workspace/import.d.ts.map +1 -0
- 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 +8 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +149 -5
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +24 -6
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lineage-adopt-cli.d.ts +15 -0
- package/dist/workspace/lineage-adopt-cli.d.ts.map +1 -0
- package/dist/workspace/lineage-adopt.d.ts +106 -0
- package/dist/workspace/lineage-adopt.d.ts.map +1 -0
- package/dist/workspace/lineage-check.d.ts +9 -2
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-cli.d.ts +6 -1
- package/dist/workspace/lineage-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-hash-index.d.ts +110 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -0
- package/dist/workspace/lineage-init.d.ts +10 -0
- package/dist/workspace/lineage-init.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +149 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.d.ts +15 -3
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-provenance.d.ts +18 -0
- package/dist/workspace/lineage-provenance.d.ts.map +1 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts +2 -0
- package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +30 -1
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/lineage-versions.d.ts +116 -0
- package/dist/workspace/lineage-versions.d.ts.map +1 -0
- package/dist/workspace/links.d.ts +31 -5
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/ls-generated.d.ts +37 -0
- package/dist/workspace/ls-generated.d.ts.map +1 -0
- package/dist/workspace/ls.d.ts +4 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/nested-graph.d.ts +56 -0
- package/dist/workspace/nested-graph.d.ts.map +1 -0
- package/dist/workspace/nesting.d.ts +21 -0
- package/dist/workspace/nesting.d.ts.map +1 -0
- package/dist/workspace/pin-cli.d.ts +10 -0
- package/dist/workspace/pin-cli.d.ts.map +1 -0
- package/dist/workspace/pin-integrity.d.ts +51 -0
- package/dist/workspace/pin-integrity.d.ts.map +1 -0
- 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 +47 -3
- 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 +7 -11
- 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 +57 -2
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +5 -2
- 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 +23 -4
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +58 -5
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/returns.d.ts +129 -0
- package/dist/workspace/returns.d.ts.map +1 -0
- package/dist/workspace/runs-cli.d.ts +164 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +423 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/status-gates.d.ts +15 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +10 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +52 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/template-manifest.d.ts +11 -3
- package/dist/workspace/template-manifest.d.ts.map +1 -1
- 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 +8 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/dsse.d.ts +58 -0
- package/dist/workspace/trust/dsse.d.ts.map +1 -0
- package/dist/workspace/trust/evidence-cli.d.ts +66 -0
- package/dist/workspace/trust/evidence-cli.d.ts.map +1 -0
- package/dist/workspace/trust/evidence.d.ts +93 -0
- package/dist/workspace/trust/evidence.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +54 -1
- package/dist/workspace/trust/policy.d.ts.map +1 -1
- package/dist/workspace/trust/provenance.d.ts +21 -1
- package/dist/workspace/trust/provenance.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts +132 -0
- package/dist/workspace/trust/rotation.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +33 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/signers-cli.d.ts +49 -0
- package/dist/workspace/trust/signers-cli.d.ts.map +1 -0
- package/dist/workspace/trust/ssh-commit.d.ts +12 -0
- package/dist/workspace/trust/ssh-commit.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts +13 -0
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify.d.ts +15 -0
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- 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.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-scope.d.ts +259 -0
- package/dist/workspace/write-scope.d.ts.map +1 -0
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/build.ts +8 -0
- package/src/cli/build-options.ts +4 -1
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/build.ts +2 -0
- 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 +87 -1
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +69 -25
- 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/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +6 -6
- package/src/cli/handlers/fan-out.ts +2 -1
- package/src/cli/handlers/graph.test.ts +42 -0
- package/src/cli/handlers/graph.ts +22 -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.ts +88 -4
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +85 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +33 -0
- package/src/cli/main.ts +168 -17
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -4
- package/src/cli/registry.ts +33 -2
- package/src/cli/serve-mcp-workspace.test.ts +1 -1
- 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/release-wiring.test.ts +5 -1
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/components/fan-out-output.test.ts +1 -1
- package/src/components/fan-out.test.ts +1 -1
- package/src/components/promote.test.ts +1 -1
- package/src/config.test.ts +21 -0
- package/src/config.ts +27 -0
- package/src/content-digest.test.ts +2 -2
- 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/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/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/lexicon.ts +79 -3
- package/src/lifecycle/gate-ledger.test.ts +14 -0
- package/src/lifecycle/gate-ledger.ts +18 -1
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/plan-digest.test.ts +54 -3
- package/src/lifecycle/plan-digest.ts +38 -8
- 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/op/activities/activity-contracts.ts +1 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/index.ts +3 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activities/propose-upgrade.ts +8 -5
- 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/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/gate-approval.test.ts +91 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +34 -8
- package/src/op/index.ts +3 -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/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 +8 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +73 -11
- package/src/provenance.ts +35 -0
- package/src/serializer.ts +9 -0
- package/src/telemetry-attribution.test.ts +91 -0
- package/src/telemetry-attribution.ts +145 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/agent-cli.ts +138 -0
- package/src/workspace/agent.schema.json +378 -0
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/box-factory.test.ts +320 -0
- package/src/workspace/box-factory.ts +103 -0
- package/src/workspace/changes-cli.ts +5 -0
- package/src/workspace/changes.schema.json +171 -1
- package/src/workspace/changes.ts +61 -4
- package/src/workspace/check-live.test.ts +192 -0
- package/src/workspace/check.schema.json +64 -0
- package/src/workspace/checks/boxes.test.ts +2 -0
- package/src/workspace/checks/links.ts +23 -2
- package/src/workspace/checks/live.ts +113 -0
- package/src/workspace/checks.test.ts +2 -2
- package/src/workspace/checks.ts +49 -8
- package/src/workspace/compose-graph.test.ts +47 -0
- package/src/workspace/compose-graph.ts +127 -3
- package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +7 -1
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +5 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +27 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +95 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +132 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +48 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +108 -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 +578 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +35 -3
- package/src/workspace/conformance/index.mjs +30 -3
- package/src/workspace/conformance/index.ts +103 -15
- package/src/workspace/conformance/vitest.ts +44 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +131 -0
- package/src/workspace/conformance/writer.test.ts +156 -0
- package/src/workspace/conformance/writer.ts +880 -0
- package/src/workspace/decide.ts +7 -1
- package/src/workspace/declaration.schema.json +368 -4
- package/src/workspace/declaration.ts +270 -1
- package/src/workspace/declared-kinds.test.ts +33 -0
- package/src/workspace/evidence.schema.json +279 -0
- package/src/workspace/export-cli.ts +180 -0
- package/src/workspace/export-import.test.ts +282 -0
- package/src/workspace/export.ts +486 -0
- package/src/workspace/graph-cli.ts +51 -2
- package/src/workspace/graph-contract.test.ts +89 -4
- package/src/workspace/graph.schema.json +453 -1
- package/src/workspace/identity.test.ts +196 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/import.ts +325 -0
- package/src/workspace/intent-cli.ts +64 -10
- package/src/workspace/intent-record.schema.json +208 -0
- package/src/workspace/intent-record.ts +35 -1
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +718 -7
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +495 -32
- package/src/workspace/kinds.test.ts +5 -5
- package/src/workspace/kinds.ts +62 -33
- package/src/workspace/lineage-adopt-cli.ts +103 -0
- package/src/workspace/lineage-adopt.test.ts +552 -0
- package/src/workspace/lineage-adopt.ts +452 -0
- package/src/workspace/lineage-check.ts +26 -5
- package/src/workspace/lineage-cli.ts +12 -2
- package/src/workspace/lineage-hash-index.ts +305 -0
- package/src/workspace/lineage-init.test.ts +9 -0
- package/src/workspace/lineage-init.ts +29 -9
- package/src/workspace/lineage-lock.ts +54 -0
- package/src/workspace/lineage-migrations.test.ts +27 -0
- package/src/workspace/lineage-migrations.ts +44 -14
- package/src/workspace/lineage-provenance.ts +40 -0
- package/src/workspace/lineage-upgrade-cli.ts +9 -5
- package/src/workspace/lineage-upgrade.test.ts +92 -1
- package/src/workspace/lineage-upgrade.ts +111 -16
- package/src/workspace/lineage-versions.ts +348 -0
- package/src/workspace/links.test.ts +121 -2
- package/src/workspace/links.ts +97 -6
- package/src/workspace/ls-contract.test.ts +84 -1
- package/src/workspace/ls-generated.ts +111 -0
- package/src/workspace/ls.schema.json +19 -0
- package/src/workspace/ls.ts +8 -1
- package/src/workspace/member-commands.ts +3 -1
- package/src/workspace/nested-graph.test.ts +176 -0
- package/src/workspace/nested-graph.ts +169 -0
- package/src/workspace/nesting.ts +37 -0
- package/src/workspace/pin-cli.test.ts +71 -0
- package/src/workspace/pin-cli.ts +57 -0
- package/src/workspace/pin-integrity.test.ts +121 -0
- package/src/workspace/pin-integrity.ts +104 -0
- package/src/workspace/points-write.schema.json +2 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/read-contract.test.ts +24 -0
- package/src/workspace/reason-codes.test.ts +20 -2
- package/src/workspace/reason-codes.ts +53 -3
- package/src/workspace/record-sessions.ts +12 -14
- package/src/workspace/records-amend.schema.json +6 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +195 -22
- package/src/workspace/records-close.schema.json +7 -2
- package/src/workspace/records-close.ts +10 -2
- package/src/workspace/records-formats.test.ts +13 -5
- package/src/workspace/records-new.schema.json +6 -0
- package/src/workspace/records-review.schema.json +6 -0
- package/src/workspace/records-sessions.test.ts +23 -6
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.test.ts +65 -8
- package/src/workspace/records-write.ts +92 -6
- package/src/workspace/records.schema.json +127 -4
- package/src/workspace/records.ts +123 -5
- package/src/workspace/returns.ts +328 -0
- package/src/workspace/runs-cli.ts +381 -0
- package/src/workspace/runs-write.schema.json +583 -0
- package/src/workspace/runs.schema.json +810 -0
- package/src/workspace/runs.test.ts +242 -0
- package/src/workspace/runs.ts +709 -0
- package/src/workspace/signers.schema.json +206 -0
- package/src/workspace/status-contract.test.ts +5 -0
- package/src/workspace/status-gates.ts +24 -9
- package/src/workspace/status.schema.json +127 -2
- package/src/workspace/status.ts +21 -1
- package/src/workspace/symbols.ts +180 -0
- package/src/workspace/template-manifest.ts +22 -4
- 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/attestor.ts +15 -0
- package/src/workspace/trust/dsse.ts +134 -0
- package/src/workspace/trust/evidence-cli.ts +195 -0
- package/src/workspace/trust/evidence.test.ts +241 -0
- package/src/workspace/trust/evidence.ts +207 -0
- package/src/workspace/trust/policy.ts +110 -3
- package/src/workspace/trust/provenance.ts +41 -4
- package/src/workspace/trust/record-seal.test.ts +1 -1
- package/src/workspace/trust/rotation.test.ts +258 -0
- package/src/workspace/trust/rotation.ts +336 -0
- package/src/workspace/trust/seal.ts +63 -1
- package/src/workspace/trust/signers-cli.ts +178 -0
- package/src/workspace/trust/ssh-commit.ts +53 -4
- package/src/workspace/trust/test-repo.ts +18 -0
- package/src/workspace/trust/trust.test.ts +8 -2
- package/src/workspace/trust/verify-cli.ts +1 -0
- package/src/workspace/trust/verify.ts +22 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +133 -8
- package/src/workspace/work-evidence.schema.json +6 -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.ts +82 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-scope.test.ts +466 -0
- package/src/workspace/write-scope.ts +573 -0
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
|
@@ -97,6 +97,19 @@ function makeBuildResult(entitiesByLexicon: Record<string, string[]>): BuildResu
|
|
|
97
97
|
} as unknown as BuildResult;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* #3001 — a build holding one resource and one property-kind declarable that
|
|
102
|
+
* the resource inlines, the shape every grafana dashboard with exported panels
|
|
103
|
+
* has. Only the resource has a live counterpart of its own.
|
|
104
|
+
*/
|
|
105
|
+
function buildWithPropertyKind(lexicon: string): BuildResult {
|
|
106
|
+
const build = makeBuildResult({ [lexicon]: ["board"] });
|
|
107
|
+
const panel = { lexicon, entityType: `${lexicon}::Panel`, kind: "property", props: { title: "CPU" } };
|
|
108
|
+
build.entities.set("board", { lexicon, entityType: `${lexicon}::Board`, kind: "resource", props: { panels: [panel] } } as never);
|
|
109
|
+
build.entities.set("cpuPanel", panel as never);
|
|
110
|
+
return build;
|
|
111
|
+
}
|
|
112
|
+
|
|
100
113
|
const meta = (overrides: Partial<ResourceMetadata> = {}): ResourceMetadata => ({
|
|
101
114
|
type: "AWS::S3::Bucket",
|
|
102
115
|
status: "CREATE_COMPLETE",
|
|
@@ -537,6 +550,37 @@ describe("runLifecycleDiff --live", () => {
|
|
|
537
550
|
});
|
|
538
551
|
|
|
539
552
|
// #1014 — property-level drift, gated purely on the deep capability.
|
|
553
|
+
test("hands only resource-kind entities to describeResources and observeResourcesDeep (#3001)", async () => {
|
|
554
|
+
buildMock.mockResolvedValue(buildWithPropertyKind("graf"));
|
|
555
|
+
fetchLifecycleMock.mockResolvedValue(undefined);
|
|
556
|
+
readSnapshotMock.mockResolvedValue(null);
|
|
557
|
+
const seen: { thin?: string[]; deep?: string[] } = {};
|
|
558
|
+
const plugins: LexiconPlugin[] = [
|
|
559
|
+
createMockPlugin({
|
|
560
|
+
name: "graf",
|
|
561
|
+
describeResources: async (opts) => {
|
|
562
|
+
seen.thin = [...opts.entities.keys()];
|
|
563
|
+
return { board: meta({ type: "graf::Board", physicalId: "uid-1" }) };
|
|
564
|
+
},
|
|
565
|
+
observeResourcesDeep: async (opts) => {
|
|
566
|
+
seen.deep = [...opts.entities.keys()];
|
|
567
|
+
return deepObservation({ board: { type: "graf::Board", properties: { panels: [{ title: "CPU" }] } } });
|
|
568
|
+
},
|
|
569
|
+
}),
|
|
570
|
+
];
|
|
571
|
+
const exit = await runLifecycleDiff({
|
|
572
|
+
args: makeArgs({ path: "diff", extraPositional: "prod", live: true }),
|
|
573
|
+
plugins,
|
|
574
|
+
serializers: plugins.map((p) => p.serializer),
|
|
575
|
+
});
|
|
576
|
+
expect(exit).toBe(0);
|
|
577
|
+
expect(seen.thin).toEqual(["board"]);
|
|
578
|
+
expect(seen.deep).toEqual(["board"]);
|
|
579
|
+
const stdout = stdoutBuf.join("\n");
|
|
580
|
+
expect(stdout).not.toContain("cpuPanel");
|
|
581
|
+
expect(stdout).toContain("0 missing");
|
|
582
|
+
});
|
|
583
|
+
|
|
540
584
|
describe("deep observation (#1014)", () => {
|
|
541
585
|
const withDeep = (over: Parameters<typeof createMockPlugin>[0] = {}) =>
|
|
542
586
|
createMockPlugin({
|
|
@@ -872,6 +916,29 @@ describe("runLifecyclePlan", () => {
|
|
|
872
916
|
expect(stdoutBuf.join("\n")).toContain("bucket");
|
|
873
917
|
});
|
|
874
918
|
|
|
919
|
+
test("proposes no create for a property-kind declarable its parent inlines (#3001)", async () => {
|
|
920
|
+
buildMock.mockResolvedValue(buildWithPropertyKind("graf"));
|
|
921
|
+
let names: string[] = [];
|
|
922
|
+
const plugins: LexiconPlugin[] = [
|
|
923
|
+
createMockPlugin({
|
|
924
|
+
name: "graf",
|
|
925
|
+
describeResources: async (opts) => {
|
|
926
|
+
names = opts.entityNames;
|
|
927
|
+
return { board: meta({ type: "graf::Board", physicalId: "uid-1" }) };
|
|
928
|
+
},
|
|
929
|
+
}),
|
|
930
|
+
];
|
|
931
|
+
const exit = await runLifecyclePlan({
|
|
932
|
+
args: makeArgs({ path: "plan", extraPositional: "prod", json: true }),
|
|
933
|
+
plugins,
|
|
934
|
+
serializers: plugins.map((p) => p.serializer),
|
|
935
|
+
});
|
|
936
|
+
expect(exit).toBe(0);
|
|
937
|
+
expect(names).toEqual(["board"]);
|
|
938
|
+
const plan = JSON.parse(stdoutBuf.join("\n"));
|
|
939
|
+
expect(plan.entries.map((e: { name: string }) => e.name)).not.toContain("cpuPanel");
|
|
940
|
+
});
|
|
941
|
+
|
|
875
942
|
// #1983 — `--report markdown` emits the reviewer-facing projection instead
|
|
876
943
|
// of the human render, same as `--report gitlab-mr` swaps in the widget JSON.
|
|
877
944
|
test("--report markdown emits the markdown projection instead of the human render", async () => {
|
|
@@ -42,7 +42,7 @@ import { unknownEnvError, isProdLikeEnvironment } from "../../env";
|
|
|
42
42
|
import { planTeardown, executeTeardown, type TeardownPlan, type TeardownReport } from "../../lifecycle/teardown";
|
|
43
43
|
import { collectBuildRootContributors } from "../plugins";
|
|
44
44
|
import { applyLiveEndpoint } from "../../live-endpoint";
|
|
45
|
-
import {
|
|
45
|
+
import { isObservableDeclarable } from "../../declarable";
|
|
46
46
|
import { formatError, formatWarning, formatSuccess, formatBold } from "../format";
|
|
47
47
|
import type { CommandContext } from "../registry";
|
|
48
48
|
import type { LifecycleSnapshot } from "../../lifecycle/types";
|
|
@@ -812,13 +812,14 @@ async function runLifecycleDiffLive(args: LiveDiffArgs): Promise<LiveDiffOutcome
|
|
|
812
812
|
}
|
|
813
813
|
|
|
814
814
|
// Build per-lexicon entity index. Resource declarables only — outputs,
|
|
815
|
-
// parameters
|
|
815
|
+
// parameters, serializer directives and property-kind declarables (read
|
|
816
|
+
// inside their parent, #3001) have no live counterpart of their own, and a
|
|
816
817
|
// declared name the reader can never resolve reads as missing (see
|
|
817
818
|
// lifecycle/observe.ts).
|
|
818
819
|
const declared = new Set<string>();
|
|
819
820
|
const entities: DeclaredEntities = new Map();
|
|
820
821
|
for (const [name, entity] of args.buildResult.entities) {
|
|
821
|
-
if (entity.lexicon === lexiconName &&
|
|
822
|
+
if (entity.lexicon === lexiconName && isObservableDeclarable(entity)) {
|
|
822
823
|
declared.add(name);
|
|
823
824
|
// Path origins are carried across explicitly (#1443): this map is plain
|
|
824
825
|
// objects, and the symbol-keyed provenance channel does not survive it.
|
|
@@ -1289,11 +1290,11 @@ export async function runLifecyclePlan(ctx: CommandContext): Promise<number> {
|
|
|
1289
1290
|
// A receipt has no `props` payload of its own but is declared, diffed,
|
|
1290
1291
|
// and observed like any resource (#1832) — it joins the declared axis
|
|
1291
1292
|
// so its lexicon's observation can confirm presence or absence.
|
|
1292
|
-
if (entity.lexicon === lexiconName && (
|
|
1293
|
+
if (entity.lexicon === lexiconName && (isObservableDeclarable(entity) || isEffectReceipt(entity))) {
|
|
1293
1294
|
declared.add(name);
|
|
1294
1295
|
entities.set(name, {
|
|
1295
1296
|
entityType: entity.entityType,
|
|
1296
|
-
props: (
|
|
1297
|
+
props: (isObservableDeclarable(entity) && entity.props != null ? entity.props : {}) as Record<string, unknown>,
|
|
1297
1298
|
});
|
|
1298
1299
|
}
|
|
1299
1300
|
}
|
package/src/cli/handlers/misc.ts
CHANGED
|
@@ -324,6 +324,7 @@ export async function runImport(ctx: CommandContext): Promise<number> {
|
|
|
324
324
|
lexicon: "k8s",
|
|
325
325
|
output: args.output,
|
|
326
326
|
force: args.force,
|
|
327
|
+
parserOptions: args.parserOption,
|
|
327
328
|
});
|
|
328
329
|
printImportResult(result);
|
|
329
330
|
return result.success ? 0 : 1;
|
|
@@ -381,6 +382,7 @@ export async function runImport(ctx: CommandContext): Promise<number> {
|
|
|
381
382
|
output: ctx.args.output,
|
|
382
383
|
force: ctx.args.force,
|
|
383
384
|
lexicon: ctx.args.lexicon,
|
|
385
|
+
parserOptions: ctx.args.parserOption,
|
|
384
386
|
});
|
|
385
387
|
|
|
386
388
|
printImportResult(result);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { lexiconNames } from "../../lexicon-module";
|
|
10
10
|
import { loadChantConfig } from "../../config";
|
|
11
11
|
import { build } from "../../build";
|
|
12
|
-
import {
|
|
12
|
+
import { isObservableDeclarable } from "../../declarable";
|
|
13
13
|
import { collectBuildRootContributors, collectChangeSubscribers } from "../plugins";
|
|
14
14
|
import { discoverOps, discoverStewards } from "../../op/discover";
|
|
15
15
|
import { pickSteward, stewardBesideOf, stewardFormFor, stewardLeaseName, stewardTurnOps, DEFAULT_STEWARD_ENV } from "../../op/steward";
|
|
@@ -116,7 +116,7 @@ async function collectOperatorSubscribers(
|
|
|
116
116
|
// subscription may watch.
|
|
117
117
|
const entities = new Map<string, Map<string, { entityType: string; props: Record<string, unknown> }>>();
|
|
118
118
|
for (const [name, entity] of buildResult.entities) {
|
|
119
|
-
if (!
|
|
119
|
+
if (!isObservableDeclarable(entity)) continue;
|
|
120
120
|
let perLexicon = entities.get(entity.lexicon);
|
|
121
121
|
if (!perLexicon) entities.set(entity.lexicon, (perLexicon = new Map()));
|
|
122
122
|
perLexicon.set(name, {
|
|
@@ -902,6 +902,7 @@ export async function runApprove(ctx: CommandContext): Promise<number> {
|
|
|
902
902
|
allowSameOrigin: ctx.args.allowSameOrigin,
|
|
903
903
|
...(ctx.args.roles ? { roles: ctx.args.roles } : {}),
|
|
904
904
|
...(ctx.args.agent ? { agent: true } : {}),
|
|
905
|
+
...(ctx.args.sign !== undefined ? { sign: ctx.args.sign } : {}),
|
|
905
906
|
});
|
|
906
907
|
if (!outcome.ok) return 1;
|
|
907
908
|
|
|
@@ -959,6 +960,15 @@ export interface GateApprovalOptions {
|
|
|
959
960
|
* model-authored channel it is one whether or not this is set.
|
|
960
961
|
*/
|
|
961
962
|
agent?: boolean;
|
|
963
|
+
/**
|
|
964
|
+
* `--sign [<key file>]` (#3163, ws-080): seal the approval with an ssh key,
|
|
965
|
+
* a key file or true for git's `user.signingkey`. The seal attests the
|
|
966
|
+
* approver when the signers file at base lists the key for them, and a gate
|
|
967
|
+
* the declaration's `identity.gates` names counts only sealed approvals.
|
|
968
|
+
*/
|
|
969
|
+
sign?: string | true;
|
|
970
|
+
/** Where the workspace and the key file are looked up from. Defaults to the process's directory. */
|
|
971
|
+
cwd?: string;
|
|
962
972
|
/** Replaces the lexicon evaluator a gate policy is loaded from. For tests. */
|
|
963
973
|
evaluator?: GatePolicyEvaluator;
|
|
964
974
|
}
|
|
@@ -1047,7 +1057,7 @@ export async function recordGateApproval(
|
|
|
1047
1057
|
if (opts.plan !== undefined) {
|
|
1048
1058
|
if (!isPlanDigest(opts.plan)) {
|
|
1049
1059
|
console.error(formatError({
|
|
1050
|
-
message: `--plan must be a plan digest ("sha256:"
|
|
1060
|
+
message: `--plan must be a plan digest ("jcs1-sha256:" or "sha256:", then 64 hex characters), got "${opts.plan}"`,
|
|
1051
1061
|
hint: "Copy it from the gated run's `plan :` line, or from the pending-gate summary. It is not a plan file path.",
|
|
1052
1062
|
}));
|
|
1053
1063
|
return { ok: false };
|
|
@@ -1107,6 +1117,78 @@ export async function recordGateApproval(
|
|
|
1107
1117
|
...(opts.roles && opts.roles.length > 0 ? { roles: [...new Set(opts.roles)] } : {}),
|
|
1108
1118
|
};
|
|
1109
1119
|
|
|
1120
|
+
// #3163, ws-080: the declaration at base may require a checkable approver
|
|
1121
|
+
// (identity.attribution "identified") and a signed approval for this gate
|
|
1122
|
+
// (identity.gates). Both are judged before anything is written.
|
|
1123
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
1124
|
+
const identity = await import("../../workspace/identity");
|
|
1125
|
+
const { scopeSource } = await import("../../workspace/write-scope");
|
|
1126
|
+
const scope = scopeSource(cwd);
|
|
1127
|
+
try {
|
|
1128
|
+
identity.refuseUnidentified(scope, [resolvedBy], opts.actor !== undefined ? "--actor" : "the approver");
|
|
1129
|
+
} catch (err) {
|
|
1130
|
+
if (!(err instanceof identity.IdentityError)) throw err;
|
|
1131
|
+
console.error(formatError({
|
|
1132
|
+
message: `Gate "${gate}" on "${opName}" was not approved: ${err.message}`,
|
|
1133
|
+
hint: "Pass --actor <forge identity or signer>, as the surface that signed the person in maps them, for example --actor github:<login>.",
|
|
1134
|
+
}));
|
|
1135
|
+
return { ok: false };
|
|
1136
|
+
}
|
|
1137
|
+
const rule = identity.gateAdmissionFrom(scope, gate);
|
|
1138
|
+
if (rule && opts.sign === undefined) {
|
|
1139
|
+
console.error(formatError({
|
|
1140
|
+
message:
|
|
1141
|
+
`Gate "${gate}" needs a signed approval: chant.workspace.json at base names it in identity.gates` +
|
|
1142
|
+
(rule.requirement.class !== null ? `, from the class ${rule.requirement.class}` : "") +
|
|
1143
|
+
`, and this approval is not signed`,
|
|
1144
|
+
hint: `chant approve ${opName} ${gate} --actor <principal> --sign [<key file>], with a key ${scope.policy.signersPath} at base lists for that principal.`,
|
|
1145
|
+
}));
|
|
1146
|
+
return { ok: false };
|
|
1147
|
+
}
|
|
1148
|
+
const timestamp = new Date().toISOString();
|
|
1149
|
+
let seal: GateResolutionRecord["seal"];
|
|
1150
|
+
if (opts.sign !== undefined) {
|
|
1151
|
+
const { resolveSigningKey, sealGateApproval, SealError } = await import("../../workspace/trust/seal");
|
|
1152
|
+
try {
|
|
1153
|
+
const key = resolveSigningKey(opts.sign, cwd);
|
|
1154
|
+
try {
|
|
1155
|
+
seal = sealGateApproval(key.file, {
|
|
1156
|
+
op: opName,
|
|
1157
|
+
gate,
|
|
1158
|
+
...(environment !== undefined ? { environment } : {}),
|
|
1159
|
+
...(planDigest !== undefined ? { planDigest } : {}),
|
|
1160
|
+
resolvedBy,
|
|
1161
|
+
timestamp,
|
|
1162
|
+
});
|
|
1163
|
+
} finally {
|
|
1164
|
+
key.cleanup();
|
|
1165
|
+
}
|
|
1166
|
+
} catch (err) {
|
|
1167
|
+
if (!(err instanceof SealError)) throw err;
|
|
1168
|
+
console.error(formatError({ message: `Gate "${gate}" on "${opName}" was not approved: ${err.message}` }));
|
|
1169
|
+
return { ok: false };
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
if (rule) {
|
|
1173
|
+
const why = rule.refuses({
|
|
1174
|
+
op: opName,
|
|
1175
|
+
gate,
|
|
1176
|
+
...(environment !== undefined ? { environment } : {}),
|
|
1177
|
+
...(planDigest !== undefined ? { planDigest } : {}),
|
|
1178
|
+
resolvedBy,
|
|
1179
|
+
timestamp,
|
|
1180
|
+
seal,
|
|
1181
|
+
});
|
|
1182
|
+
if (why !== null) {
|
|
1183
|
+
console.error(formatError({
|
|
1184
|
+
message: `Gate "${gate}" on "${opName}" was not approved: ${why}`,
|
|
1185
|
+
hint: `identity.gates.${gate} in chant.workspace.json at base counts only an approval signed by a key ${scope.policy.signersPath} lists for the approver` +
|
|
1186
|
+
(rule.requirement.class !== null ? `, who holds the role of the class ${rule.requirement.class}` : "") + ".",
|
|
1187
|
+
}));
|
|
1188
|
+
return { ok: false };
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1110
1192
|
// #2508: a gate with a policy has it evaluated for this approval now, while
|
|
1111
1193
|
// the approver is known, against the context the gated run recorded. The
|
|
1112
1194
|
// decision is written next to the approval, so a pass can be traced to the
|
|
@@ -1148,7 +1230,8 @@ export async function recordGateApproval(
|
|
|
1148
1230
|
op: opName,
|
|
1149
1231
|
gate,
|
|
1150
1232
|
resolvedBy,
|
|
1151
|
-
timestamp
|
|
1233
|
+
timestamp,
|
|
1234
|
+
...(seal ? { seal } : {}),
|
|
1152
1235
|
approver,
|
|
1153
1236
|
...(policyDecision ? { policyDecision } : {}),
|
|
1154
1237
|
...(opts.note ? { note: opts.note } : {}),
|
|
@@ -1166,6 +1249,7 @@ export async function recordGateApproval(
|
|
|
1166
1249
|
console.error(formatSuccess(
|
|
1167
1250
|
`Gate "${gate}" on "${opName}" resolved by ${record.resolvedBy} at ${record.timestamp}` +
|
|
1168
1251
|
(record.url ? ` (${record.url})` : "") +
|
|
1252
|
+
(record.seal ? `, signed with ${record.seal.key}` : "") +
|
|
1169
1253
|
(pushed ? "" : " (local only — the push did not land)"),
|
|
1170
1254
|
));
|
|
1171
1255
|
if (record.planDigest) {
|
|
@@ -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,7 @@ 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 } : {}),
|
|
398
457
|
});
|
|
399
458
|
if (!outcome.ok) return 1;
|
|
400
459
|
|
|
@@ -582,7 +641,9 @@ async function stewardTurnGate(opName: string, ctx: CommandContext): Promise<Ste
|
|
|
582
641
|
const form = stewardFormFor(owner, env);
|
|
583
642
|
|
|
584
643
|
if (form === "fountain") {
|
|
585
|
-
|
|
644
|
+
// `run.on: "fountain"` asks for the steward's thread as much as the flag
|
|
645
|
+
// does (#2523).
|
|
646
|
+
if ((await chooseOpRuntime(ctx, true))?.on === "fountain") return { ok: true };
|
|
586
647
|
return {
|
|
587
648
|
ok: false,
|
|
588
649
|
message: `Op "${opName}" is one of steward "${owner.name}"'s Ops, which runs on fountain in environment "${env}"`,
|
|
@@ -15,7 +15,7 @@ import { collectEffectReceipts, isEffectReceipt, type EffectReceiptDeclaration }
|
|
|
15
15
|
import { evaluateScenario, type ScenarioBehaviourFixture, type ScenarioVerdict } from "../../lifecycle/scenario-eval";
|
|
16
16
|
import { validateBehaviourResult } from "../../behaviour-delta";
|
|
17
17
|
import { collectScenarios, type ScenarioDeclaration, type ScenarioGiven } from "../../lifecycle/scenario";
|
|
18
|
-
import {
|
|
18
|
+
import { isObservableDeclarable } from "../../declarable";
|
|
19
19
|
import { loadChantConfig } from "../../config";
|
|
20
20
|
import { unknownEnvError } from "../../env";
|
|
21
21
|
import { collectBuildRootContributors } from "../plugins";
|
|
@@ -281,7 +281,7 @@ async function evaluateOneScenario(
|
|
|
281
281
|
// and observed like any resource (#1832) — it joins the declared axis so
|
|
282
282
|
// its lexicon's fixture data can confirm presence, absence, or a hole,
|
|
283
283
|
// the same as `runLifecyclePlan` (lifecycle.ts:1184).
|
|
284
|
-
if (!
|
|
284
|
+
if (!isObservableDeclarable(entity) && !isEffectReceipt(entity)) continue;
|
|
285
285
|
if (!declaredByLexicon.has(entity.lexicon)) declaredByLexicon.set(entity.lexicon, new Set());
|
|
286
286
|
declaredByLexicon.get(entity.lexicon)!.add(name);
|
|
287
287
|
}
|