@intentius/chant 0.102.0 → 0.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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/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/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/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
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/chant/schemas/workspace/wip/v1/wip.schema.json",
|
|
4
|
+
"title": "chant workspace wip output",
|
|
5
|
+
"description": "What `chant workspace wip [--branch <branch>] --json` prints (#3172, ws-085): the work-in-progress snapshots chant keeps under refs/chant/wip/<branch>, newest first, and, when a box block declares replicate, how far each ref the policy names is from its remote. It reads local refs and never fetches. Version 1 of the read contract. Readers ignore fields they do not know; a field is only ever added within a version. The codes are a closed list, each in the one closed list of `reason-codes.ts`. Contract version 1 of this document is written by chant 0.103.0 and newer.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{
|
|
8
|
+
"$ref": "#/$defs/result"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"$ref": "#/$defs/failure"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"$defs": {
|
|
15
|
+
"result": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"description": "Exit code 0.",
|
|
18
|
+
"required": [
|
|
19
|
+
"$schema",
|
|
20
|
+
"contract",
|
|
21
|
+
"chant",
|
|
22
|
+
"checkout",
|
|
23
|
+
"branches",
|
|
24
|
+
"replication"
|
|
25
|
+
],
|
|
26
|
+
"properties": {
|
|
27
|
+
"$schema": {
|
|
28
|
+
"const": "https://intentius.io/chant/schemas/workspace/wip/v1/wip.schema.json"
|
|
29
|
+
},
|
|
30
|
+
"contract": {
|
|
31
|
+
"const": 1
|
|
32
|
+
},
|
|
33
|
+
"chant": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"error": false,
|
|
37
|
+
"checkout": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": [
|
|
40
|
+
"branch",
|
|
41
|
+
"head"
|
|
42
|
+
],
|
|
43
|
+
"description": "The branch and commit the checkout is on; null for a detached HEAD or a branch with no commit.",
|
|
44
|
+
"properties": {
|
|
45
|
+
"branch": {
|
|
46
|
+
"type": [
|
|
47
|
+
"string",
|
|
48
|
+
"null"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"head": {
|
|
52
|
+
"type": [
|
|
53
|
+
"string",
|
|
54
|
+
"null"
|
|
55
|
+
],
|
|
56
|
+
"pattern": "^[0-9a-f]{40,64}$"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"branches": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"description": "Each branch with snapshots, sorted by branch; only --branch's when it is given.",
|
|
63
|
+
"items": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"required": [
|
|
66
|
+
"branch",
|
|
67
|
+
"ref",
|
|
68
|
+
"tip",
|
|
69
|
+
"snapshots"
|
|
70
|
+
],
|
|
71
|
+
"properties": {
|
|
72
|
+
"branch": {
|
|
73
|
+
"type": "string"
|
|
74
|
+
},
|
|
75
|
+
"ref": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"description": "refs/chant/wip/<branch>."
|
|
78
|
+
},
|
|
79
|
+
"tip": {
|
|
80
|
+
"type": "string",
|
|
81
|
+
"pattern": "^[0-9a-f]{40,64}$"
|
|
82
|
+
},
|
|
83
|
+
"snapshots": {
|
|
84
|
+
"type": "array",
|
|
85
|
+
"items": {
|
|
86
|
+
"$ref": "#/$defs/snapshot"
|
|
87
|
+
},
|
|
88
|
+
"description": "The ref's first-parent chain, newest first: the branch's checkpoint history."
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"replication": {
|
|
94
|
+
"description": "Where replication stands, or null when no box block declares replicate.",
|
|
95
|
+
"oneOf": [
|
|
96
|
+
{
|
|
97
|
+
"type": "null"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"$ref": "#/$defs/replication"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"failure": {
|
|
107
|
+
"type": "object",
|
|
108
|
+
"description": "Nothing was read or written. Exit code 1.",
|
|
109
|
+
"required": [
|
|
110
|
+
"$schema",
|
|
111
|
+
"contract",
|
|
112
|
+
"chant",
|
|
113
|
+
"error"
|
|
114
|
+
],
|
|
115
|
+
"properties": {
|
|
116
|
+
"$schema": {
|
|
117
|
+
"const": "https://intentius.io/chant/schemas/workspace/wip/v1/wip.schema.json"
|
|
118
|
+
},
|
|
119
|
+
"contract": {
|
|
120
|
+
"const": 1
|
|
121
|
+
},
|
|
122
|
+
"chant": {
|
|
123
|
+
"type": "string"
|
|
124
|
+
},
|
|
125
|
+
"error": {
|
|
126
|
+
"type": "object",
|
|
127
|
+
"required": [
|
|
128
|
+
"code",
|
|
129
|
+
"message"
|
|
130
|
+
],
|
|
131
|
+
"properties": {
|
|
132
|
+
"code": {
|
|
133
|
+
"enum": [
|
|
134
|
+
"declaration-missing",
|
|
135
|
+
"declaration-ambiguous",
|
|
136
|
+
"declaration-unparseable",
|
|
137
|
+
"declaration-invalid",
|
|
138
|
+
"placement-invalid",
|
|
139
|
+
"reader-too-old",
|
|
140
|
+
"root-chant-required",
|
|
141
|
+
"not-a-git-repository",
|
|
142
|
+
"revision-unknown"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"message": {
|
|
146
|
+
"type": "string"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"snapshot": {
|
|
153
|
+
"type": "object",
|
|
154
|
+
"description": "One snapshot of a branch's working tree: a commit whose tree is the whole working tree, staged, unstaged and untracked files alike, ignored files left out. Its first parent is the snapshot before it on the same ref, when there is one, and its last parent is head.",
|
|
155
|
+
"required": [
|
|
156
|
+
"commit",
|
|
157
|
+
"tree",
|
|
158
|
+
"branch",
|
|
159
|
+
"head",
|
|
160
|
+
"kind",
|
|
161
|
+
"label",
|
|
162
|
+
"by",
|
|
163
|
+
"at"
|
|
164
|
+
],
|
|
165
|
+
"properties": {
|
|
166
|
+
"commit": {
|
|
167
|
+
"type": "string",
|
|
168
|
+
"pattern": "^[0-9a-f]{40,64}$",
|
|
169
|
+
"description": "The snapshot commit. wip restore <commit> puts the working tree back as it holds it."
|
|
170
|
+
},
|
|
171
|
+
"tree": {
|
|
172
|
+
"type": "string",
|
|
173
|
+
"pattern": "^[0-9a-f]{40,64}$",
|
|
174
|
+
"description": "The tree of the working tree as it was. Two snapshots with the same tree hold the same files."
|
|
175
|
+
},
|
|
176
|
+
"branch": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"description": "The branch it was taken on (trailer Chant-Wip-Branch)."
|
|
179
|
+
},
|
|
180
|
+
"head": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
"pattern": "^[0-9a-f]{40,64}$",
|
|
183
|
+
"description": "The commit HEAD named when it was taken (Chant-Wip-Head)."
|
|
184
|
+
},
|
|
185
|
+
"kind": {
|
|
186
|
+
"enum": [
|
|
187
|
+
"save",
|
|
188
|
+
"pre-restore"
|
|
189
|
+
],
|
|
190
|
+
"description": "save for wip save; pre-restore for the snapshot wip restore takes of the working tree before it changes it, so a restore can be undone (Chant-Wip-Kind)."
|
|
191
|
+
},
|
|
192
|
+
"label": {
|
|
193
|
+
"type": [
|
|
194
|
+
"string",
|
|
195
|
+
"null"
|
|
196
|
+
],
|
|
197
|
+
"description": "What the caller called it with --label, such as a turn id, or null (Chant-Wip-Label). A pre-restore snapshot is labelled before <the restored snapshot's first 12 characters>."
|
|
198
|
+
},
|
|
199
|
+
"by": {
|
|
200
|
+
"type": [
|
|
201
|
+
"string",
|
|
202
|
+
"null"
|
|
203
|
+
],
|
|
204
|
+
"description": "Who took it, as --by named them, or null (Chant-Wip-By)."
|
|
205
|
+
},
|
|
206
|
+
"at": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"description": "When it was taken: the commit's committer time."
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"policy": {
|
|
213
|
+
"type": "object",
|
|
214
|
+
"description": "The replicate policy the declaration in the working tree states (box.replicate), with every default filled in.",
|
|
215
|
+
"required": [
|
|
216
|
+
"box",
|
|
217
|
+
"remote",
|
|
218
|
+
"refs",
|
|
219
|
+
"on",
|
|
220
|
+
"every"
|
|
221
|
+
],
|
|
222
|
+
"properties": {
|
|
223
|
+
"box": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"description": "The member whose box block declares it."
|
|
226
|
+
},
|
|
227
|
+
"remote": {
|
|
228
|
+
"type": "string",
|
|
229
|
+
"description": "The git remote it pushes to, by name."
|
|
230
|
+
},
|
|
231
|
+
"refs": {
|
|
232
|
+
"type": "array",
|
|
233
|
+
"items": {
|
|
234
|
+
"enum": [
|
|
235
|
+
"work",
|
|
236
|
+
"kept",
|
|
237
|
+
"wip",
|
|
238
|
+
"ledger"
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
"description": "What it replicates, in this order: work (refs/heads/chant/work/...), kept (refs/chant/kept/...), wip (refs/chant/wip/...) and ledger (refs/heads/chant/lifecycle)."
|
|
242
|
+
},
|
|
243
|
+
"on": {
|
|
244
|
+
"type": "array",
|
|
245
|
+
"items": {
|
|
246
|
+
"enum": [
|
|
247
|
+
"save",
|
|
248
|
+
"release"
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
"description": "When chant pushes on its own: after a wip save, after a work lease release."
|
|
252
|
+
},
|
|
253
|
+
"every": {
|
|
254
|
+
"type": [
|
|
255
|
+
"string",
|
|
256
|
+
"null"
|
|
257
|
+
],
|
|
258
|
+
"description": "The interval at which the host runs wip push, or null."
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
"replication": {
|
|
263
|
+
"type": "object",
|
|
264
|
+
"description": "Where every ref the policy names stands against its remote, read locally: what reached the remote is what chant recorded under refs/chant/replica/<remote>/ at its last push or fetch, or for a branch git's remote-tracking ref. Never fetches.",
|
|
265
|
+
"required": [
|
|
266
|
+
"policy",
|
|
267
|
+
"remoteConfigured",
|
|
268
|
+
"replicated",
|
|
269
|
+
"refs"
|
|
270
|
+
],
|
|
271
|
+
"properties": {
|
|
272
|
+
"policy": {
|
|
273
|
+
"$ref": "#/$defs/policy"
|
|
274
|
+
},
|
|
275
|
+
"remoteConfigured": {
|
|
276
|
+
"type": "boolean",
|
|
277
|
+
"description": "Whether the checkout has a git remote of the policy's name."
|
|
278
|
+
},
|
|
279
|
+
"replicated": {
|
|
280
|
+
"type": "boolean",
|
|
281
|
+
"description": "True when every ref listed is on the remote as it is locally."
|
|
282
|
+
},
|
|
283
|
+
"refs": {
|
|
284
|
+
"type": "array",
|
|
285
|
+
"description": "Every local ref the policy names, sorted by ref.",
|
|
286
|
+
"items": {
|
|
287
|
+
"type": "object",
|
|
288
|
+
"required": [
|
|
289
|
+
"ref",
|
|
290
|
+
"class",
|
|
291
|
+
"commit",
|
|
292
|
+
"replica",
|
|
293
|
+
"replicated",
|
|
294
|
+
"ahead"
|
|
295
|
+
],
|
|
296
|
+
"properties": {
|
|
297
|
+
"ref": {
|
|
298
|
+
"type": "string"
|
|
299
|
+
},
|
|
300
|
+
"class": {
|
|
301
|
+
"enum": [
|
|
302
|
+
"work",
|
|
303
|
+
"kept",
|
|
304
|
+
"wip",
|
|
305
|
+
"ledger"
|
|
306
|
+
]
|
|
307
|
+
},
|
|
308
|
+
"commit": {
|
|
309
|
+
"type": "string",
|
|
310
|
+
"pattern": "^[0-9a-f]{40,64}$"
|
|
311
|
+
},
|
|
312
|
+
"replica": {
|
|
313
|
+
"type": [
|
|
314
|
+
"string",
|
|
315
|
+
"null"
|
|
316
|
+
],
|
|
317
|
+
"pattern": "^[0-9a-f]{40,64}$",
|
|
318
|
+
"description": "What the remote holds of the ref as chant last saw it, or null when unknown."
|
|
319
|
+
},
|
|
320
|
+
"replicated": {
|
|
321
|
+
"type": "boolean"
|
|
322
|
+
},
|
|
323
|
+
"ahead": {
|
|
324
|
+
"type": "integer",
|
|
325
|
+
"minimum": 0,
|
|
326
|
+
"description": "Commits reachable from commit that nothing known to be on the remote reaches; 0 when replicated."
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #3172 — work in progress under refs/chant/wip/<branch>: snapshots that
|
|
3
|
+
* leave the index and the branch alone, restore that checkpoints first, and
|
|
4
|
+
* replication to a remote under the box's policy, down to a box that is lost
|
|
5
|
+
* and replaced.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { afterAll, describe, expect, test } from "vitest";
|
|
12
|
+
import { parseDeclaration } from "./declaration";
|
|
13
|
+
import { cleanScratch, commitAll, contract, declaration, git, repo, scratchDir, writeFiles } from "./__fixtures__/contract-repo";
|
|
14
|
+
import { readReplicatePolicy, replicaRef, replicationState, wipFetch, wipPush, wipRestore, wipSave, workspaceWip, type WipWriteDocument } from "./wip";
|
|
15
|
+
import wipSchema from "./wip.schema.json";
|
|
16
|
+
import wipWriteSchema from "./wip-write.schema.json";
|
|
17
|
+
import statusSchema from "./status.schema.json";
|
|
18
|
+
import { workspaceStatus } from "./status";
|
|
19
|
+
|
|
20
|
+
afterAll(cleanScratch);
|
|
21
|
+
|
|
22
|
+
const read = contract(wipSchema);
|
|
23
|
+
const write = contract(wipWriteSchema);
|
|
24
|
+
|
|
25
|
+
function ok<A extends string>(doc: WipWriteDocument, action: A): Extract<WipWriteDocument, { action: A; branch?: unknown }> & Record<string, unknown> {
|
|
26
|
+
write.expectValid(doc);
|
|
27
|
+
if ("error" in doc) throw new Error(`${doc.error.code}: ${doc.error.message}`);
|
|
28
|
+
expect(doc.action).toBe(action);
|
|
29
|
+
return doc as never;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function refused(doc: WipWriteDocument): string {
|
|
33
|
+
write.expectValid(doc);
|
|
34
|
+
if (!("error" in doc)) throw new Error(`expected a refusal, got ${JSON.stringify(doc)}`);
|
|
35
|
+
return doc.error.code;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const sha = (file: string) => createHash("sha256").update(readFileSync(file)).digest("hex");
|
|
39
|
+
|
|
40
|
+
/** A workspace on branch chant/work/W-001 with one committed file. */
|
|
41
|
+
function box(extraDecl: Record<string, unknown> = {}, replicate?: Record<string, unknown>): string {
|
|
42
|
+
const root = repo({
|
|
43
|
+
"chant.workspace.json": declaration([{ name: "app", dir: "app", kind: "other", because: "the app", box: replicate === undefined ? {} : { replicate } }], extraDecl),
|
|
44
|
+
"app/server.mjs": "export const port = 8080;\n",
|
|
45
|
+
".gitignore": "node_modules/\n",
|
|
46
|
+
});
|
|
47
|
+
git(root, "symbolic-ref", "HEAD", "refs/heads/main");
|
|
48
|
+
commitAll(root, "the app");
|
|
49
|
+
git(root, "checkout", "-q", "-b", "chant/work/W-001");
|
|
50
|
+
return root;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("the replicate policy on the box block (#3172)", () => {
|
|
54
|
+
const decl = (box: unknown, more: unknown[] = []) => JSON.stringify({ name: "w", schema: 1, members: [{ name: "app", dir: "app", kind: "other", because: "x", box }, ...more] });
|
|
55
|
+
|
|
56
|
+
test("parses with every default filled in, in the closed lists' order", () => {
|
|
57
|
+
expect(parseDeclaration(decl({ replicate: {} }), "chant.workspace.json").members[0].box!.replicate).toEqual({
|
|
58
|
+
remote: "origin",
|
|
59
|
+
refs: ["work", "kept", "wip", "ledger"],
|
|
60
|
+
on: ["save", "release"],
|
|
61
|
+
every: null,
|
|
62
|
+
pointer: "/members/0/box/replicate",
|
|
63
|
+
});
|
|
64
|
+
expect(parseDeclaration(decl({ replicate: { remote: "mirror", refs: ["wip", "kept"], on: [], every: "10m" } }), "chant.workspace.json").members[0].box!.replicate).toMatchObject({
|
|
65
|
+
remote: "mirror",
|
|
66
|
+
refs: ["kept", "wip"],
|
|
67
|
+
on: [],
|
|
68
|
+
every: "10m",
|
|
69
|
+
});
|
|
70
|
+
expect(parseDeclaration(decl({}), "chant.workspace.json").members[0].box!.replicate).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("a workspace has one policy, and the schema refuses what it doesn't know", () => {
|
|
74
|
+
const two = decl({ replicate: {} }, [{ name: "b", dir: "b", kind: "other", because: "x", box: { replicate: {} } }]);
|
|
75
|
+
expect(() => parseDeclaration(two, "chant.workspace.json")).toThrow(/both declare replicate/);
|
|
76
|
+
expect(() => parseDeclaration(decl({ replicate: { refs: ["everything"] } }), "chant.workspace.json")).toThrow();
|
|
77
|
+
expect(() => parseDeclaration(decl({ replicate: { on: ["write"] } }), "chant.workspace.json")).toThrow();
|
|
78
|
+
expect(() => parseDeclaration(decl({ replicate: { every: "soon" } }), "chant.workspace.json")).toThrow();
|
|
79
|
+
expect(() => parseDeclaration(decl({ replicate: { remote: "https://example.com/x.git" } }), "chant.workspace.json")).toThrow();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("wip save (#3172)", () => {
|
|
84
|
+
test("snapshots staged, unstaged and untracked files without touching the index, HEAD or the branch", () => {
|
|
85
|
+
const root = box();
|
|
86
|
+
writeFiles(root, { "app/server.mjs": "export const port = 9090;\n", "app/staged.mjs": "staged\n", "decisions/fix-001.md": "uncommitted record\n", "node_modules/x.js": "ignored\n" });
|
|
87
|
+
git(root, "add", "app/staged.mjs");
|
|
88
|
+
const index = sha(join(root, ".git", "index"));
|
|
89
|
+
const head = git(root, "rev-parse", "HEAD");
|
|
90
|
+
const statusBefore = git(root, "status", "--porcelain");
|
|
91
|
+
|
|
92
|
+
const doc = ok(wipSave({ cwd: root, label: "turn:1", by: "github:alex" }), "save");
|
|
93
|
+
expect(doc).toMatchObject({ branch: "chant/work/W-001", ref: "refs/chant/wip/chant/work/W-001", created: true, replication: null });
|
|
94
|
+
expect(doc.snapshot).toMatchObject({ branch: "chant/work/W-001", head, kind: "save", label: "turn:1", by: "github:alex" });
|
|
95
|
+
expect(sha(join(root, ".git", "index"))).toBe(index);
|
|
96
|
+
expect(git(root, "rev-parse", "HEAD")).toBe(head);
|
|
97
|
+
expect(git(root, "status", "--porcelain")).toBe(statusBefore);
|
|
98
|
+
const files = git(root, "ls-tree", "-r", "--name-only", doc.snapshot.commit).split("\n");
|
|
99
|
+
expect(files).toEqual(expect.arrayContaining(["app/server.mjs", "app/staged.mjs", "decisions/fix-001.md"]));
|
|
100
|
+
expect(files).not.toContain("node_modules/x.js");
|
|
101
|
+
expect(git(root, "show", `${doc.snapshot.commit}:app/server.mjs`)).toBe("export const port = 9090;");
|
|
102
|
+
// The snapshot's last parent is HEAD, so pushing the ref carries the branch's commits.
|
|
103
|
+
expect(git(root, "rev-parse", `${doc.snapshot.commit}^1`)).toBe(head);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("the same tree, head, label and principal take no new snapshot; anything else chains onto the last", () => {
|
|
107
|
+
const root = box();
|
|
108
|
+
writeFiles(root, { "a.txt": "1\n" });
|
|
109
|
+
const first = ok(wipSave({ cwd: root }), "save");
|
|
110
|
+
const again = ok(wipSave({ cwd: root }), "save");
|
|
111
|
+
expect(again.created).toBe(false);
|
|
112
|
+
expect(again.snapshot.commit).toBe(first.snapshot.commit);
|
|
113
|
+
const labelled = ok(wipSave({ cwd: root, label: "turn:2" }), "save");
|
|
114
|
+
expect(labelled.created).toBe(true);
|
|
115
|
+
writeFiles(root, { "a.txt": "2\n" });
|
|
116
|
+
const third = ok(wipSave({ cwd: root, label: "turn:3" }), "save");
|
|
117
|
+
expect(git(root, "rev-parse", `${third.snapshot.commit}^1`)).toBe(labelled.snapshot.commit);
|
|
118
|
+
|
|
119
|
+
const list = workspaceWip({ cwd: root });
|
|
120
|
+
read.expectValid(list);
|
|
121
|
+
if ("error" in list) throw new Error(list.error.message);
|
|
122
|
+
expect(list.checkout.branch).toBe("chant/work/W-001");
|
|
123
|
+
expect(list.branches).toHaveLength(1);
|
|
124
|
+
expect(list.branches[0].tip).toBe(third.snapshot.commit);
|
|
125
|
+
expect(list.branches[0].snapshots.map((s) => s.label)).toEqual(["turn:3", "turn:2", null]);
|
|
126
|
+
expect(list.replication).toBeNull();
|
|
127
|
+
expect(workspaceWip({ cwd: root, branch: "other" })).toMatchObject({ branches: [] });
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("refuses a detached HEAD, a branch with no commit and a label that isn't one line", () => {
|
|
131
|
+
const root = box();
|
|
132
|
+
git(root, "checkout", "-q", "--detach");
|
|
133
|
+
expect(refused(wipSave({ cwd: root }))).toBe("wip-no-branch");
|
|
134
|
+
const empty = repo({ "x.txt": "x\n" });
|
|
135
|
+
expect(refused(wipSave({ cwd: empty }))).toBe("wip-no-branch");
|
|
136
|
+
git(root, "checkout", "-q", "chant/work/W-001");
|
|
137
|
+
expect(refused(wipSave({ cwd: root, label: "two\nlines" }))).toBe("write-usage-invalid");
|
|
138
|
+
expect(refused(wipSave({ cwd: scratchDir() }))).toBe("not-a-git-repository");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("--by is held to the identity rule at base (ws-080)", () => {
|
|
142
|
+
const root = box({ identity: { attribution: "identified" } });
|
|
143
|
+
expect(refused(wipSave({ cwd: root, by: "alex" }))).toBe("principal-unidentified");
|
|
144
|
+
ok(wipSave({ cwd: root, by: "github:alex" }), "save");
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe("wip restore (#3172)", () => {
|
|
149
|
+
test("puts the working tree back exactly, after a checkpoint of how it was, and the checkpoint undoes it", () => {
|
|
150
|
+
const root = box();
|
|
151
|
+
writeFiles(root, { "app/server.mjs": "export const port = 1;\n", "decisions/fix-001.md": "kept\n" });
|
|
152
|
+
const saved = ok(wipSave({ cwd: root, label: "turn:1" }), "save");
|
|
153
|
+
// The next turn breaks things: edits, deletes the record, adds a file, stages one.
|
|
154
|
+
writeFiles(root, { "app/server.mjs": "broken\n", "junk.txt": "junk\n" });
|
|
155
|
+
rmSync(join(root, "decisions/fix-001.md"));
|
|
156
|
+
git(root, "add", "junk.txt");
|
|
157
|
+
|
|
158
|
+
const doc = ok(wipRestore({ cwd: root, snapshot: saved.snapshot.commit }), "restore");
|
|
159
|
+
expect(doc.paths).toEqual(["app/server.mjs", "decisions/fix-001.md", "junk.txt"]);
|
|
160
|
+
expect(doc.headMoved).toBe(false);
|
|
161
|
+
expect(doc.checkpoint.created).toBe(true);
|
|
162
|
+
expect(doc.checkpoint.snapshot).toMatchObject({ kind: "pre-restore", label: `before ${saved.snapshot.commit.slice(0, 12)}` });
|
|
163
|
+
expect(readFileSync(join(root, "app/server.mjs"), "utf-8")).toBe("export const port = 1;\n");
|
|
164
|
+
expect(readFileSync(join(root, "decisions/fix-001.md"), "utf-8")).toBe("kept\n");
|
|
165
|
+
expect(existsSync(join(root, "junk.txt"))).toBe(false);
|
|
166
|
+
// The index is HEAD's: everything restored reads as uncommitted.
|
|
167
|
+
expect(git(root, "diff", "--cached", "--name-only")).toBe("");
|
|
168
|
+
|
|
169
|
+
const undo = ok(wipRestore({ cwd: root, snapshot: doc.checkpoint.snapshot.commit }), "restore");
|
|
170
|
+
expect(undo.paths).toEqual(["app/server.mjs", "decisions/fix-001.md", "junk.txt"]);
|
|
171
|
+
expect(readFileSync(join(root, "app/server.mjs"), "utf-8")).toBe("broken\n");
|
|
172
|
+
expect(existsSync(join(root, "decisions/fix-001.md"))).toBe(false);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("restores the branch's latest by default, over a HEAD that has moved on, and refuses what it can't", () => {
|
|
176
|
+
const root = box();
|
|
177
|
+
expect(refused(wipRestore({ cwd: root }))).toBe("wip-none");
|
|
178
|
+
writeFiles(root, { "a.txt": "a\n" });
|
|
179
|
+
const saved = ok(wipSave({ cwd: root }), "save");
|
|
180
|
+
commitAll(root, "a commit after the snapshot");
|
|
181
|
+
writeFiles(root, { "a.txt": "changed\n" });
|
|
182
|
+
const doc = ok(wipRestore({ cwd: root }), "restore");
|
|
183
|
+
expect(doc.snapshot.commit).toBe(saved.snapshot.commit);
|
|
184
|
+
expect(doc.headMoved).toBe(true);
|
|
185
|
+
expect(readFileSync(join(root, "a.txt"), "utf-8")).toBe("a\n");
|
|
186
|
+
|
|
187
|
+
expect(refused(wipRestore({ cwd: root, snapshot: "HEAD" }))).toBe("wip-snapshot-unknown");
|
|
188
|
+
expect(refused(wipRestore({ cwd: root, snapshot: "no-such-rev" }))).toBe("wip-snapshot-unknown");
|
|
189
|
+
git(root, "checkout", "-q", "-b", "chant/work/W-002");
|
|
190
|
+
expect(refused(wipRestore({ cwd: root, snapshot: saved.snapshot.commit }))).toBe("wip-branch-other");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("replication (#3172)", () => {
|
|
195
|
+
/** A bare remote, and a box cloned from it with the policy declared. */
|
|
196
|
+
function boxWithRemote(replicate: Record<string, unknown> = {}): { remote: string; root: string } {
|
|
197
|
+
const remote = scratchDir("chant-wip-remote-");
|
|
198
|
+
git(remote, "init", "-q", "--bare");
|
|
199
|
+
git(remote, "symbolic-ref", "HEAD", "refs/heads/main");
|
|
200
|
+
const root = box({}, replicate);
|
|
201
|
+
git(root, "remote", "add", "origin", remote);
|
|
202
|
+
git(root, "push", "-q", "origin", "main", "chant/work/W-001");
|
|
203
|
+
return { remote, root };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
test("save pushes the snapshot, the work branch, kept attempts and the ledger, never forced, and status reports where each stands", async () => {
|
|
207
|
+
const { remote, root } = boxWithRemote();
|
|
208
|
+
expect(readReplicatePolicy(root)).toEqual({ box: "app", remote: "origin", refs: ["work", "kept", "wip", "ledger"], on: ["save", "release"], every: null });
|
|
209
|
+
writeFiles(root, { "app/more.mjs": "more\n" });
|
|
210
|
+
commitAll(root, "unpushed work");
|
|
211
|
+
git(root, "update-ref", "refs/chant/kept/W-001/tok-1", "HEAD");
|
|
212
|
+
git(root, "branch", "chant/lifecycle");
|
|
213
|
+
writeFiles(root, { "decisions/fix-001.md": "uncommitted record\n" });
|
|
214
|
+
|
|
215
|
+
const before = replicationState(root, readReplicatePolicy(root)!);
|
|
216
|
+
expect(before.replicated).toBe(false);
|
|
217
|
+
expect(before.refs.find((r) => r.ref === "refs/heads/chant/work/W-001")).toMatchObject({ replicated: false, ahead: 1 });
|
|
218
|
+
|
|
219
|
+
const doc = ok(wipSave({ cwd: root, label: "turn:1" }), "save");
|
|
220
|
+
expect(doc.replication?.rejected).toEqual([]);
|
|
221
|
+
expect(doc.replication?.pushed.map((p) => p.ref).sort()).toEqual([
|
|
222
|
+
"refs/chant/kept/W-001/tok-1",
|
|
223
|
+
"refs/chant/wip/chant/work/W-001",
|
|
224
|
+
"refs/heads/chant/lifecycle",
|
|
225
|
+
"refs/heads/chant/work/W-001",
|
|
226
|
+
]);
|
|
227
|
+
expect(git(remote, "rev-parse", "refs/chant/wip/chant/work/W-001")).toBe(doc.snapshot.commit);
|
|
228
|
+
expect(git(root, "rev-parse", replicaRef("origin", "refs/chant/wip/chant/work/W-001"))).toBe(doc.snapshot.commit);
|
|
229
|
+
|
|
230
|
+
const status = await workspaceStatus({ cwd: root, env: "dev" });
|
|
231
|
+
contract(statusSchema).expectValid(status);
|
|
232
|
+
if ("error" in status) throw new Error(status.error.message);
|
|
233
|
+
expect(status.replication).toMatchObject({ remoteConfigured: true, replicated: true });
|
|
234
|
+
expect(status.members[0].box?.replicate).toEqual({ remote: "origin", refs: ["work", "kept", "wip", "ledger"], on: ["save", "release"], every: null });
|
|
235
|
+
|
|
236
|
+
// A push that would rewrite the remote is refused, never forced.
|
|
237
|
+
git(root, "update-ref", "refs/chant/kept/W-001/tok-1", "HEAD~1");
|
|
238
|
+
const push = ok(wipPush({ cwd: root }), "push");
|
|
239
|
+
expect(push.replication.rejected.map((r) => r.ref)).toEqual(["refs/chant/kept/W-001/tok-1"]);
|
|
240
|
+
expect(git(remote, "rev-parse", "refs/chant/kept/W-001/tok-1")).toBe(git(root, "rev-parse", "HEAD"));
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test("a policy that leaves save out doesn't push on save; push and fetch need a policy and a remote", () => {
|
|
244
|
+
const { root } = boxWithRemote({ on: ["release"] });
|
|
245
|
+
writeFiles(root, { "a.txt": "a\n" });
|
|
246
|
+
expect(ok(wipSave({ cwd: root }), "save").replication).toBeNull();
|
|
247
|
+
const none = box();
|
|
248
|
+
expect(refused(wipPush({ cwd: none }))).toBe("wip-policy-none");
|
|
249
|
+
expect(refused(wipFetch({ cwd: none }))).toBe("wip-policy-none");
|
|
250
|
+
const noRemote = box({}, { remote: "mirror" });
|
|
251
|
+
expect(refused(wipPush({ cwd: noRemote }))).toBe("wip-remote-unknown");
|
|
252
|
+
writeFiles(noRemote, { "a.txt": "a\n" });
|
|
253
|
+
const saved = ok(wipSave({ cwd: noRemote }), "save");
|
|
254
|
+
expect(saved.replication?.pushed).toEqual([]);
|
|
255
|
+
expect(saved.replication?.rejected[0].reason).toMatch(/no git remote named mirror/);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("a box lost mid-work: a replacement fetches and restores every uncommitted record and kept attempt", () => {
|
|
259
|
+
const { remote, root } = boxWithRemote();
|
|
260
|
+
writeFiles(root, { "app/half.mjs": "half\n" });
|
|
261
|
+
commitAll(root, "half the work, committed");
|
|
262
|
+
git(root, "update-ref", "refs/chant/kept/W-001/tok-1", "HEAD");
|
|
263
|
+
writeFiles(root, { "decisions/fix-001.md": "a decision, proposed and not committed\n", "app/server.mjs": "export const port = 7070;\n" });
|
|
264
|
+
rmSync(join(root, ".gitignore"));
|
|
265
|
+
const saved = ok(wipSave({ cwd: root, label: "turn:9" }), "save");
|
|
266
|
+
expect(saved.replication?.rejected).toEqual([]);
|
|
267
|
+
rmSync(root, { recursive: true, force: true });
|
|
268
|
+
|
|
269
|
+
// A new box: a clone of the remote, on its default branch, whose declaration states the policy.
|
|
270
|
+
const fresh = scratchDir("chant-wip-replacement-");
|
|
271
|
+
git(fresh, "clone", "-q", remote, ".");
|
|
272
|
+
const fetched = ok(wipFetch({ cwd: fresh }), "fetch");
|
|
273
|
+
expect(fetched.failed).toBeNull();
|
|
274
|
+
expect(fetched.refs.map((r) => [r.ref, r.result])).toEqual([
|
|
275
|
+
["refs/chant/kept/W-001/tok-1", "created"],
|
|
276
|
+
["refs/chant/wip/chant/work/W-001", "created"],
|
|
277
|
+
["refs/heads/chant/work/W-001", "created"],
|
|
278
|
+
]);
|
|
279
|
+
git(fresh, "checkout", "-q", "chant/work/W-001");
|
|
280
|
+
const restored = ok(wipRestore({ cwd: fresh }), "restore");
|
|
281
|
+
expect(restored.snapshot.commit).toBe(saved.snapshot.commit);
|
|
282
|
+
expect(restored.headMoved).toBe(false);
|
|
283
|
+
expect(readFileSync(join(fresh, "decisions/fix-001.md"), "utf-8")).toBe("a decision, proposed and not committed\n");
|
|
284
|
+
expect(readFileSync(join(fresh, "app/server.mjs"), "utf-8")).toBe("export const port = 7070;\n");
|
|
285
|
+
expect(existsSync(join(fresh, ".gitignore"))).toBe(false);
|
|
286
|
+
expect(git(fresh, "rev-parse", "refs/chant/kept/W-001/tok-1")).toBe(git(fresh, "rev-parse", "HEAD"));
|
|
287
|
+
// Fetching again moves nothing: the restore's own checkpoint left the local snapshot ref ahead of the remote's.
|
|
288
|
+
expect(ok(wipFetch({ cwd: fresh }), "fetch").refs.map((r) => [r.ref, r.result])).toEqual([
|
|
289
|
+
["refs/chant/kept/W-001/tok-1", "up-to-date"],
|
|
290
|
+
["refs/chant/wip/chant/work/W-001", "ahead"],
|
|
291
|
+
["refs/heads/chant/work/W-001", "up-to-date"],
|
|
292
|
+
]);
|
|
293
|
+
});
|
|
294
|
+
});
|