@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
package/src/lifecycle/git.ts
CHANGED
|
@@ -660,44 +660,120 @@ export async function getRemoteLifecycleBranchSha(
|
|
|
660
660
|
}
|
|
661
661
|
|
|
662
662
|
/**
|
|
663
|
-
*
|
|
663
|
+
* Why a push of the state branch did or did not reach the remote.
|
|
664
664
|
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
667
|
-
*
|
|
665
|
+
* - `pushed` — the remote now holds the local tip.
|
|
666
|
+
* - `no-remote` — nothing to push to; local is the whole ledger.
|
|
667
|
+
* - `stale` — the remote moved past the tip this checkout last saw (another
|
|
668
|
+
* writer pushed); fetch, re-apply and retry.
|
|
669
|
+
* - `failed` — git refused for another reason (no network, no credentials,
|
|
670
|
+
* a protected branch); `stderr` is git's first words on it.
|
|
671
|
+
*/
|
|
672
|
+
export type LifecyclePushStatus =
|
|
673
|
+
| { status: "pushed"; remote: string; commit: string }
|
|
674
|
+
| { status: "no-remote" }
|
|
675
|
+
| { status: "stale"; remote: string; expected: string | null; stderr: string }
|
|
676
|
+
| { status: "failed"; remote: string; stderr: string };
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Point `refs/remotes/<remote>/chant/lifecycle` at `sha`, the remote tip this
|
|
680
|
+
* checkout has just seen (#3391).
|
|
668
681
|
*
|
|
669
|
-
*
|
|
682
|
+
* The push's lease is that ref, and git only keeps it up to date when the
|
|
683
|
+
* remote's configured fetch refspec covers `chant/lifecycle`. A single-branch
|
|
684
|
+
* clone (`git clone --single-branch`, a CI checkout of one ref, a shallow
|
|
685
|
+
* clone) has a refspec for its one branch only, so neither the explicit
|
|
686
|
+
* `chant/lifecycle:chant/lifecycle` fetch nor a successful push touches the
|
|
687
|
+
* tracking ref. The first push of a new branch then succeeds against an empty
|
|
688
|
+
* lease, and every later one is refused as stale against a remote that holds
|
|
689
|
+
* exactly what this checkout last pushed. Recording the tip ourselves, only at
|
|
690
|
+
* the two moments it is known (a fetch that fast-forwarded or found the local
|
|
691
|
+
* branch ahead, and a push that landed), keeps the lease honest without
|
|
692
|
+
* widening the clone's refspec. It is never set from a diverged fetch: that is
|
|
693
|
+
* the case the lease exists to refuse.
|
|
670
694
|
*/
|
|
671
|
-
|
|
695
|
+
async function trackRemoteLifecycle(remote: string, sha: string, cwd?: string): Promise<void> {
|
|
672
696
|
const rt = getRuntime();
|
|
673
|
-
|
|
674
|
-
|
|
697
|
+
await rt.spawn(["git", "update-ref", `refs/remotes/${remote}/${STATE_BRANCH}`, sha], { cwd, env: C_LOCALE_ENV });
|
|
698
|
+
}
|
|
675
699
|
|
|
676
|
-
|
|
700
|
+
/**
|
|
701
|
+
* Push the state branch to the ledger remote with --force-with-lease and say
|
|
702
|
+
* what happened (#3391). Never throws for a git refusal; {@link pushLifecycle}
|
|
703
|
+
* is the throwing form most callers use.
|
|
704
|
+
*/
|
|
705
|
+
export async function pushLifecycleStatus(opts?: { cwd?: string }): Promise<LifecyclePushStatus> {
|
|
706
|
+
const rt = getRuntime();
|
|
707
|
+
const cwd = opts?.cwd;
|
|
708
|
+
const found = await ledgerRemote(cwd);
|
|
709
|
+
if (found === null) return { status: "no-remote" };
|
|
710
|
+
if ("failed" in found) return { status: "failed", remote: "(unknown)", stderr: found.stderr };
|
|
711
|
+
const { remote } = found;
|
|
677
712
|
|
|
678
713
|
// Capture the lease SHA — if null, the remote ref doesn't exist yet
|
|
679
714
|
// (first-time push) and we send `--force-with-lease=ref:` (empty SHA),
|
|
680
715
|
// which git interprets as "ref does not exist on remote".
|
|
681
716
|
const expected = await getRemoteLifecycleBranchSha(remote, opts);
|
|
682
717
|
const lease = `refs/heads/${STATE_BRANCH}:${expected ?? ""}`;
|
|
718
|
+
const tip = await getStateBranchTip(cwd);
|
|
683
719
|
|
|
684
720
|
const pushResult = await rt.spawn(
|
|
685
721
|
["git", "push", `--force-with-lease=${lease}`, remote, `${STATE_BRANCH}:${STATE_BRANCH}`],
|
|
686
|
-
{ cwd:
|
|
722
|
+
{ cwd, env: C_LOCALE_ENV },
|
|
687
723
|
);
|
|
688
724
|
|
|
689
725
|
if (pushResult.exitCode !== 0) {
|
|
690
|
-
const stderr = pushResult.stderr ?? "";
|
|
726
|
+
const stderr = (pushResult.stderr ?? "").trim();
|
|
691
727
|
if (
|
|
692
728
|
stderr.includes("stale info") ||
|
|
693
729
|
stderr.includes("rejected") ||
|
|
694
730
|
stderr.includes("non-fast-forward")
|
|
695
731
|
) {
|
|
696
|
-
|
|
732
|
+
return { status: "stale", remote, expected, stderr };
|
|
697
733
|
}
|
|
698
|
-
return
|
|
734
|
+
return { status: "failed", remote, stderr };
|
|
735
|
+
}
|
|
736
|
+
if (tip) await trackRemoteLifecycle(remote, tip, cwd);
|
|
737
|
+
return { status: "pushed", remote, commit: tip ?? "" };
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Push the state branch to remote with --force-with-lease.
|
|
742
|
+
*
|
|
743
|
+
* If the remote chant/lifecycle ref has advanced past the local remote-tracking
|
|
744
|
+
* SHA captured at the start of this push, the push is rejected and we throw
|
|
745
|
+
* StaleLifecycleBranchError so the caller can surface a recovery hint.
|
|
746
|
+
*
|
|
747
|
+
* Returns false (without throwing) when no remote is configured, or when git
|
|
748
|
+
* refused the push for a reason other than a stale lease.
|
|
749
|
+
*
|
|
750
|
+
* The remote is the ledger's ({@link ledgerRemote}: `origin` when there is one),
|
|
751
|
+
* the same one {@link fetchLifecycleStatus} reads, and a push that lands
|
|
752
|
+
* records the tip it pushed as the remote-tracking ref, so the next push's
|
|
753
|
+
* lease is right in a single-branch clone too (#3391).
|
|
754
|
+
*/
|
|
755
|
+
export async function pushLifecycle(opts?: { cwd?: string }): Promise<boolean> {
|
|
756
|
+
const result = await pushLifecycleStatus(opts);
|
|
757
|
+
if (result.status === "stale") throw new StaleLifecycleBranchError(result.expected, result.stderr);
|
|
758
|
+
return result.status === "pushed";
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* One line on why a push did not land, for a write document's `notPushed`
|
|
763
|
+
* (#3391), or null when it did.
|
|
764
|
+
*/
|
|
765
|
+
export function describeLifecyclePush(result: LifecyclePushStatus): string | null {
|
|
766
|
+
const said = (stderr: string) => (stderr ? `; git said: ${stderr.split("\n").find((l) => l.trim()) ?? stderr}` : "");
|
|
767
|
+
switch (result.status) {
|
|
768
|
+
case "pushed":
|
|
769
|
+
return null;
|
|
770
|
+
case "no-remote":
|
|
771
|
+
return `this repository has no remote, so ${STATE_BRANCH} stays local`;
|
|
772
|
+
case "stale":
|
|
773
|
+
return `"${result.remote}" holds ${STATE_BRANCH} commits this checkout has not fetched, so the push was refused; fetch ${STATE_BRANCH} and write again${said(result.stderr)}`;
|
|
774
|
+
case "failed":
|
|
775
|
+
return `the push of ${STATE_BRANCH} to "${result.remote}" failed${said(result.stderr)}`;
|
|
699
776
|
}
|
|
700
|
-
return true;
|
|
701
777
|
}
|
|
702
778
|
|
|
703
779
|
/**
|
|
@@ -814,7 +890,12 @@ export async function fetchLifecycleStatus(opts?: { cwd?: string }): Promise<Lif
|
|
|
814
890
|
["git", "fetch", remote, `${STATE_BRANCH}:${STATE_BRANCH}`],
|
|
815
891
|
{ cwd, env: C_LOCALE_ENV },
|
|
816
892
|
);
|
|
817
|
-
if (fetchResult.exitCode === 0)
|
|
893
|
+
if (fetchResult.exitCode === 0) {
|
|
894
|
+
// The local branch is now the remote's tip; record it for the push's lease (#3391).
|
|
895
|
+
const tip = await getStateBranchTip(cwd);
|
|
896
|
+
if (tip) await trackRemoteLifecycle(remote, tip, cwd);
|
|
897
|
+
return { status: "fetched" };
|
|
898
|
+
}
|
|
818
899
|
|
|
819
900
|
const stderr = (fetchResult.stderr ?? "").trim();
|
|
820
901
|
if (NO_SUCH_REMOTE_REF_RE.test(stderr)) return { status: "absent", remote };
|
|
@@ -834,8 +915,13 @@ export async function fetchLifecycleStatus(opts?: { cwd?: string }): Promise<Lif
|
|
|
834
915
|
["git", "merge-base", "--is-ancestor", PROBE_REF, `refs/heads/${STATE_BRANCH}`],
|
|
835
916
|
{ cwd, env: C_LOCALE_ENV },
|
|
836
917
|
);
|
|
918
|
+
const remoteTip = contains.exitCode === 0 ? (await rt.spawn(["git", "rev-parse", "--verify", PROBE_REF], { cwd, env: C_LOCALE_ENV })).stdout.trim() : "";
|
|
837
919
|
await rt.spawn(["git", "update-ref", "-d", PROBE_REF], { cwd, env: C_LOCALE_ENV });
|
|
838
|
-
if (contains.exitCode === 0)
|
|
920
|
+
if (contains.exitCode === 0) {
|
|
921
|
+
// Ahead of the remote: its tip is in our history, so it is the right lease (#3391).
|
|
922
|
+
if (remoteTip) await trackRemoteLifecycle(remote, remoteTip, cwd);
|
|
923
|
+
return { status: "ahead", remote };
|
|
924
|
+
}
|
|
839
925
|
return { status: "diverged", remote, stderr };
|
|
840
926
|
}
|
|
841
927
|
|
|
@@ -162,6 +162,25 @@ describe("cross-lexicon activity contracts (#2101)", () => {
|
|
|
162
162
|
});
|
|
163
163
|
});
|
|
164
164
|
|
|
165
|
+
describe("telemetry attribution (#3375)", () => {
|
|
166
|
+
const readsTelemetry: PostSynthCheck = {
|
|
167
|
+
id: "TELEMETRY",
|
|
168
|
+
description: "reports the attribution the context carries",
|
|
169
|
+
check(ctx) {
|
|
170
|
+
return [{ checkId: "TELEMETRY", severity: "warning", message: JSON.stringify(ctx.telemetry ?? null) }];
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
test("the build's attribution is threaded into the context", () => {
|
|
175
|
+
const diags = runPostSynthChecks([readsTelemetry], createBuildResult(), undefined, { telemetry: { workspace: "acme" } });
|
|
176
|
+
expect(diags[0].message).toBe('{"workspace":"acme"}');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("a level-0 run leaves the field undefined", () => {
|
|
180
|
+
expect(runPostSynthChecks([readsTelemetry], createBuildResult())[0].message).toBe("null");
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
165
184
|
describe("isPostSynthCheck", () => {
|
|
166
185
|
test("accepts a well-formed check and rejects others", async () => {
|
|
167
186
|
const { isPostSynthCheck } = await import("./post-synth");
|
package/src/lint/post-synth.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Declarable } from "../declarable";
|
|
2
2
|
import type { ActivityContract } from "../op/activity-contract";
|
|
3
3
|
import type { SerializerResult } from "../serializer";
|
|
4
|
+
import type { TelemetryAttribution } from "../telemetry-attribution";
|
|
4
5
|
import type { Severity } from "./rule";
|
|
5
6
|
import { parseOutputDocs, type OutputDoc } from "./output-docs";
|
|
6
7
|
|
|
@@ -55,6 +56,13 @@ export interface PostSynthContext {
|
|
|
55
56
|
* when it is `undefined`.
|
|
56
57
|
*/
|
|
57
58
|
readonly activityContracts?: ReadonlyMap<string, ActivityContract>;
|
|
59
|
+
/**
|
|
60
|
+
* The telemetry attribution the build stamped (#2558), from
|
|
61
|
+
* `resolveTelemetryAttribution`. Set when the project is inside a workspace
|
|
62
|
+
* or sets `telemetry.attribution: true`, and absent at level 0 and from a
|
|
63
|
+
* hand-built context. OTEL118 runs only when it is set.
|
|
64
|
+
*/
|
|
65
|
+
readonly telemetry?: TelemetryAttribution;
|
|
58
66
|
/** Raw build result object */
|
|
59
67
|
buildResult: {
|
|
60
68
|
outputs: Map<string, string | SerializerResult>;
|
|
@@ -183,6 +191,14 @@ export interface PostSynthCheck {
|
|
|
183
191
|
description: string;
|
|
184
192
|
/** Execute the check and return diagnostics */
|
|
185
193
|
check(ctx: PostSynthContext): PostSynthDiagnostic[];
|
|
194
|
+
/**
|
|
195
|
+
* `chant audit` skips this check unless the project enables it with a
|
|
196
|
+
* `lint.rules` entry for its id (chant #3190). Builds are not affected: they
|
|
197
|
+
* already filter by the lexicon's `lintPresets()`. It exists because the
|
|
198
|
+
* audit runs every check a lexicon ships, report-only ones included, so a
|
|
199
|
+
* new check would otherwise change the audit output of every project.
|
|
200
|
+
*/
|
|
201
|
+
auditOptIn?: boolean;
|
|
186
202
|
}
|
|
187
203
|
|
|
188
204
|
/** Structural type guard — used to collect project-authored policy checks. */
|
|
@@ -201,12 +217,13 @@ export function isPostSynthCheck(value: unknown): value is PostSynthCheck {
|
|
|
201
217
|
* into the context so a check can branch on the current environment/stack, and
|
|
202
218
|
* `opts.activityContracts` (chant #2101) carries the build's cross-lexicon
|
|
203
219
|
* activity-contract map to the checks that validate Op steps against it.
|
|
220
|
+
* `opts.telemetry` is the build's resolved telemetry attribution.
|
|
204
221
|
*/
|
|
205
222
|
export function runPostSynthChecks(
|
|
206
223
|
checks: PostSynthCheck[],
|
|
207
224
|
buildResult: PostSynthContext["buildResult"],
|
|
208
225
|
env?: string,
|
|
209
|
-
opts?: { activityContracts?: ReadonlyMap<string, ActivityContract
|
|
226
|
+
opts?: { activityContracts?: ReadonlyMap<string, ActivityContract>; telemetry?: TelemetryAttribution },
|
|
210
227
|
): PostSynthDiagnostic[] {
|
|
211
228
|
const getDocs = createDocsAccessor(buildResult.outputs);
|
|
212
229
|
const ctx: PostSynthContext = {
|
|
@@ -215,6 +232,7 @@ export function runPostSynthChecks(
|
|
|
215
232
|
env,
|
|
216
233
|
buildResult,
|
|
217
234
|
...(opts?.activityContracts ? { activityContracts: opts.activityContracts } : {}),
|
|
235
|
+
...(opts?.telemetry ? { telemetry: opts.telemetry } : {}),
|
|
218
236
|
get docs(): OutputDoc[] {
|
|
219
237
|
return getDocs();
|
|
220
238
|
},
|
|
@@ -43,7 +43,7 @@ const DELIBERATELY_UNDECLARED = new Map<string, string>([
|
|
|
43
43
|
[
|
|
44
44
|
"@cdktn/hcl2json",
|
|
45
45
|
"carries a ~1.8 MB wasm blob and is only needed by `chant carve`; " +
|
|
46
|
-
"`terraform/
|
|
46
|
+
"`terraform/hcl2json.ts` catches the failed import and prints the install line",
|
|
47
47
|
],
|
|
48
48
|
[
|
|
49
49
|
"@intentius/chant-lexicon-gitlab",
|
|
@@ -252,6 +252,29 @@ export const sourceArchiveContract = activityContract(
|
|
|
252
252
|
z.object({ digest: z.string(), archive: z.string(), commit: z.string(), dir: z.string(), files: z.number(), bytes: z.number() }),
|
|
253
253
|
);
|
|
254
254
|
|
|
255
|
+
const changeSetPart = z.object({
|
|
256
|
+
member: z.object({ member: z.string(), planDigest: z.string().nullable() }).passthrough(),
|
|
257
|
+
entries: z.array(z.unknown()),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
export const composeChangeSetContract = activityContract(
|
|
261
|
+
"composeChangeSet",
|
|
262
|
+
z.strictObject({ parts: z.array(changeSetPart) }),
|
|
263
|
+
z.object({ document: z.record(z.string(), z.unknown()), digest: z.string(), summary: z.record(z.string(), z.unknown()) }),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
export const lifecyclePlanChangeSetContract = activityContract(
|
|
267
|
+
"lifecyclePlanChangeSet",
|
|
268
|
+
z.strictObject({ member: z.string(), env: z.string(), cwd: z.string().optional(), owned: z.boolean().optional() }),
|
|
269
|
+
z.object({ part: changeSetPart }),
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
export const readChangeSetPartContract = activityContract(
|
|
273
|
+
"readChangeSetPart",
|
|
274
|
+
z.strictObject({ member: z.string(), planner: z.enum(["chant", "warden"]), file: z.string(), lexicon: z.string().optional() }),
|
|
275
|
+
z.object({ part: changeSetPart }),
|
|
276
|
+
);
|
|
277
|
+
|
|
255
278
|
export const releasePlanContract = activityContract(
|
|
256
279
|
"releasePlan",
|
|
257
280
|
z.strictObject({
|
|
@@ -356,3 +379,64 @@ export const releaseRollbackRecordContract = activityContract(
|
|
|
356
379
|
}),
|
|
357
380
|
z.object({ recorded: z.boolean(), digest: z.string(), env: z.string(), component: z.string(), approver: z.string().nullable() }),
|
|
358
381
|
);
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* The factory reference Op's activities (#3406, ws-087, ./factory.ts).
|
|
385
|
+
* OPS013 checks a later step's reference into each result, so `factoryOp`'s
|
|
386
|
+
* wiring (ask into build, build into check, all three into record) is
|
|
387
|
+
* validated at `chant build`.
|
|
388
|
+
*/
|
|
389
|
+
const factoryLease = z.unknown();
|
|
390
|
+
const factoryBackends = z.record(z.string(), backendSchema).optional();
|
|
391
|
+
|
|
392
|
+
export const factoryPickContract = activityContract(
|
|
393
|
+
"factoryPick",
|
|
394
|
+
z.strictObject({ cwd: z.string().optional(), kind: z.string().optional() }),
|
|
395
|
+
z.strictObject({
|
|
396
|
+
candidates: z.array(z.string()),
|
|
397
|
+
held: z.array(z.object({ item: z.string(), hold: z.string(), message: z.string() })),
|
|
398
|
+
keys: z.array(z.string()),
|
|
399
|
+
}),
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
export const factoryReadyContract = activityContract(
|
|
403
|
+
"factoryReady",
|
|
404
|
+
z.strictObject({ cwd: z.string().optional(), kind: z.string().optional(), also: z.string().optional() }),
|
|
405
|
+
z.array(z.string()),
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
export const factoryAskContract = activityContract(
|
|
409
|
+
"factoryAsk",
|
|
410
|
+
z.strictObject({ lease: factoryLease, cwd: z.string().optional(), kind: z.string().optional(), backends: factoryBackends }),
|
|
411
|
+
z.strictObject({
|
|
412
|
+
item: z.string(),
|
|
413
|
+
ask: z.boolean(),
|
|
414
|
+
tier: z.string(),
|
|
415
|
+
understand: z.string().nullable(),
|
|
416
|
+
outcome: z.enum(["dropped", "redraft", "ask"]).nullable(),
|
|
417
|
+
}),
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
export const factoryBuildContract = activityContract(
|
|
421
|
+
"factoryBuild",
|
|
422
|
+
z.strictObject({ lease: factoryLease, ask: z.unknown(), builder: z.string().min(1), context: z.string().optional(), cwd: z.string().optional() }),
|
|
423
|
+
z.strictObject({ ran: z.boolean(), finished: z.boolean(), exitCode: z.number().nullable(), reverted: z.array(z.string()), note: z.string(), report: z.record(z.string(), z.unknown()).nullable() }),
|
|
424
|
+
);
|
|
425
|
+
|
|
426
|
+
export const factoryCheckContract = activityContract(
|
|
427
|
+
"factoryCheck",
|
|
428
|
+
z.strictObject({ lease: factoryLease, build: z.unknown(), check: z.string().optional(), cwd: z.string().optional() }),
|
|
429
|
+
z.strictObject({ ran: z.boolean(), ok: z.boolean(), command: z.string().nullable(), evidence: z.array(z.string()), log: z.string().nullable(), report: z.record(z.string(), z.unknown()).nullable() }),
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
export const factoryRecordContract = activityContract(
|
|
433
|
+
"factoryRecord",
|
|
434
|
+
z.strictObject({ lease: factoryLease, ask: z.unknown(), build: z.unknown(), check: z.unknown(), after: z.string().optional(), cwd: z.string().optional() }),
|
|
435
|
+
z.strictObject({
|
|
436
|
+
outcome: z.enum(["done", "not_done", "dropped", "redraft", "ask"]),
|
|
437
|
+
reason: z.string().nullable(),
|
|
438
|
+
commit: z.string().nullable(),
|
|
439
|
+
implementsProposed: z.array(z.object({ decision: z.string(), paths: z.array(z.string()) })),
|
|
440
|
+
}),
|
|
441
|
+
);
|
|
442
|
+
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Op activities for the change-set document (#3181).
|
|
3
|
+
*
|
|
4
|
+
* A combined run over several members plans each one in its own step, joins
|
|
5
|
+
* the parts with {@link composeChangeSet}, and binds its gate to the
|
|
6
|
+
* document's digest:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* phase("Plan", [
|
|
10
|
+
* terraformPlan({ root: "estate", id: "estate" }), // a choudoufu member
|
|
11
|
+
* lifecyclePlanChangeSet({ member: "delivery", env: "prod", cwd: "delivery", id: "delivery" }),
|
|
12
|
+
* readChangeSetPart({ member: "warden", planner: "warden", file: "warden.plan.json", id: "warden" }),
|
|
13
|
+
* composeChangeSet({ parts: [estate.out.changeSet, delivery.out.part, warden.out.part], id: "change-set" }),
|
|
14
|
+
* ]),
|
|
15
|
+
* phase("Approve", [gate("approve-run", { plan: stepOutput("change-set", "digest") })]),
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Each activity here only reads: a plan, a file, or the parts it is handed.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { exec } from "node:child_process";
|
|
22
|
+
import { readFileSync } from "node:fs";
|
|
23
|
+
import { resolve } from "node:path";
|
|
24
|
+
import { promisify } from "node:util";
|
|
25
|
+
import {
|
|
26
|
+
composeChangeSet as compose,
|
|
27
|
+
lifecyclePlanPart,
|
|
28
|
+
reconcilePlanPart,
|
|
29
|
+
type ChangeSetDocument,
|
|
30
|
+
type ChangeSetPart,
|
|
31
|
+
type ChangeSetSummary,
|
|
32
|
+
} from "../../change-set";
|
|
33
|
+
import type { ChangeSet as LifecycleChangeSet } from "../../lifecycle/change-set";
|
|
34
|
+
import type { ChangeSet as ReconcileChangeSet } from "../../reconcile";
|
|
35
|
+
import { CHANT_VERSION } from "../../cli/version";
|
|
36
|
+
|
|
37
|
+
const execAsync = promisify(exec);
|
|
38
|
+
|
|
39
|
+
export interface ComposeChangeSetArgs {
|
|
40
|
+
/** One part per member, usually step outputs: `terraformPlan`'s `changeSet`, the other activities' `part`. */
|
|
41
|
+
parts: ChangeSetPart[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ComposeChangeSetResult {
|
|
45
|
+
document: ChangeSetDocument;
|
|
46
|
+
/** The document's digest. A gate's `plan` binds it. */
|
|
47
|
+
digest: string;
|
|
48
|
+
summary: ChangeSetSummary;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Join members' parts into one change-set document. Fails when two parts name the same member. */
|
|
52
|
+
export async function composeChangeSet(args: ComposeChangeSetArgs): Promise<ComposeChangeSetResult> {
|
|
53
|
+
const parts = args.parts ?? [];
|
|
54
|
+
const missing = parts.findIndex((p) => !p || typeof p !== "object" || !p.member);
|
|
55
|
+
if (missing !== -1) throw new Error(`composeChangeSet: parts[${missing}] is not a change-set part; did the step that plans it run?`);
|
|
56
|
+
const document = compose(parts, { chant: CHANT_VERSION });
|
|
57
|
+
return { document, digest: document.digest, summary: document.summary };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface LifecyclePlanChangeSetArgs {
|
|
61
|
+
/** The workspace member the plan is of. */
|
|
62
|
+
member: string;
|
|
63
|
+
env: string;
|
|
64
|
+
/** The member's directory. Default: the current directory. */
|
|
65
|
+
cwd?: string;
|
|
66
|
+
/** Pass `--owned`, so owned resources missing from source plan as deletes. */
|
|
67
|
+
owned?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ChangeSetPartResult {
|
|
71
|
+
part: ChangeSetPart;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function shellQuote(s: string): string {
|
|
75
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** `chant lifecycle plan <env> --json` in a chant member's directory, as that member's change-set part. */
|
|
79
|
+
export async function lifecyclePlanChangeSet(args: LifecyclePlanChangeSetArgs, signal?: AbortSignal): Promise<ChangeSetPartResult> {
|
|
80
|
+
const { stdout } = await execAsync(`chant lifecycle plan ${shellQuote(args.env)}${args.owned ? " --owned" : ""} --json`, {
|
|
81
|
+
cwd: args.cwd ? resolve(args.cwd) : process.cwd(),
|
|
82
|
+
signal,
|
|
83
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
84
|
+
});
|
|
85
|
+
return { part: lifecyclePlanPart({ member: args.member, plan: JSON.parse(stdout) as LifecycleChangeSet }) };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface ReadChangeSetPartArgs {
|
|
89
|
+
member: string;
|
|
90
|
+
/** Which planner wrote the file: `chant` (`lifecycle plan --json`) or `warden` (its reconcile change sets). */
|
|
91
|
+
planner: "chant" | "warden";
|
|
92
|
+
/** The plan file, relative to the current directory. */
|
|
93
|
+
file: string;
|
|
94
|
+
/** The lexicon the entries belong to, when the plan does not say. */
|
|
95
|
+
lexicon?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A plan another step or job wrote to a file, as a member's part. A warden
|
|
100
|
+
* plan is the reconcile `ChangeSet` (`@intentius/chant/reconcile`), or an
|
|
101
|
+
* array of them, one per cycle and org.
|
|
102
|
+
*/
|
|
103
|
+
export async function readChangeSetPart(args: ReadChangeSetPartArgs): Promise<ChangeSetPartResult> {
|
|
104
|
+
const plan: unknown = JSON.parse(readFileSync(resolve(args.file), "utf-8"));
|
|
105
|
+
const lexicon = args.lexicon !== undefined ? { lexicon: args.lexicon } : {};
|
|
106
|
+
switch (args.planner) {
|
|
107
|
+
case "chant":
|
|
108
|
+
return { part: lifecyclePlanPart({ member: args.member, plan: plan as LifecycleChangeSet, ...lexicon }) };
|
|
109
|
+
case "warden":
|
|
110
|
+
return { part: reconcilePlanPart({ member: args.member, plan: plan as ReconcileChangeSet | ReconcileChangeSet[], ...lexicon }) };
|
|
111
|
+
default:
|
|
112
|
+
throw new Error(`readChangeSetPart: no adapter for planner ${String(args.planner)}; terraform-family plans come from terraformPlan's changeSet`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -84,6 +84,8 @@ export interface DecideResult {
|
|
|
84
84
|
backend: string | null;
|
|
85
85
|
confidence: number | null;
|
|
86
86
|
threshold: number | null;
|
|
87
|
+
/** For a model's answer: the model's own explanation of it, when the backend gave one (#3345). */
|
|
88
|
+
reason: string | null;
|
|
87
89
|
/** The people who answered, when people did. */
|
|
88
90
|
answeredBy: string[];
|
|
89
91
|
/** Each decider that was asked and did not answer, and why. */
|
|
@@ -159,6 +161,7 @@ function result(q: QuestionView, missing: string[]): DecideResult {
|
|
|
159
161
|
backend: byModel ? (q.model?.backend ?? null) : null,
|
|
160
162
|
confidence: byModel ? q.confidence : null,
|
|
161
163
|
threshold: byModel ? q.threshold : null,
|
|
164
|
+
reason: byModel ? q.reason : null,
|
|
162
165
|
answeredBy: q.answeredBy,
|
|
163
166
|
escalations: q.escalations,
|
|
164
167
|
missing,
|