@intentius/chant 0.102.0 → 0.104.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/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/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/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/fan-out.d.ts +33 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +7 -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/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +3 -2
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +63 -1
- package/dist/cli/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.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/verbs/shell.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/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +48 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +7 -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/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +126 -0
- package/dist/op/activities/activity-contracts.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 +4 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activity-contract.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/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/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- package/dist/op/index.d.ts +4 -1
- package/dist/op/index.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/types.d.ts +8 -0
- package/dist/op/types.d.ts.map +1 -1
- 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/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.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/vendor/js-yaml-load.d.ts +56 -0
- package/dist/vendor/js-yaml-load.d.ts.map +1 -0
- 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 +27 -3
- package/dist/workspace/box-factory.d.ts.map +1 -1
- 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/checks.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 +2 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +9 -2
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +108 -14
- package/dist/workspace/conformance/writer.d.ts.map +1 -1
- 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 +65 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +153 -4
- 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/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/intent-cli.d.ts +1 -1
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +28 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +102 -5
- 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 +48 -0
- 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-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.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/reason-codes.d.ts +33 -4
- package/dist/workspace/reason-codes.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-cli.d.ts +7 -0
- 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-write.d.ts +66 -6
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +28 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +138 -6
- package/dist/workspace/runs-cli.d.ts.map +1 -1
- package/dist/workspace/runs.d.ts +132 -11
- package/dist/workspace/runs.d.ts.map +1 -1
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.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 +2 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +54 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +16 -5
- package/dist/workspace/symbols.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 +6 -1
- package/dist/workspace/trust/seal.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.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/workspace-kinds.schema.json +122 -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 +6 -2
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +1 -1
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +6 -1
- 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/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/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/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/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/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +34 -3
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.ts +1 -0
- package/src/cli/main.test.ts +20 -0
- package/src/cli/main.ts +185 -23
- 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 +1 -1
- package/src/cli/mcp/workspace-tools.ts +34 -6
- package/src/cli/registry.ts +63 -1
- 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/discovery/sandbox/bundle.ts +1 -1
- 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/index.ts +1 -0
- package/src/lexicon.ts +51 -0
- package/src/lifecycle/gate-ledger.ts +7 -0
- package/src/lifecycle/git.ts +102 -16
- 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/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 +6 -0
- 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/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/index.ts +9 -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/types.ts +8 -0
- package/src/op/work-lease-run.ts +3 -0
- 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/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/vendor/js-yaml-load.test.ts +115 -0
- package/src/vendor/js-yaml-load.ts +1939 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +4 -1
- package/src/workspace/box-factory.ts +37 -4
- 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/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +3 -0
- package/src/workspace/checks.ts +10 -3
- package/src/workspace/component-environments.test.ts +105 -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 +7 -2
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +42 -2
- 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 +96 -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 +14 -8
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +187 -6
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +25 -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 +2 -1
- package/src/workspace/conformance/index.mjs +22 -1
- package/src/workspace/conformance/index.ts +5 -1
- package/src/workspace/conformance/vitest.ts +33 -1
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +49 -3
- package/src/workspace/conformance/writer.test.ts +32 -2
- package/src/workspace/conformance/writer.ts +339 -28
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +427 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +153 -4
- package/src/workspace/declaration.ts +141 -0
- 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 +2 -2
- package/src/workspace/graph.schema.json +67 -0
- package/src/workspace/identity.test.ts +23 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +26 -9
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +130 -3
- package/src/workspace/intent-record.ts +74 -28
- 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 +5 -5
- package/src/workspace/intent.schema.json +234 -4
- package/src/workspace/intent.ts +260 -66
- 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 +157 -2
- 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 +162 -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/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +13 -1
- package/src/workspace/reason-codes.ts +38 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +78 -0
- package/src/workspace/records-cli.ts +20 -6
- package/src/workspace/records-close.schema.json +78 -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 +7 -0
- package/src/workspace/records-review.schema.json +78 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-write.ts +192 -25
- package/src/workspace/records.schema.json +16 -0
- package/src/workspace/records.ts +50 -9
- 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 +343 -14
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +416 -5
- package/src/workspace/runs.schema.json +451 -4
- package/src/workspace/runs.test.ts +39 -0
- package/src/workspace/runs.ts +296 -35
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +5 -2
- package/src/workspace/status-gates.ts +3 -1
- package/src/workspace/status.schema.json +126 -3
- package/src/workspace/status.ts +90 -1
- package/src/workspace/symbols.ts +20 -9
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +8 -2
- 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.ts +3 -0
- package/src/workspace/work-evidence.schema.json +3 -0
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/workspace-kinds.schema.json +122 -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 +16 -1
- package/src/workspace/write-scope.ts +33 -11
- package/src/yaml.ts +31 -21
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* read to the workspace root's pinned chant included (ws-021), and keeps
|
|
16
16
|
* anything a command prints away from the protocol on stdout.
|
|
17
17
|
* - The writes (`records-new`, `records-amend`, `records-review`,
|
|
18
|
-
* `records-close`, `points-answer`) call the functions
|
|
19
|
-
* records new|amend|review|close` and `points
|
|
18
|
+
* `records-close`, `points-answer`, `points-retract`) call the functions
|
|
19
|
+
* `chant workspace records new|amend|review|close` and `points
|
|
20
|
+
* answer|retract` call, and return the
|
|
20
21
|
* same JSON result. They keep every rule
|
|
21
22
|
* the CLI keeps: the kind's schema, a closed record never changing, an
|
|
22
23
|
* approved one changing only as its approval rule allows, a dissent needing
|
|
@@ -112,6 +113,7 @@ export const workspaceReadTools: ToolDefinition[] = [
|
|
|
112
113
|
description: "Record kind files whose records join the graph (--kind). The plain graph takes one; intent takes several.",
|
|
113
114
|
},
|
|
114
115
|
intent: { type: "string", description: "The region for the intent graph: a workspace path, path:line, path:start-end, or path#symbol for a TypeScript or JavaScript declaration such as src/server.ts#createApp (--intent). The document's why answers why the region is like this." },
|
|
116
|
+
followSquash: { type: "boolean", description: "With intent: follow squash merges to their pull requests' original commits (--follow-squash, #3035), fetching a pull request ref the clone lacks from origin. Off by default, so a read never reaches the network." },
|
|
115
117
|
composites: { type: "boolean", description: "The composites document instead (--composites). Takes no kind or intent." },
|
|
116
118
|
at: atProp,
|
|
117
119
|
},
|
|
@@ -204,6 +206,7 @@ export const workspaceReadTools: ToolDefinition[] = [
|
|
|
204
206
|
decision: { type: "string", description: "Only the runs that carried out this decision, by id or <kind>/<id> (--decision)." },
|
|
205
207
|
by: { type: "string", description: "Only the runs made for this principal (--by)." },
|
|
206
208
|
since: { type: "string", description: "Only the runs that made a commit after this revision, or started after it (--since)." },
|
|
209
|
+
followSquash: { type: "boolean", description: "Join each squash merge on HEAD to the runs its pull request's original commits joined (--follow-squash, #3035), fetching a pull request ref the clone lacks from origin." },
|
|
207
210
|
},
|
|
208
211
|
},
|
|
209
212
|
},
|
|
@@ -286,7 +289,7 @@ export const workspaceWriteTools: ToolDefinition[] = [
|
|
|
286
289
|
{
|
|
287
290
|
name: "points-answer",
|
|
288
291
|
description:
|
|
289
|
-
"Record people's answer to an open decision point question, or confirm a model's proposal: chant workspace points answer. Refused unless the point's quorum is met: distinct people, none holding the agent role, each holding one of the quorum's roles when it names any. An answered question never changes. " +
|
|
292
|
+
"Record people's answer to an open decision point question, or confirm a model's proposal: chant workspace points answer. Refused unless the point's quorum is met: distinct people, none holding the agent role, each holding one of the quorum's roles when it names any. An answered question never changes in place: points-retract takes it back. " +
|
|
290
293
|
PROTOCOL,
|
|
291
294
|
inputSchema: {
|
|
292
295
|
type: "object",
|
|
@@ -294,12 +297,31 @@ export const workspaceWriteTools: ToolDefinition[] = [
|
|
|
294
297
|
id: { type: "string", description: "The question's id, as workspace-points lists it." },
|
|
295
298
|
answer: { type: ["string", "boolean"], description: "One of the question's candidates; for a noul, true or false." },
|
|
296
299
|
by: { type: "array", items: { type: "string" }, description: "Each person who answered (--by)." },
|
|
300
|
+
note: { type: "string", description: "What the people who answered say with it, kept on the answer (--note)." },
|
|
301
|
+
relayedBy: { type: "string", description: "Who relayed the answer for the people in by, such as a follower; recorded as relayed_by and not counted toward the quorum (--relayed-by)." },
|
|
297
302
|
kind: { type: "string", description: "The answer kind file. Without it, the declared answer kinds." },
|
|
298
303
|
dryRun: dryRunProp,
|
|
299
304
|
},
|
|
300
305
|
required: ["id", "answer", "by"],
|
|
301
306
|
},
|
|
302
307
|
},
|
|
308
|
+
{
|
|
309
|
+
name: "points-retract",
|
|
310
|
+
description:
|
|
311
|
+
"Take back people's answer to a decision point question: chant workspace points retract. The question is escalated to people again, and the answer, who gave it and its note stay in the record's retractions with who retracted it, when and why. Refused unless the point's quorum is met, counted as for an answer. " +
|
|
312
|
+
PROTOCOL,
|
|
313
|
+
inputSchema: {
|
|
314
|
+
type: "object",
|
|
315
|
+
properties: {
|
|
316
|
+
id: { type: "string", description: "The question's id, as workspace-points lists it." },
|
|
317
|
+
by: { type: "array", items: { type: "string" }, description: "Each person who takes the answer back (--by)." },
|
|
318
|
+
note: { type: "string", description: "Why, kept on the retraction (--note)." },
|
|
319
|
+
kind: { type: "string", description: "The answer kind file. Without it, the declared answer kinds." },
|
|
320
|
+
dryRun: dryRunProp,
|
|
321
|
+
},
|
|
322
|
+
required: ["id", "by"],
|
|
323
|
+
},
|
|
324
|
+
},
|
|
303
325
|
];
|
|
304
326
|
|
|
305
327
|
/** A tool call that can't be made as given: the client gets it as an error result, and nothing runs. */
|
|
@@ -355,7 +377,7 @@ export function readArgv(tool: string, params: Record<string, unknown>): string[
|
|
|
355
377
|
const composites = bool(params, "composites");
|
|
356
378
|
const kindArgs = kinds(params).flatMap((k) => ["--kind", k]);
|
|
357
379
|
if (composites) return ["workspace", "graph", "--composites", ...kindArgs, ...(intent !== undefined ? ["--intent", intent] : []), ...atArgs, "--json"];
|
|
358
|
-
if (intent !== undefined) return ["workspace", "graph", "--intent", intent, ...kindArgs, ...atArgs, "--json"];
|
|
380
|
+
if (intent !== undefined) return ["workspace", "graph", "--intent", intent, ...kindArgs, ...atArgs, ...(bool(params, "followSquash") ? ["--follow-squash"] : []), "--json"];
|
|
359
381
|
return ["workspace", "graph", ...kindArgs, ...atArgs, "--json"];
|
|
360
382
|
}
|
|
361
383
|
case "workspace-changes": {
|
|
@@ -388,7 +410,7 @@ export function readArgv(tool: string, params: Record<string, unknown>): string[
|
|
|
388
410
|
const v = str(params, f);
|
|
389
411
|
return v !== undefined ? [`--${f}`, v] : [];
|
|
390
412
|
});
|
|
391
|
-
return ["workspace", "runs", ...flags, "--json"];
|
|
413
|
+
return ["workspace", "runs", ...flags, ...(bool(params, "followSquash") ? ["--follow-squash"] : []), "--json"];
|
|
392
414
|
}
|
|
393
415
|
case "workspace-points": {
|
|
394
416
|
const kind = str(params, "kind");
|
|
@@ -547,7 +569,13 @@ export function createWorkspaceTools(options: WorkspaceToolsOptions): WorkspaceT
|
|
|
547
569
|
if (typeof answer !== "string" && typeof answer !== "boolean") throw new ToolInputError("answer must be a string, or true or false");
|
|
548
570
|
const by = params.by;
|
|
549
571
|
if (!Array.isArray(by) || by.length === 0 || !by.every((b) => typeof b === "string" && b.trim() !== "")) throw new ToolInputError("by must list each person who answered");
|
|
550
|
-
return answerPoint({ cwd, id: str(params, "id", true)!, answer, by: by as string[], kind: str(params, "kind"), dryRun: bool(params, "dryRun") });
|
|
572
|
+
return answerPoint({ cwd, id: str(params, "id", true)!, answer, by: by as string[], note: str(params, "note"), relayedBy: str(params, "relayedBy"), kind: str(params, "kind"), dryRun: bool(params, "dryRun") });
|
|
573
|
+
},
|
|
574
|
+
"points-retract": async (params) => {
|
|
575
|
+
const { retractAnswer } = await import("../../workspace/decide");
|
|
576
|
+
const by = params.by;
|
|
577
|
+
if (!Array.isArray(by) || by.length === 0 || !by.every((b) => typeof b === "string" && b.trim() !== "")) throw new ToolInputError("by must list each person who takes the answer back");
|
|
578
|
+
return retractAnswer({ cwd, id: str(params, "id", true)!, by: by as string[], note: str(params, "note"), kind: str(params, "kind"), dryRun: bool(params, "dryRun") });
|
|
551
579
|
},
|
|
552
580
|
"records-close": async (params) => {
|
|
553
581
|
const w = await write();
|
package/src/cli/registry.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface ParsedArgs {
|
|
|
9
9
|
path: string;
|
|
10
10
|
extraPositional?: string;
|
|
11
11
|
extraPositional2?: string;
|
|
12
|
+
/** Every positional after the command word, in order (#3308): for a command with more than three, such as `workspace box listing set <member>`. */
|
|
13
|
+
positionals?: string[];
|
|
12
14
|
output?: string;
|
|
13
15
|
format: string;
|
|
14
16
|
force?: boolean;
|
|
@@ -238,6 +240,42 @@ export interface ParsedArgs {
|
|
|
238
240
|
* ungated. A component's own authored gates are unaffected either way.
|
|
239
241
|
*/
|
|
240
242
|
gate?: string;
|
|
243
|
+
/**
|
|
244
|
+
* `chant components fan-out --wave-gate <name>` (#3049) — one gate per wave
|
|
245
|
+
* instead of one over the set. Wave `n` waits on `<name>-wave-<n>`, bound to
|
|
246
|
+
* that wave's set digest, and is planned only once the waves before it
|
|
247
|
+
* applied. Also `chant build --components --generate <lexicon> --wave-gate
|
|
248
|
+
* <name>`, which generates one CI job per wave.
|
|
249
|
+
*/
|
|
250
|
+
waveGate?: string;
|
|
251
|
+
/** `chant components fan-out --wave <n>` (#3049) — run wave `n` of a `--wave-gate` fan-out and no other. */
|
|
252
|
+
wave?: number;
|
|
253
|
+
/** `chant components fan-out --canary <component>` (#3049), repeatable — components that form wave 1. */
|
|
254
|
+
canary?: string[];
|
|
255
|
+
/**
|
|
256
|
+
* `chant components pr-plan|pr-apply --pr <n>` (#3183) — the pull or merge
|
|
257
|
+
* request the plan belongs to. Its gate is recorded under op `pr-<n>`.
|
|
258
|
+
* pr-apply finds it from the commit through `--forge` when omitted.
|
|
259
|
+
*/
|
|
260
|
+
pr?: number;
|
|
261
|
+
/**
|
|
262
|
+
* `chant components pr-plan|pr-apply --forge github|gitlab|forgejo` (#3183)
|
|
263
|
+
* — post the note and the commit status on this forge, with the client
|
|
264
|
+
* read from the CI job's environment.
|
|
265
|
+
*/
|
|
266
|
+
forge?: string;
|
|
267
|
+
/**
|
|
268
|
+
* `chant components pr-apply --require-review` (#3183) — count an approval
|
|
269
|
+
* only when its approver has a standing approving review on the pull
|
|
270
|
+
* request. Needs `--forge`.
|
|
271
|
+
*/
|
|
272
|
+
requireReview?: boolean;
|
|
273
|
+
/**
|
|
274
|
+
* `chant build --components --generate <lexicon> --pr-loop` (#3183) —
|
|
275
|
+
* generate the pull-request pipeline: plan on the pull request, apply on
|
|
276
|
+
* merge bound to the approved digest.
|
|
277
|
+
*/
|
|
278
|
+
prLoop?: boolean;
|
|
241
279
|
/**
|
|
242
280
|
* `chant components fan-out --resume <file>` (#2420) — the attempt record
|
|
243
281
|
* this fan-out reads before it starts and writes when it finishes. Repeating
|
|
@@ -303,8 +341,10 @@ export interface ParsedArgs {
|
|
|
303
341
|
bys?: string[];
|
|
304
342
|
/** `chant workspace points --open` (#2739): only the questions still open. */
|
|
305
343
|
open?: boolean;
|
|
306
|
-
/** `chant workspace points ask <point> --inputs <file
|
|
344
|
+
/** `chant workspace points ask <point> --inputs <file|-|json>` (#2739): the inputs, as a JSON object. */
|
|
307
345
|
inputs?: string;
|
|
346
|
+
/** `chant workspace points ask <point> --candidates <file|-|json>` (#3403): an ad-hoc point's question and candidates. */
|
|
347
|
+
candidates?: string;
|
|
308
348
|
/** `chant workspace points ask <point> --response <file>` (#2739): a POST /v1/systemone response the caller got from a backend. */
|
|
309
349
|
response?: string;
|
|
310
350
|
/** `chant workspace points ask <point> --subject <id>` (#2739): what the question is about. */
|
|
@@ -317,6 +357,8 @@ export interface ParsedArgs {
|
|
|
317
357
|
composites?: boolean;
|
|
318
358
|
/** `chant workspace graph --intent <path[:start-end]|path#symbol>` (#2651): the region the intent graph is over. Empty with `--record`. */
|
|
319
359
|
intent?: string;
|
|
360
|
+
/** `chant workspace graph --intent` and `chant workspace runs` (#3035): follow squash merges to their pull requests' original commits, fetching missing pull request refs. */
|
|
361
|
+
followSquash?: boolean;
|
|
320
362
|
/** `chant workspace graph --intent --record <id>`: walk one decision record over every entry its constrains lists. */
|
|
321
363
|
record?: string;
|
|
322
364
|
/** `chant workspace patch <range> --path <p>`: only these paths, from the workspace root. Repeatable. */
|
|
@@ -335,8 +377,20 @@ export interface ParsedArgs {
|
|
|
335
377
|
uncommitted?: boolean;
|
|
336
378
|
/** `chant workspace records amend <id> --set <file|->` (#2670): the JSON fields to set. */
|
|
337
379
|
set?: string;
|
|
380
|
+
/** `chant workspace records amend|review|close <id> --expect <digest>` (#3173): the record's digest the caller last read; the write is refused with record-conflict when it has moved on. */
|
|
381
|
+
expect?: string;
|
|
338
382
|
/** `chant workspace records review <id> --verdict <v>` (#2670): agree, dissent or abstain. */
|
|
339
383
|
verdict?: string;
|
|
384
|
+
/** `chant workspace box listing set <member> --cover <image>` (#3308): a PNG, JPEG or WebP picture to copy in as the box's cover. */
|
|
385
|
+
cover?: string;
|
|
386
|
+
/** `chant workspace box listing set <member> --cover <image> --cover-path <path>` (#3308): where the cover goes, from the workspace root. */
|
|
387
|
+
coverPath?: string;
|
|
388
|
+
/** `chant workspace box publish <member> --records` (#3165): publish the records kept uncommitted instead of a work item. */
|
|
389
|
+
records?: boolean;
|
|
390
|
+
/** `chant workspace wip save --label <text>` (#3172): what the caller calls the snapshot, such as a turn id. */
|
|
391
|
+
label?: string;
|
|
392
|
+
/** `chant workspace wip --branch <branch>` (#3172): list one branch's snapshots. */
|
|
393
|
+
branch?: string;
|
|
340
394
|
/**
|
|
341
395
|
* `chant workspace records review <id> --by <principal>` (#2670): the
|
|
342
396
|
* reviewer, as the caller names them. Also `chant workspace records new
|
|
@@ -351,6 +405,12 @@ export interface ParsedArgs {
|
|
|
351
405
|
* On `chant approve` and `chant run approve`, the key that seals the gate approval (#3163).
|
|
352
406
|
*/
|
|
353
407
|
sign?: string | true;
|
|
408
|
+
/**
|
|
409
|
+
* `chant approve <op> <gate> --relayed-by <principal>` and `chant workspace
|
|
410
|
+
* points answer <id> --relayed-by <principal>` (#3402): the principal that
|
|
411
|
+
* carried the approval or answer to chant on behalf of the person it names.
|
|
412
|
+
*/
|
|
413
|
+
relayedBy?: string;
|
|
354
414
|
/** `chant workspace records review <id> --session <id>` (#2670): the review session the verdict was given in. */
|
|
355
415
|
session?: string;
|
|
356
416
|
/** `chant workspace records new <kind> --prefix <prefix>` (#2670): the id prefix to allocate under. */
|
|
@@ -365,6 +425,8 @@ export interface ParsedArgs {
|
|
|
365
425
|
claim?: string;
|
|
366
426
|
/** `chant workspace evidence sign --environment <file>` (#2553): the runner environment, hashed into the evidence. */
|
|
367
427
|
environment?: string;
|
|
428
|
+
/** `chant workspace runs statement <id> --signer <principal>` (#3192): the runner principal that will sign. */
|
|
429
|
+
signer?: string;
|
|
368
430
|
/** `chant workspace evidence verify --envelope <file>` (#2553). */
|
|
369
431
|
envelope?: string;
|
|
370
432
|
/** `chant workspace signers rotate --threshold <n>` (#2553). */
|
|
@@ -41,7 +41,7 @@ import type { DriverStepRecord } from "./driver";
|
|
|
41
41
|
* driver's own `collectComponentOutputs` stays looser (uri/digest/key) because it
|
|
42
42
|
* only feeds `@<component>.publish.*` wiring, where a false positive is harmless.
|
|
43
43
|
*/
|
|
44
|
-
function isPromotedArtifact(output: unknown): output is { uri: string; digest?: string } {
|
|
44
|
+
export function isPromotedArtifact(output: unknown): output is { uri: string; digest?: string } {
|
|
45
45
|
return !!output && typeof output === "object" && "uri" in output && typeof (output as { uri?: unknown }).uri === "string";
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* Cloud implementations are a later phase (see epic #551, issue #554).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import type { ReleaseIdentity } from "../telemetry-attribution";
|
|
16
|
+
import type { ChangeSetPart } from "../change-set";
|
|
17
|
+
|
|
15
18
|
/**
|
|
16
19
|
* Ambient information a capability's `run`/`rollback` receives, independent of
|
|
17
20
|
* its typed `input`. Deliberately minimal for this phase: the orchestrator
|
|
@@ -27,6 +30,42 @@ export interface DeployContext {
|
|
|
27
30
|
component: string;
|
|
28
31
|
/** Arbitrary environment config resolved by the orchestrator (registry URLs, cluster names, ...). */
|
|
29
32
|
vars?: Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* The release this run deploys (#3061, ws-081): the commit, set by the
|
|
35
|
+
* caller, and the digest of the artifact a publish step has promoted so
|
|
36
|
+
* far in this component's run, set by the driver. A deploy step passes it
|
|
37
|
+
* to the workload with `releaseEnvironment()`. Absent outside
|
|
38
|
+
* `chant run --components`.
|
|
39
|
+
*/
|
|
40
|
+
release?: ReleaseIdentity;
|
|
41
|
+
/**
|
|
42
|
+
* What this component's steps planned before its wave's gate was decided
|
|
43
|
+
* (#3049), keyed by {@link CapabilityPlan.member}. Set by a gated-wave
|
|
44
|
+
* fan-out and by a pull request's apply (#3183). A capability whose `run`
|
|
45
|
+
* finds its own member here applies that plan, the one the approver
|
|
46
|
+
* approved, instead of planning again.
|
|
47
|
+
*/
|
|
48
|
+
plans?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* What a capability's `plan` produced (#3049): the member it planned, that
|
|
53
|
+
* plan's digest, and whatever `run` needs to apply exactly that plan.
|
|
54
|
+
*/
|
|
55
|
+
export interface CapabilityPlan {
|
|
56
|
+
/** The member's name in a wave's set digest. For a terraform-family step, the root. */
|
|
57
|
+
member: string;
|
|
58
|
+
/** The digest a gate on this member alone would bind (#2300). */
|
|
59
|
+
planDigest: string;
|
|
60
|
+
/** Handed back to `run` as `DeployContext.plans[member]`. Opaque to the runner. */
|
|
61
|
+
artifact?: unknown;
|
|
62
|
+
/**
|
|
63
|
+
* The member's part of a change-set document (#3181): every change the
|
|
64
|
+
* plan proposes. A pull request's plan (#3183) composes the parts into the
|
|
65
|
+
* document whose grouped summary the PR note shows. Without it the member
|
|
66
|
+
* still counts toward the digest, with no entries.
|
|
67
|
+
*/
|
|
68
|
+
changeSet?: ChangeSetPart;
|
|
30
69
|
}
|
|
31
70
|
|
|
32
71
|
/**
|
|
@@ -61,6 +100,22 @@ export interface Capability<In = unknown, Out = unknown> {
|
|
|
61
100
|
* never needs it (most of them) simply ignores the third parameter.
|
|
62
101
|
*/
|
|
63
102
|
rollback?(ctx: DeployContext, input: In, output?: Out): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Optional: say what `run` would change, without changing it (#3049). A
|
|
105
|
+
* gated-wave fan-out calls this for every step of every component in a
|
|
106
|
+
* wave, once the waves before it have applied, and binds the wave's gate
|
|
107
|
+
* to the set digest of the results. `run` then receives the result's
|
|
108
|
+
* `artifact` through `DeployContext.plans`. A capability without `plan`
|
|
109
|
+
* is covered by its component's composition digest instead.
|
|
110
|
+
*/
|
|
111
|
+
plan?(ctx: DeployContext, input: In): Promise<CapabilityPlan>;
|
|
112
|
+
/**
|
|
113
|
+
* Optional: the outputs `run` exposed when it last ran, read without
|
|
114
|
+
* changing anything (#3183). A pull request's plan reads them for each
|
|
115
|
+
* component a planned one depends on, so a `stackOutput()` wiring resolves
|
|
116
|
+
* to the value standing now. The shape is `run`'s `outputs` field.
|
|
117
|
+
*/
|
|
118
|
+
outputs?(ctx: DeployContext, input: In): Promise<Record<string, unknown>>;
|
|
64
119
|
/**
|
|
65
120
|
* How this verb relates to rollback, for the COMP003 composition check.
|
|
66
121
|
* Usually derivable and left unset: a capability with a `rollback` method is
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files a change touched, and the units lexicons own that those files
|
|
3
|
+
* belong to (#3183).
|
|
4
|
+
*
|
|
5
|
+
* `lifecycle affected` judges chant source by diffing what it builds. A unit
|
|
6
|
+
* that is not chant source, such as a hand-written Terraform root, never
|
|
7
|
+
* shows in that diff, so a lexicon that owns such units answers from the
|
|
8
|
+
* changed paths instead (`LexiconPlugin.changedUnits`).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execFile } from "node:child_process";
|
|
12
|
+
import { promisify } from "node:util";
|
|
13
|
+
import type { LexiconPlugin } from "../lexicon";
|
|
14
|
+
|
|
15
|
+
const execFileAsync = promisify(execFile);
|
|
16
|
+
|
|
17
|
+
async function git(cwd: string, args: string[]): Promise<string> {
|
|
18
|
+
const { stdout } = await execFileAsync("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
19
|
+
return stdout;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The commit a change is measured from: the merge base of `base` and `head`.
|
|
24
|
+
* A pull request's head that branched before `base` moved is measured from
|
|
25
|
+
* where it branched, so the other changes on `base` are not counted as its
|
|
26
|
+
* own; a merge commit's first parent is its own merge base.
|
|
27
|
+
*/
|
|
28
|
+
export async function resolveMergeBase(cwd: string, base: string, head = "HEAD"): Promise<string> {
|
|
29
|
+
try {
|
|
30
|
+
return (await git(cwd, ["merge-base", base, head])).trim();
|
|
31
|
+
} catch (err) {
|
|
32
|
+
const detail = (err as { stderr?: string }).stderr?.trim();
|
|
33
|
+
throw new Error(
|
|
34
|
+
`cannot find where ${head} and ${base} meet${detail ? `: ${detail}` : ""}. ` +
|
|
35
|
+
"Is the base fetched? A CI checkout needs the history (fetch-depth: 0, GIT_DEPTH: 0).",
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The full commit `ref` names. */
|
|
41
|
+
export async function resolveCommit(cwd: string, ref: string): Promise<string> {
|
|
42
|
+
return (await git(cwd, ["rev-parse", "--verify", `${ref}^{commit}`])).trim();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Files changed between `base` and `head`, relative to `cwd` and limited to
|
|
47
|
+
* it, with `/` separators. A rename counts as its old and its new path.
|
|
48
|
+
*/
|
|
49
|
+
export async function changedFilesBetween(cwd: string, base: string, head = "HEAD"): Promise<string[]> {
|
|
50
|
+
const out = await git(cwd, ["diff", "--name-only", "-z", "--no-renames", "--relative", base, head]);
|
|
51
|
+
return out.split("\0").filter(Boolean).sort();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The union of every plugin's `changedUnits` answer, sorted. */
|
|
55
|
+
export async function lexiconChangedUnits(
|
|
56
|
+
plugins: readonly Pick<LexiconPlugin, "changedUnits">[],
|
|
57
|
+
ctx: { projectRoot: string; config: Record<string, unknown>; changedFiles: string[] },
|
|
58
|
+
): Promise<string[]> {
|
|
59
|
+
if (ctx.changedFiles.length === 0) return [];
|
|
60
|
+
const units = new Set<string>();
|
|
61
|
+
for (const plugin of plugins) {
|
|
62
|
+
if (!plugin.changedUnits) continue;
|
|
63
|
+
for (const unit of await plugin.changedUnits(ctx)) units.add(unit);
|
|
64
|
+
}
|
|
65
|
+
return [...units].sort();
|
|
66
|
+
}
|
|
@@ -22,11 +22,13 @@
|
|
|
22
22
|
* executor, the CLI entrypoint the driver (#556) never had.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
+
import { UnknownCanaryError } from "../gated-waves";
|
|
25
26
|
import { lexiconModulePath, lexiconNames, importLexiconPackage } from "../lexicon-module";
|
|
26
27
|
import { discoverComponents } from "./discover";
|
|
27
28
|
import type { BuildParamProvenance } from "../provenance";
|
|
28
|
-
import { inferArchetype, projectToJson, type Archetype } from "./component";
|
|
29
|
+
import { inferArchetype, projectToJson, type Archetype, type ComponentEnvironmentDeclaration } from "./component";
|
|
29
30
|
import {
|
|
31
|
+
deployContext,
|
|
30
32
|
resolveComponentGraph,
|
|
31
33
|
runInterpretDriver,
|
|
32
34
|
runComponentDeploy,
|
|
@@ -43,7 +45,9 @@ import type { GateDigestMismatch, GateLedgerPort } from "../op/gate";
|
|
|
43
45
|
import { gateName } from "../op/gate-name";
|
|
44
46
|
import { isLexiconPlugin, type LexiconPlugin, type ComponentPipelineOptions } from "../lexicon";
|
|
45
47
|
import type { RunProgressEvent } from "./run-progress";
|
|
46
|
-
import { relative } from "node:path";
|
|
48
|
+
import { dirname, relative } from "node:path";
|
|
49
|
+
import { existsSync, statSync } from "node:fs";
|
|
50
|
+
import { getHeadCommit } from "../lifecycle/git";
|
|
47
51
|
import { buildCapabilityRegistry } from "./capability-plugin-loader";
|
|
48
52
|
import type { CapabilityRegistry } from "./capability";
|
|
49
53
|
import { applyConfigDefaults } from "./config-defaults";
|
|
@@ -156,6 +160,8 @@ export interface ComponentGraphResult {
|
|
|
156
160
|
* (`inferArchetype`), so a reader can label a component without its source
|
|
157
161
|
* (#2662). */
|
|
158
162
|
archetypes?: Record<string, Archetype>;
|
|
163
|
+
/** Component name → the environments it declares (#3153), present only for components that declared them. */
|
|
164
|
+
environments?: Record<string, ComponentEnvironmentDeclaration[]>;
|
|
159
165
|
error?: string;
|
|
160
166
|
}
|
|
161
167
|
|
|
@@ -192,7 +198,10 @@ export async function computeComponentGraph(
|
|
|
192
198
|
// that declared them — no identity fallback (see ComponentGraphResult doc).
|
|
193
199
|
const composites: Record<string, string[]> = {};
|
|
194
200
|
const archetypes: Record<string, Archetype> = {};
|
|
201
|
+
const environments: Record<string, ComponentEnvironmentDeclaration[]> = {};
|
|
195
202
|
for (const [name, discovered] of result.components) {
|
|
203
|
+
const declaredEnvironments = discovered.component.environments;
|
|
204
|
+
if (declaredEnvironments && declaredEnvironments.length > 0) environments[name] = declaredEnvironments.map((e) => ({ ...e }));
|
|
196
205
|
archetypes[name] = discovered.component.archetype ?? inferArchetype(discovered.component);
|
|
197
206
|
files[name] = relative(path, discovered.filePath);
|
|
198
207
|
const declared = discovered.component.liveNames;
|
|
@@ -207,7 +216,7 @@ export async function computeComponentGraph(
|
|
|
207
216
|
for (const c of driverComponents) {
|
|
208
217
|
for (const dep of c.dependsOn ?? []) edges.push({ from: c.name, to: dep });
|
|
209
218
|
}
|
|
210
|
-
return { success: true, order, waves, edges, files, liveNames, composites, archetypes };
|
|
219
|
+
return { success: true, order, waves, edges, files, liveNames, composites, archetypes, environments };
|
|
211
220
|
} catch (err) {
|
|
212
221
|
if (err instanceof UnknownDependencyError || err instanceof DependencyCycleError) {
|
|
213
222
|
return { success: false, order: [], waves: [], edges: [], error: err.message };
|
|
@@ -302,7 +311,7 @@ export async function generateComponentsPipeline(
|
|
|
302
311
|
const { yaml, stages, jobs, env } = plugin.generateComponentPipeline(driverComponents, options);
|
|
303
312
|
return { success: true, yaml, stages, jobs, ...(env ? { env } : {}), buildParams };
|
|
304
313
|
} catch (err) {
|
|
305
|
-
if (err instanceof UnknownDependencyError || err instanceof DependencyCycleError) {
|
|
314
|
+
if (err instanceof UnknownDependencyError || err instanceof DependencyCycleError || err instanceof UnknownCanaryError) {
|
|
306
315
|
return { success: false, error: err.message };
|
|
307
316
|
}
|
|
308
317
|
throw err;
|
|
@@ -421,6 +430,12 @@ export interface RunComponentsOptions {
|
|
|
421
430
|
buildParams?: BuildParamProvenance[];
|
|
422
431
|
/** Where a `gate` step's facts are read and written (#2119). Defaults to the `chant/lifecycle` orphan branch; a test passes `memoryGateLedgerPort()` from `../op/gate.ts`. */
|
|
423
432
|
gates?: GateLedgerPort;
|
|
433
|
+
/**
|
|
434
|
+
* The commit the run deploys, for the workloads' `vcs.ref.head.revision`
|
|
435
|
+
* (#3061). Default: `git rev-parse HEAD` in the project, or nothing outside
|
|
436
|
+
* a checkout. `null` passes none.
|
|
437
|
+
*/
|
|
438
|
+
revision?: string | null;
|
|
424
439
|
}
|
|
425
440
|
|
|
426
441
|
/** Result of `chant run --components <name|all>`. */
|
|
@@ -571,11 +586,19 @@ export async function runComponents(
|
|
|
571
586
|
const { onProgress } = options;
|
|
572
587
|
|
|
573
588
|
const gates = options.gates;
|
|
589
|
+
// #3061: the commit this run deploys, for the workloads' vcs.ref.head.revision. The digest comes
|
|
590
|
+
// from the run's own publish step. Best effort: outside a git checkout nothing is passed.
|
|
591
|
+
const revision =
|
|
592
|
+
options.revision !== undefined
|
|
593
|
+
? options.revision ?? undefined
|
|
594
|
+
: await getHeadCommit({ cwd: existsSync(path) && statSync(path).isDirectory() ? path : dirname(path) }).catch(() => undefined);
|
|
595
|
+
const releaseIdentity = () => (revision ? { revision } : {});
|
|
574
596
|
|
|
575
597
|
try {
|
|
576
598
|
if (selector === "all") {
|
|
577
599
|
const run = await runInterpretDriver(resolvedTargets, registry, {
|
|
578
600
|
env,
|
|
601
|
+
releaseIdentity,
|
|
579
602
|
componentOutputs: seedOutputs,
|
|
580
603
|
onProgress,
|
|
581
604
|
...(gates ? { gates } : {}),
|
|
@@ -618,7 +641,7 @@ export async function runComponents(
|
|
|
618
641
|
onProgress?.({ type: "component-start", wave: 1, component: componentName });
|
|
619
642
|
const componentResult = await runComponentDeploy(
|
|
620
643
|
resolvedTargets[0],
|
|
621
|
-
{ env,
|
|
644
|
+
deployContext({ env, releaseIdentity }, componentName),
|
|
622
645
|
registry,
|
|
623
646
|
componentOutputs,
|
|
624
647
|
onProgress,
|
|
@@ -60,6 +60,23 @@
|
|
|
60
60
|
"description": "Optional: the composite kind name(s) this component's deployed resources come from, when a consumer cannot infer it from `name` (#1492). Without this, a consumer joining a composite graph to the component DAG guesses by kebab-casing each composite's kind and matching it against this component's `name`, which only holds when a component maps 1:1 to a composite named for it. Omitted entirely (the default), the naming convention stays in effect with no behavior change. A component built from several composites may list them all.",
|
|
61
61
|
"items": { "type": "string", "minLength": 1 },
|
|
62
62
|
"minItems": 1
|
|
63
|
+
},
|
|
64
|
+
"environments": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"description": "Optional: where a release of this component goes, by environment (#3153). Each names an environment --env takes and, for it, the runtime that hosts the release, the URL it answers on, a custom domain attached to it, and the git remote its lifecycle records are pushed to. chant workspace graph --composites lists them first among the component's environments, with source component. Omitted, the component's environments are its member's.",
|
|
67
|
+
"minItems": 1,
|
|
68
|
+
"items": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["name"],
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"properties": {
|
|
73
|
+
"name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,62}$", "description": "The environment's name, as --env takes it." },
|
|
74
|
+
"runtime": { "type": "string", "minLength": 1, "description": "The runtime that hosts a release here, such as local or fly." },
|
|
75
|
+
"url": { "type": "string", "pattern": "^https?://", "description": "Where the released component answers." },
|
|
76
|
+
"domain": { "type": "string", "minLength": 1, "description": "A custom domain the release attaches to it." },
|
|
77
|
+
"lifecycle": { "type": "string", "minLength": 1, "description": "The git remote this environment's approvals, effect receipts and ledger records are pushed to." }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
63
80
|
}
|
|
64
81
|
},
|
|
65
82
|
"$defs": {
|
|
@@ -183,6 +183,31 @@ export interface Component {
|
|
|
183
183
|
* default and nothing changes.
|
|
184
184
|
*/
|
|
185
185
|
composites?: string[];
|
|
186
|
+
/**
|
|
187
|
+
* Optional: where a release of this component goes, by environment
|
|
188
|
+
* (#3153, ws-095). Each names an environment `--env` takes and, for that
|
|
189
|
+
* environment, the runtime that hosts the release, the URL its health
|
|
190
|
+
* answers on, a custom domain attached to it, and the git remote its
|
|
191
|
+
* approvals, effect receipts and ledger records are pushed to. `chant
|
|
192
|
+
* workspace graph --composites` lists them first among the component's
|
|
193
|
+
* environments, with source `component`. Omitted, the component's
|
|
194
|
+
* environments are its member's, as before.
|
|
195
|
+
*/
|
|
196
|
+
environments?: ComponentEnvironmentDeclaration[];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** One environment a component declares it deploys to (#3153). */
|
|
200
|
+
export interface ComponentEnvironmentDeclaration {
|
|
201
|
+
/** The environment's name, as `--env` takes it. */
|
|
202
|
+
name: string;
|
|
203
|
+
/** The runtime that hosts a release here, such as `local` or a lexicon's runtime (`fly`). */
|
|
204
|
+
runtime?: string;
|
|
205
|
+
/** Where the released component answers, such as its health endpoint's origin. */
|
|
206
|
+
url?: string;
|
|
207
|
+
/** A custom domain the release attaches to it. */
|
|
208
|
+
domain?: string;
|
|
209
|
+
/** The git remote this environment's approvals, effect receipts and ledger records are pushed to. */
|
|
210
|
+
lifecycle?: string;
|
|
186
211
|
}
|
|
187
212
|
|
|
188
213
|
/** Author a named phase. `steps` may mix capability `Step`s, `Gate`s, and nested `Phase`s (fan-out). */
|
|
@@ -56,6 +56,9 @@ export const DEPLOY_UNIT_RULES: readonly DeployUnitRule[] = [
|
|
|
56
56
|
{ kind: "argo-app", field: "stack", lexicon: "k8s" },
|
|
57
57
|
{ kind: "flux-reconcile", field: "stack", lexicon: "k8s" },
|
|
58
58
|
{ kind: "helm-upgrade", field: "release", lexicon: "helm" },
|
|
59
|
+
// A Terraform-family root (#3049). Its unit is the root's name in
|
|
60
|
+
// `terraform.roots`, which is also the member a gated wave's digest names.
|
|
61
|
+
{ kind: "terraform-apply", field: "root", lexicon: "terraform" },
|
|
59
62
|
];
|
|
60
63
|
|
|
61
64
|
/** One resolved unit a component's deploy composition targets. */
|
|
@@ -1069,3 +1069,55 @@ describe("capabilities are consumed exactly as the registry provides them", () =
|
|
|
1069
1069
|
expect(failed?.error).toMatch(/capability "some-future-verb" is not implemented/);
|
|
1070
1070
|
});
|
|
1071
1071
|
});
|
|
1072
|
+
|
|
1073
|
+
describe("the release a deploy step sees (#3061, ws-081)", () => {
|
|
1074
|
+
function setup() {
|
|
1075
|
+
const registry = new CapabilityRegistry();
|
|
1076
|
+
registry.register(fakeCapability("publish-image", { run: () => ({ uri: "ghcr.io/acme/api@sha256:abc", digest: "sha256:abc" }) }).capability);
|
|
1077
|
+
registry.register(fakeCapability("generate-sbom", { run: () => ({ digest: "sha256:sbom" }) }).capability);
|
|
1078
|
+
const deploy = fakeCapability("deploy");
|
|
1079
|
+
registry.register(deploy.capability);
|
|
1080
|
+
return { registry, deploy };
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
it("carries the caller's revision and the digest a publish step promoted, not an SBOM's", async () => {
|
|
1084
|
+
const { registry, deploy } = setup();
|
|
1085
|
+
const api: DriverComponent = {
|
|
1086
|
+
name: "api",
|
|
1087
|
+
dependsOn: [],
|
|
1088
|
+
deploy: [
|
|
1089
|
+
{ phase: "Publish", steps: [{ kind: "publish-image" }, { kind: "generate-sbom" }] },
|
|
1090
|
+
{ phase: "Deploy", steps: [{ kind: "deploy" }] },
|
|
1091
|
+
],
|
|
1092
|
+
};
|
|
1093
|
+
const result = await runInterpretDriver([api], registry, { env: "prod", releaseIdentity: () => ({ revision: "0123abc" }) });
|
|
1094
|
+
expect(result.ok).toBe(true);
|
|
1095
|
+
expect(deploy.calls[0]!.ctx.release).toEqual({ revision: "0123abc", version: "sha256:abc" });
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
it("keeps each component's release its own, and passes none without releaseIdentity", async () => {
|
|
1099
|
+
const { registry, deploy } = setup();
|
|
1100
|
+
const api: DriverComponent = { name: "api", dependsOn: [], deploy: [{ phase: "P", steps: [{ kind: "publish-image" }, { kind: "deploy" }] }] };
|
|
1101
|
+
const worker: DriverComponent = { name: "worker", dependsOn: ["api"], deploy: [{ phase: "D", steps: [{ kind: "deploy" }] }] };
|
|
1102
|
+
await runInterpretDriver([api, worker], registry, { env: "prod", releaseIdentity: () => ({ revision: "r1" }) });
|
|
1103
|
+
expect(deploy.calls.map((c) => [c.ctx.component, c.ctx.release])).toEqual([
|
|
1104
|
+
["api", { revision: "r1", version: "sha256:abc" }],
|
|
1105
|
+
["worker", { revision: "r1" }],
|
|
1106
|
+
]);
|
|
1107
|
+
const plain = setup();
|
|
1108
|
+
await runInterpretDriver([{ ...worker, dependsOn: [] }], plain.registry, { env: "prod" });
|
|
1109
|
+
expect(plain.deploy.calls[0]!.ctx.release).toBeUndefined();
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
it("a promote's recorded digest is the version when no step publishes one", async () => {
|
|
1113
|
+
const { registry, deploy } = setup();
|
|
1114
|
+
const api: DriverComponent = { name: "api", dependsOn: [], deploy: [{ phase: "D", steps: [{ kind: "deploy" }] }] };
|
|
1115
|
+
await runInterpretDriver([api], registry, {
|
|
1116
|
+
env: "prod",
|
|
1117
|
+
gates: memoryGateLedgerPort(),
|
|
1118
|
+
releases: new Map([["api", "sha256:recorded"]]),
|
|
1119
|
+
releaseIdentity: () => ({ revision: "r0" }),
|
|
1120
|
+
});
|
|
1121
|
+
expect(deploy.calls[0]!.ctx.release).toEqual({ revision: "r0", version: "sha256:recorded" });
|
|
1122
|
+
});
|
|
1123
|
+
});
|